Sfoglia il codice sorgente

remove flow. add typescript

KaFai Choi 6 anni fa
parent
commit
5ebdeb579e
13 ha cambiato i file con 319 aggiunte e 725 eliminazioni
  1. 5
    1
      .gitignore
  2. 0
    3
      index.js
  3. 0
    458
      js/WebViewTypes.js
  4. 9
    9
      package.json
  5. 69
    81
      src/WebView.android.tsx
  6. 110
    116
      src/WebView.ios.tsx
  7. 2
    2
      src/WebViewShared.ts
  8. 8
    0
      src/index.ts
  9. 69
    50
      src/types/WebViewTypes.ts
  10. 3
    0
      src/utils.ts
  11. 28
    0
      tsconfig.base.json
  12. 5
    0
      tsconfig.json
  13. 11
    5
      yarn.lock

+ 5
- 1
.gitignore Vedi File

42
 #
42
 #
43
 bundles/
43
 bundles/
44
 
44
 
45
+# Typescript compile
46
+lib/
47
+
45
 # VS Code
48
 # VS Code
46
 .vscode/*
49
 .vscode/*
47
 !.vscode/settings.json
50
 !.vscode/settings.json
51
 
54
 
52
 android/gradle
55
 android/gradle
53
 android/gradlew
56
 android/gradlew
54
-android/gradlew.bat
57
+android/gradlew.bat
58
+

+ 0
- 3
index.js Vedi File

1
-import WebView from './js/WebView';
2
-
3
-export { WebView };

+ 0
- 458
js/WebViewTypes.js Vedi File

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

+ 9
- 9
package.json Vedi File

1
 {
1
 {
2
   "name": "react-native-webview",
2
   "name": "react-native-webview",
3
   "description": "React Native WebView component for iOS, Android, and Windows 10 (coming soon)",
3
   "description": "React Native WebView component for iOS, Android, and Windows 10 (coming soon)",
4
-  "main": "index.js",
5
-  "typings": "typings/index.d.ts",
4
+  "main": "lib/index.js",
5
+  "types": "lib/index.d.ts",
6
   "author": "Jamon Holmgren <jamon@infinite.red>",
6
   "author": "Jamon Holmgren <jamon@infinite.red>",
7
   "contributors": [
7
   "contributors": [
8
     "Thibault Malbranche <malbranche.thibault@gmail.com>"
8
     "Thibault Malbranche <malbranche.thibault@gmail.com>"
11
   "version": "2.12.1",
11
   "version": "2.12.1",
12
   "homepage": "https://github.com/react-native-community/react-native-webview#readme",
12
   "homepage": "https://github.com/react-native-community/react-native-webview#readme",
13
   "scripts": {
13
   "scripts": {
14
-    "test:ios:flow": "flow check",
15
-    "test:android:flow": "flow check --flowconfig-name .flowconfig.android",
14
+    "compile": "tsc",
16
     "ci:publish": "yarn semantic-release",
15
     "ci:publish": "yarn semantic-release",
17
-    "ci:test": "yarn ci:test:flow",
18
-    "ci:test:flow": "yarn test:ios:flow && yarn test:android:flow",
16
+    "ci:test": "yarn ci:test:compile",
17
+    "ci:test:compile": "yarn compile",
19
     "semantic-release": "semantic-release"
18
     "semantic-release": "semantic-release"
20
   },
19
   },
21
   "peerDependencies": {
20
   "peerDependencies": {
24
   },
23
   },
25
   "dependencies": {
24
   "dependencies": {
26
     "escape-string-regexp": "^1.0.5",
25
     "escape-string-regexp": "^1.0.5",
27
-    "fbjs": "^0.8.17"
26
+    "invariant": "^2.2.4"
28
   },
27
   },
29
   "devDependencies": {
28
   "devDependencies": {
30
     "@semantic-release/git": "7.0.5",
29
     "@semantic-release/git": "7.0.5",
30
+    "@types/invariant": "^2.2.29",
31
     "@types/react": "^16.4.18",
31
     "@types/react": "^16.4.18",
32
     "@types/react-native": "^0.57.6",
32
     "@types/react-native": "^0.57.6",
33
-    "flow-bin": "^0.80.0",
34
     "react-native": "^0.57",
33
     "react-native": "^0.57",
35
-    "semantic-release": "15.10.3"
34
+    "semantic-release": "15.10.3",
35
+    "typescript": "^3.1.6"
36
   },
36
   },
37
   "repository": {
37
   "repository": {
38
     "type": "git",
38
     "type": "git",

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

1
-/**
2
- * Copyright (c) 2015-present, Facebook, Inc.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @flow
9
- */
10
-
11
-'use strict';
1
+import React from "react";
12
 
2
 
13
-import React from 'react';
14
-
15
-import ReactNative from 'react-native';
3
+import ReactNative from "react-native";
16
 import {
4
 import {
17
   ActivityIndicator,
5
   ActivityIndicator,
18
   StyleSheet,
6
   StyleSheet,
19
   UIManager,
7
   UIManager,
20
   View,
8
   View,
21
-  Image,
22
   requireNativeComponent,
9
   requireNativeComponent,
23
-  NativeModules
24
-} from 'react-native';
10
+  NativeModules,
11
+  Image,
12
+  NativeSyntheticEvent
13
+} from "react-native";
25
 
14
 
26
-import invariant from 'fbjs/lib/invariant';
27
-import keyMirror from 'fbjs/lib/keyMirror';
15
+import invariant from "invariant";
28
 
16
 
29
-import WebViewShared from './WebViewShared';
30
-import type {
31
-  WebViewEvent,
17
+import WebViewShared from "./WebViewShared";
18
+import {
19
+  WebViewSourceUri,
32
   WebViewError,
20
   WebViewError,
33
   WebViewErrorEvent,
21
   WebViewErrorEvent,
34
   WebViewMessageEvent,
22
   WebViewMessageEvent,
35
-  WebViewNavigation,
36
   WebViewNavigationEvent,
23
   WebViewNavigationEvent,
37
   WebViewSharedProps,
24
   WebViewSharedProps,
38
   WebViewSource,
25
   WebViewSource,
39
-  WebViewProgressEvent,
40
-} from './WebViewTypes';
41
-
42
-const resolveAssetSource = Image.resolveAssetSource;
43
-
44
-const WebViewState = keyMirror({
45
-  IDLE: null,
46
-  LOADING: null,
47
-  ERROR: null,
48
-});
26
+  WebViewProgressEvent
27
+} from "./types/WebViewTypes";
28
+import { isWebViewUriSource } from "./utils";
29
+
30
+enum WebViewState {
31
+  IDLE = "IDLE",
32
+  LOADING = "LOADING",
33
+  ERROR = "ERROR"
34
+}
49
 
35
 
50
 const defaultRenderLoading = () => (
36
 const defaultRenderLoading = () => (
51
   <View style={styles.loadingView}>
37
   <View style={styles.loadingView}>
53
   </View>
39
   </View>
54
 );
40
 );
55
 
41
 
56
-type State = {|
57
-  viewState: WebViewState,
58
-  lastErrorEvent: ?WebViewError,
59
-|};
42
+type State = {
43
+  viewState: WebViewState;
44
+  lastErrorEvent: WebViewError;
45
+};
60
 
46
 
61
 /**
47
 /**
62
  * Renders a native WebView.
48
  * Renders a native WebView.
63
  */
49
  */
64
-class WebView extends React.Component<WebViewSharedProps, State> {
50
+export default class WebView extends React.Component<WebViewSharedProps, State> {
65
   static defaultProps = {
51
   static defaultProps = {
66
-    overScrollMode: 'always',
52
+    overScrollMode: "always",
67
     javaScriptEnabled: true,
53
     javaScriptEnabled: true,
68
     thirdPartyCookiesEnabled: true,
54
     thirdPartyCookiesEnabled: true,
69
     scalesPageToFit: true,
55
     scalesPageToFit: true,
70
     allowFileAccess: false,
56
     allowFileAccess: false,
71
     saveFormDataDisabled: false,
57
     saveFormDataDisabled: false,
72
-    originWhitelist: WebViewShared.defaultOriginWhitelist,
58
+    originWhitelist: WebViewShared.defaultOriginWhitelist
73
   };
59
   };
74
 
60
 
75
   static isFileUploadSupported = async () => {
61
   static isFileUploadSupported = async () => {
76
     // native implementation should return "true" only for Android 5+
62
     // native implementation should return "true" only for Android 5+
77
     return NativeModules.RNCWebView.isFileUploadSupported();
63
     return NativeModules.RNCWebView.isFileUploadSupported();
78
-  }
64
+  };
79
 
65
 
80
-  state = {
81
-    viewState: this.props.startInLoadingState ? WebViewState.LOADING : WebViewState.IDLE,
82
-    lastErrorEvent: null,
66
+  state: State = {
67
+    viewState: this.props.startInLoadingState
68
+      ? WebViewState.LOADING
69
+      : WebViewState.IDLE,
70
+    lastErrorEvent: null
83
   };
71
   };
84
 
72
 
85
-  webViewRef = React.createRef();
73
+  webViewRef = React.createRef<React.ComponentClass>();
86
 
74
 
87
   render() {
75
   render() {
88
     let otherView = null;
76
     let otherView = null;
91
       otherView = (this.props.renderLoading || defaultRenderLoading)();
79
       otherView = (this.props.renderLoading || defaultRenderLoading)();
92
     } else if (this.state.viewState === WebViewState.ERROR) {
80
     } else if (this.state.viewState === WebViewState.ERROR) {
93
       const errorEvent = this.state.lastErrorEvent;
81
       const errorEvent = this.state.lastErrorEvent;
94
-      invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
82
+      invariant(errorEvent != null, "lastErrorEvent expected to be non-null");
95
       otherView =
83
       otherView =
96
         this.props.renderError &&
84
         this.props.renderError &&
97
         this.props.renderError(
85
         this.props.renderError(
98
           errorEvent.domain,
86
           errorEvent.domain,
99
           errorEvent.code,
87
           errorEvent.code,
100
-          errorEvent.description,
88
+          errorEvent.description
101
         );
89
         );
102
     } else if (this.state.viewState !== WebViewState.IDLE) {
90
     } else if (this.state.viewState !== WebViewState.IDLE) {
103
       console.error(
91
       console.error(
104
-        'RNCWebView invalid state encountered: ' + this.state.viewState,
92
+        "RNCWebView invalid state encountered: " + this.state.viewState
105
       );
93
       );
106
     }
94
     }
107
 
95
 
121
       source = { uri: this.props.url };
109
       source = { uri: this.props.url };
122
     }
110
     }
123
 
111
 
124
-    if (source.method === 'POST' && source.headers) {
125
-      console.warn(
126
-        'WebView: `source.headers` is not supported when using POST.',
127
-      );
128
-    } else if (source.method === 'GET' && source.body) {
129
-      console.warn('WebView: `source.body` is not supported when using GET.');
112
+    if (isWebViewUriSource(source)) {
113
+      if (source.method === "POST" && source.headers) {
114
+        console.warn(
115
+          "WebView: `source.headers` is not supported when using POST."
116
+        );
117
+      } else if (source.method === "GET" && source.body) {
118
+        console.warn("WebView: `source.body` is not supported when using GET.");
119
+      }
130
     }
120
     }
131
 
121
 
132
     const nativeConfig = this.props.nativeConfig || {};
122
     const nativeConfig = this.props.nativeConfig || {};
133
 
123
 
134
     const originWhitelist = (this.props.originWhitelist || []).map(
124
     const originWhitelist = (this.props.originWhitelist || []).map(
135
-      WebViewShared.originWhitelistToRegex,
125
+      WebViewShared.originWhitelistToRegex
136
     );
126
     );
137
 
127
 
138
     let NativeWebView = nativeConfig.component || RNCWebView;
128
     let NativeWebView = nativeConfig.component || RNCWebView;
142
         ref={this.webViewRef}
132
         ref={this.webViewRef}
143
         key="webViewKey"
133
         key="webViewKey"
144
         style={webViewStyles}
134
         style={webViewStyles}
145
-        source={resolveAssetSource(source)}
135
+        source={Image.resolveAssetSource(source as WebViewSourceUri)} // typing issue of not compatible of WebViewSourceHtml in react native.
146
         scalesPageToFit={this.props.scalesPageToFit}
136
         scalesPageToFit={this.props.scalesPageToFit}
147
         allowFileAccess={this.props.allowFileAccess}
137
         allowFileAccess={this.props.allowFileAccess}
148
         injectedJavaScript={this.props.injectedJavaScript}
138
         injectedJavaScript={this.props.injectedJavaScript}
150
         javaScriptEnabled={this.props.javaScriptEnabled}
140
         javaScriptEnabled={this.props.javaScriptEnabled}
151
         thirdPartyCookiesEnabled={this.props.thirdPartyCookiesEnabled}
141
         thirdPartyCookiesEnabled={this.props.thirdPartyCookiesEnabled}
152
         domStorageEnabled={this.props.domStorageEnabled}
142
         domStorageEnabled={this.props.domStorageEnabled}
153
-        messagingEnabled={typeof this.props.onMessage === 'function'}
143
+        messagingEnabled={typeof this.props.onMessage === "function"}
154
         onMessage={this.onMessage}
144
         onMessage={this.onMessage}
155
         overScrollMode={this.props.overScrollMode}
145
         overScrollMode={this.props.overScrollMode}
156
         contentInset={this.props.contentInset}
146
         contentInset={this.props.contentInset}
190
     UIManager.dispatchViewManagerCommand(
180
     UIManager.dispatchViewManagerCommand(
191
       this.getWebViewHandle(),
181
       this.getWebViewHandle(),
192
       UIManager.RNCWebView.Commands.goForward,
182
       UIManager.RNCWebView.Commands.goForward,
193
-      null,
183
+      null
194
     );
184
     );
195
   };
185
   };
196
 
186
 
198
     UIManager.dispatchViewManagerCommand(
188
     UIManager.dispatchViewManagerCommand(
199
       this.getWebViewHandle(),
189
       this.getWebViewHandle(),
200
       UIManager.RNCWebView.Commands.goBack,
190
       UIManager.RNCWebView.Commands.goBack,
201
-      null,
191
+      null
202
     );
192
     );
203
   };
193
   };
204
 
194
 
205
   reload = () => {
195
   reload = () => {
206
     this.setState({
196
     this.setState({
207
-      viewState: WebViewState.LOADING,
197
+      viewState: WebViewState.LOADING
208
     });
198
     });
209
     UIManager.dispatchViewManagerCommand(
199
     UIManager.dispatchViewManagerCommand(
210
       this.getWebViewHandle(),
200
       this.getWebViewHandle(),
211
       UIManager.RNCWebView.Commands.reload,
201
       UIManager.RNCWebView.Commands.reload,
212
-      null,
202
+      null
213
     );
203
     );
214
   };
204
   };
215
 
205
 
217
     UIManager.dispatchViewManagerCommand(
207
     UIManager.dispatchViewManagerCommand(
218
       this.getWebViewHandle(),
208
       this.getWebViewHandle(),
219
       UIManager.RNCWebView.Commands.stopLoading,
209
       UIManager.RNCWebView.Commands.stopLoading,
220
-      null,
210
+      null
221
     );
211
     );
222
   };
212
   };
223
 
213
 
225
     UIManager.dispatchViewManagerCommand(
215
     UIManager.dispatchViewManagerCommand(
226
       this.getWebViewHandle(),
216
       this.getWebViewHandle(),
227
       UIManager.RNCWebView.Commands.postMessage,
217
       UIManager.RNCWebView.Commands.postMessage,
228
-      [String(data)],
218
+      [String(data)]
229
     );
219
     );
230
   };
220
   };
231
 
221
 
239
     UIManager.dispatchViewManagerCommand(
229
     UIManager.dispatchViewManagerCommand(
240
       this.getWebViewHandle(),
230
       this.getWebViewHandle(),
241
       UIManager.RNCWebView.Commands.injectJavaScript,
231
       UIManager.RNCWebView.Commands.injectJavaScript,
242
-      [data],
232
+      [data]
243
     );
233
     );
244
   };
234
   };
245
 
235
 
268
     const { onError, onLoadEnd } = this.props;
258
     const { onError, onLoadEnd } = this.props;
269
     onError && onError(event);
259
     onError && onError(event);
270
     onLoadEnd && onLoadEnd(event);
260
     onLoadEnd && onLoadEnd(event);
271
-    console.warn('Encountered an error loading page', event.nativeEvent);
261
+    console.warn("Encountered an error loading page", event.nativeEvent);
272
 
262
 
273
     this.setState({
263
     this.setState({
274
       lastErrorEvent: event.nativeEvent,
264
       lastErrorEvent: event.nativeEvent,
275
-      viewState: WebViewState.ERROR,
265
+      viewState: WebViewState.ERROR
276
     });
266
     });
277
   };
267
   };
278
 
268
 
281
     onLoad && onLoad(event);
271
     onLoad && onLoad(event);
282
     onLoadEnd && onLoadEnd(event);
272
     onLoadEnd && onLoadEnd(event);
283
     this.setState({
273
     this.setState({
284
-      viewState: WebViewState.IDLE,
274
+      viewState: WebViewState.IDLE
285
     });
275
     });
286
     this.updateNavigationState(event);
276
     this.updateNavigationState(event);
287
   };
277
   };
290
     const { onMessage } = this.props;
280
     const { onMessage } = this.props;
291
     onMessage && onMessage(event);
281
     onMessage && onMessage(event);
292
   };
282
   };
293
-  
294
-  onLoadingProgress = (event: WebViewProgressEvent) => {
295
-    const { onLoadProgress} = this.props;
283
+
284
+  onLoadingProgress = (event: NativeSyntheticEvent<WebViewProgressEvent>) => {
285
+    const { onLoadProgress } = this.props;
296
     onLoadProgress && onLoadProgress(event);
286
     onLoadProgress && onLoadProgress(event);
297
-  }
287
+  };
298
 }
288
 }
299
 
289
 
300
-const RNCWebView = requireNativeComponent('RNCWebView');
290
+const RNCWebView = requireNativeComponent("RNCWebView");
301
 
291
 
302
 const styles = StyleSheet.create({
292
 const styles = StyleSheet.create({
303
   container: {
293
   container: {
304
-    flex: 1,
294
+    flex: 1
305
   },
295
   },
306
   hidden: {
296
   hidden: {
307
     height: 0,
297
     height: 0,
308
-    flex: 0, // disable 'flex:1' when hiding a View
298
+    flex: 0 // disable 'flex:1' when hiding a View
309
   },
299
   },
310
   loadingView: {
300
   loadingView: {
311
     flex: 1,
301
     flex: 1,
312
-    justifyContent: 'center',
313
-    alignItems: 'center',
302
+    justifyContent: "center",
303
+    alignItems: "center"
314
   },
304
   },
315
   loadingProgressBar: {
305
   loadingProgressBar: {
316
-    height: 20,
317
-  },
318
-});
319
-
320
-module.exports = WebView;
306
+    height: 20
307
+  }
308
+});

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

1
-/**
2
- * Copyright (c) 2015-present, Facebook, Inc.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @flow
9
- */
10
-
11
-import React from 'react';
1
+import React from "react";
12
 import {
2
 import {
13
   ActivityIndicator,
3
   ActivityIndicator,
14
   Linking,
4
   Linking,
20
   NativeModules,
10
   NativeModules,
21
   Image,
11
   Image,
22
   findNodeHandle,
12
   findNodeHandle,
23
-} from 'react-native';
13
+  NativeSyntheticEvent
14
+} from "react-native";
24
 
15
 
25
-import invariant from 'fbjs/lib/invariant';
26
-import keyMirror from 'fbjs/lib/keyMirror';
16
+import invariant from "invariant";
27
 
17
 
28
-import WebViewShared from './WebViewShared';
29
-import type {
30
-  WebViewEvent,
18
+import WebViewShared from "./WebViewShared";
19
+import {
20
+  WebViewSourceUri,
31
   WebViewError,
21
   WebViewError,
22
+  WebViewIOSLoadRequestEvent,
32
   WebViewErrorEvent,
23
   WebViewErrorEvent,
33
   WebViewMessageEvent,
24
   WebViewMessageEvent,
34
   WebViewNavigationEvent,
25
   WebViewNavigationEvent,
35
   WebViewSharedProps,
26
   WebViewSharedProps,
36
   WebViewSource,
27
   WebViewSource,
37
-  WebViewProgressEvent,
38
-} from './WebViewTypes';
28
+  WebViewProgressEvent
29
+} from "./types/WebViewTypes";
39
 
30
 
40
-const resolveAssetSource = Image.resolveAssetSource;
31
+type DecelerationRate = number | "normal" | "fast";
41
 
32
 
42
 // Imported from https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/processDecelerationRate.js
33
 // Imported from https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/processDecelerationRate.js
43
-function processDecelerationRate(decelerationRate) {
44
-  if (decelerationRate === 'normal') {
34
+function processDecelerationRate(decelerationRate: DecelerationRate) {
35
+  if (decelerationRate === "normal") {
45
     decelerationRate = 0.998;
36
     decelerationRate = 0.998;
46
-  } else if (decelerationRate === 'fast') {
37
+  } else if (decelerationRate === "fast") {
47
     decelerationRate = 0.99;
38
     decelerationRate = 0.99;
48
   }
39
   }
49
   return decelerationRate;
40
   return decelerationRate;
52
 const RNCUIWebViewManager = NativeModules.RNCUIWebViewManager;
43
 const RNCUIWebViewManager = NativeModules.RNCUIWebViewManager;
53
 const RNCWKWebViewManager = NativeModules.RNCWKWebViewManager;
44
 const RNCWKWebViewManager = NativeModules.RNCWKWebViewManager;
54
 
45
 
55
-const BGWASH = 'rgba(255,255,255,0.8)';
46
+const BGWASH = "rgba(255,255,255,0.8)";
56
 
47
 
57
-const WebViewState = keyMirror({
58
-  IDLE: null,
59
-  LOADING: null,
60
-  ERROR: null,
61
-});
48
+enum WebViewState {
49
+  IDLE = "IDLE",
50
+  LOADING = "LOADING",
51
+  ERROR = "ERROR"
52
+}
62
 
53
 
63
-const NavigationType = keyMirror({
64
-  click: true,
65
-  formsubmit: true,
66
-  backforward: true,
67
-  reload: true,
68
-  formresubmit: true,
69
-  other: true,
70
-});
54
+enum NavigationType {
55
+  click = "click",
56
+  formsubmit = "formsubmit",
57
+  backforward = "backforward",
58
+  reload = "reload",
59
+  formresubmit = "formresubmit",
60
+  other = "other"
61
+}
62
+
63
+const JSNavigationScheme = "react-js-navigation";
71
 
64
 
72
-const JSNavigationScheme = 'react-js-navigation';
73
-
74
-type State = {|
75
-  viewState: WebViewState,
76
-  lastErrorEvent: ?WebViewError,
77
-|};
78
-
79
-const DataDetectorTypes = [
80
-  'phoneNumber',
81
-  'link',
82
-  'address',
83
-  'calendarEvent',
84
-  'trackingNumber',
85
-  'flightNumber',
86
-  'lookupSuggestion',
87
-  'none',
88
-  'all',
89
-];
65
+type State = {
66
+  viewState: WebViewState;
67
+  lastErrorEvent: WebViewError;
68
+};
90
 
69
 
91
 const defaultRenderLoading = () => (
70
 const defaultRenderLoading = () => (
92
   <View style={styles.loadingView}>
71
   <View style={styles.loadingView}>
93
     <ActivityIndicator />
72
     <ActivityIndicator />
94
   </View>
73
   </View>
95
 );
74
 );
96
-const defaultRenderError = (errorDomain, errorCode, errorDesc) => (
75
+const defaultRenderError = (
76
+  errorDomain: string,
77
+  errorCode: number,
78
+  errorDesc: string
79
+) => (
97
   <View style={styles.errorContainer}>
80
   <View style={styles.errorContainer}>
98
     <Text style={styles.errorTextTitle}>Error loading page</Text>
81
     <Text style={styles.errorTextTitle}>Error loading page</Text>
99
-    <Text style={styles.errorText}>{'Domain: ' + errorDomain}</Text>
100
-    <Text style={styles.errorText}>{'Error Code: ' + errorCode}</Text>
101
-    <Text style={styles.errorText}>{'Description: ' + errorDesc}</Text>
82
+    <Text style={styles.errorText}>{"Domain: " + errorDomain}</Text>
83
+    <Text style={styles.errorText}>{"Error Code: " + errorCode}</Text>
84
+    <Text style={styles.errorText}>{"Description: " + errorDesc}</Text>
102
   </View>
85
   </View>
103
 );
86
 );
104
 
87
 
124
  * You can use this component to navigate back and forth in the web view's
107
  * You can use this component to navigate back and forth in the web view's
125
  * history and configure various properties for the web content.
108
  * history and configure various properties for the web content.
126
  */
109
  */
127
-class WebView extends React.Component<WebViewSharedProps, State> {
110
+export default class WebView extends React.Component<
111
+  WebViewSharedProps,
112
+  State
113
+> {
128
   static JSNavigationScheme = JSNavigationScheme;
114
   static JSNavigationScheme = JSNavigationScheme;
129
   static NavigationType = NavigationType;
115
   static NavigationType = NavigationType;
130
 
116
 
131
   static defaultProps = {
117
   static defaultProps = {
132
     useWebKit: true,
118
     useWebKit: true,
133
-    originWhitelist: WebViewShared.defaultOriginWhitelist,
119
+    originWhitelist: WebViewShared.defaultOriginWhitelist
134
   };
120
   };
135
 
121
 
136
   static isFileUploadSupported = async () => {
122
   static isFileUploadSupported = async () => {
137
     // no native implementation for iOS, depends only on permissions
123
     // no native implementation for iOS, depends only on permissions
138
     return true;
124
     return true;
139
-  }
125
+  };
140
 
126
 
141
-  state = {
127
+  state: State = {
142
     viewState: this.props.startInLoadingState
128
     viewState: this.props.startInLoadingState
143
       ? WebViewState.LOADING
129
       ? WebViewState.LOADING
144
       : WebViewState.IDLE,
130
       : WebViewState.IDLE,
145
-    lastErrorEvent: null,
131
+    lastErrorEvent: null
146
   };
132
   };
147
 
133
 
148
-  webViewRef = React.createRef();
134
+  webViewRef = React.createRef<React.ComponentClass>();
149
 
135
 
150
   UNSAFE_componentWillMount() {
136
   UNSAFE_componentWillMount() {
151
     if (
137
     if (
153
       this.props.scalesPageToFit !== undefined
139
       this.props.scalesPageToFit !== undefined
154
     ) {
140
     ) {
155
       console.warn(
141
       console.warn(
156
-        'The scalesPageToFit property is not supported when useWebKit = true',
142
+        "The scalesPageToFit property is not supported when useWebKit = true"
157
       );
143
       );
158
     }
144
     }
159
     if (
145
     if (
161
       this.props.allowsBackForwardNavigationGestures
147
       this.props.allowsBackForwardNavigationGestures
162
     ) {
148
     ) {
163
       console.warn(
149
       console.warn(
164
-        'The allowsBackForwardNavigationGestures property is not supported when useWebKit = false',
150
+        "The allowsBackForwardNavigationGestures property is not supported when useWebKit = false"
165
       );
151
       );
166
     }
152
     }
167
   }
153
   }
181
       otherView = (this.props.renderLoading || defaultRenderLoading)();
167
       otherView = (this.props.renderLoading || defaultRenderLoading)();
182
     } else if (this.state.viewState === WebViewState.ERROR) {
168
     } else if (this.state.viewState === WebViewState.ERROR) {
183
       const errorEvent = this.state.lastErrorEvent;
169
       const errorEvent = this.state.lastErrorEvent;
184
-      invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
170
+      invariant(errorEvent != null, "lastErrorEvent expected to be non-null");
185
       otherView = (this.props.renderError || defaultRenderError)(
171
       otherView = (this.props.renderError || defaultRenderError)(
186
         errorEvent.domain,
172
         errorEvent.domain,
187
         errorEvent.code,
173
         errorEvent.code,
188
-        errorEvent.description,
174
+        errorEvent.description
189
       );
175
       );
190
     } else if (this.state.viewState !== WebViewState.IDLE) {
176
     } else if (this.state.viewState !== WebViewState.IDLE) {
191
       console.error(
177
       console.error(
192
-        'RNCWebView invalid state encountered: ' + this.state.viewState,
178
+        "RNCWebView invalid state encountered: " + this.state.viewState
193
       );
179
       );
194
     }
180
     }
195
 
181
 
213
     }
199
     }
214
 
200
 
215
     const compiledWhitelist = [
201
     const compiledWhitelist = [
216
-      'about:blank',
217
-      ...(this.props.originWhitelist || []),
202
+      "about:blank",
203
+      ...(this.props.originWhitelist || [])
218
     ].map(WebViewShared.originWhitelistToRegex);
204
     ].map(WebViewShared.originWhitelistToRegex);
219
-    const onShouldStartLoadWithRequest = event => {
205
+    const onShouldStartLoadWithRequest = (
206
+      event: NativeSyntheticEvent<WebViewIOSLoadRequestEvent>
207
+    ) => {
220
       let shouldStart = true;
208
       let shouldStart = true;
221
       const { url } = event.nativeEvent;
209
       const { url } = event.nativeEvent;
222
       const origin = WebViewShared.extractOrigin(url);
210
       const origin = WebViewShared.extractOrigin(url);
223
       const passesWhitelist = compiledWhitelist.some(x =>
211
       const passesWhitelist = compiledWhitelist.some(x =>
224
-        new RegExp(x).test(origin),
212
+        new RegExp(x).test(origin)
225
       );
213
       );
226
       shouldStart = shouldStart && passesWhitelist;
214
       shouldStart = shouldStart && passesWhitelist;
227
       if (!passesWhitelist) {
215
       if (!passesWhitelist) {
232
           shouldStart &&
220
           shouldStart &&
233
           this.props.onShouldStartLoadWithRequest(event.nativeEvent);
221
           this.props.onShouldStartLoadWithRequest(event.nativeEvent);
234
       }
222
       }
235
-      invariant(viewManager != null, 'viewManager expected to be non-null');
223
+      invariant(viewManager != null, "viewManager expected to be non-null");
236
       viewManager.startLoadWithResult(
224
       viewManager.startLoadWithResult(
237
         !!shouldStart,
225
         !!shouldStart,
238
-        event.nativeEvent.lockIdentifier,
226
+        event.nativeEvent.lockIdentifier
239
       );
227
       );
240
     };
228
     };
241
 
229
 
242
     const decelerationRate = processDecelerationRate(
230
     const decelerationRate = processDecelerationRate(
243
-      this.props.decelerationRate,
231
+      this.props.decelerationRate
244
     );
232
     );
245
 
233
 
246
     let source: WebViewSource = this.props.source || {};
234
     let source: WebViewSource = this.props.source || {};
250
       source = { uri: this.props.url };
238
       source = { uri: this.props.url };
251
     }
239
     }
252
 
240
 
253
-    const messagingEnabled = typeof this.props.onMessage === 'function';
241
+    const messagingEnabled = typeof this.props.onMessage === "function";
254
 
242
 
255
     let NativeWebView = nativeConfig.component;
243
     let NativeWebView = nativeConfig.component;
256
 
244
 
265
         ref={this.webViewRef}
253
         ref={this.webViewRef}
266
         key="webViewKey"
254
         key="webViewKey"
267
         style={webViewStyles}
255
         style={webViewStyles}
268
-        source={resolveAssetSource(source)}
256
+        source={Image.resolveAssetSource(source as WebViewSourceUri)} // typing issue of not compatible of WebViewSourceHtml in react native.
269
         injectedJavaScript={this.props.injectedJavaScript}
257
         injectedJavaScript={this.props.injectedJavaScript}
270
         bounces={this.props.bounces}
258
         bounces={this.props.bounces}
271
         scrollEnabled={this.props.scrollEnabled}
259
         scrollEnabled={this.props.scrollEnabled}
276
           this.props.automaticallyAdjustContentInsets
264
           this.props.automaticallyAdjustContentInsets
277
         }
265
         }
278
         hideKeyboardAccessoryView={this.props.hideKeyboardAccessoryView}
266
         hideKeyboardAccessoryView={this.props.hideKeyboardAccessoryView}
279
-        allowsBackForwardNavigationGestures={this.props.allowsBackForwardNavigationGestures}
267
+        allowsBackForwardNavigationGestures={
268
+          this.props.allowsBackForwardNavigationGestures
269
+        }
280
         userAgent={this.props.userAgent}
270
         userAgent={this.props.userAgent}
281
         onLoadingStart={this._onLoadingStart}
271
         onLoadingStart={this._onLoadingStart}
282
         onLoadingFinish={this._onLoadingFinish}
272
         onLoadingFinish={this._onLoadingFinish}
318
     UIManager.dispatchViewManagerCommand(
308
     UIManager.dispatchViewManagerCommand(
319
       this.getWebViewHandle(),
309
       this.getWebViewHandle(),
320
       this._getCommands().goForward,
310
       this._getCommands().goForward,
321
-      null,
311
+      null
322
     );
312
     );
323
   };
313
   };
324
 
314
 
329
     UIManager.dispatchViewManagerCommand(
319
     UIManager.dispatchViewManagerCommand(
330
       this.getWebViewHandle(),
320
       this.getWebViewHandle(),
331
       this._getCommands().goBack,
321
       this._getCommands().goBack,
332
-      null,
322
+      null
333
     );
323
     );
334
   };
324
   };
335
 
325
 
341
     UIManager.dispatchViewManagerCommand(
331
     UIManager.dispatchViewManagerCommand(
342
       this.getWebViewHandle(),
332
       this.getWebViewHandle(),
343
       this._getCommands().reload,
333
       this._getCommands().reload,
344
-      null,
334
+      null
345
     );
335
     );
346
   };
336
   };
347
 
337
 
352
     UIManager.dispatchViewManagerCommand(
342
     UIManager.dispatchViewManagerCommand(
353
       this.getWebViewHandle(),
343
       this.getWebViewHandle(),
354
       this._getCommands().stopLoading,
344
       this._getCommands().stopLoading,
355
-      null,
345
+      null
356
     );
346
     );
357
   };
347
   };
358
 
348
 
370
     UIManager.dispatchViewManagerCommand(
360
     UIManager.dispatchViewManagerCommand(
371
       this.getWebViewHandle(),
361
       this.getWebViewHandle(),
372
       this._getCommands().postMessage,
362
       this._getCommands().postMessage,
373
-      [String(data)],
363
+      [String(data)]
374
     );
364
     );
375
   };
365
   };
376
 
366
 
384
     UIManager.dispatchViewManagerCommand(
374
     UIManager.dispatchViewManagerCommand(
385
       this.getWebViewHandle(),
375
       this.getWebViewHandle(),
386
       this._getCommands().injectJavaScript,
376
       this._getCommands().injectJavaScript,
387
-      [data],
377
+      [data]
388
     );
378
     );
389
   };
379
   };
390
 
380
 
416
     const { onError, onLoadEnd } = this.props;
406
     const { onError, onLoadEnd } = this.props;
417
     onError && onError(event);
407
     onError && onError(event);
418
     onLoadEnd && onLoadEnd(event);
408
     onLoadEnd && onLoadEnd(event);
419
-    console.warn('Encountered an error loading page', event.nativeEvent);
409
+    console.warn("Encountered an error loading page", event.nativeEvent);
420
 
410
 
421
     this.setState({
411
     this.setState({
422
       lastErrorEvent: event.nativeEvent,
412
       lastErrorEvent: event.nativeEvent,
423
-      viewState: WebViewState.ERROR,
413
+      viewState: WebViewState.ERROR
424
     });
414
     });
425
   };
415
   };
426
 
416
 
429
     onLoad && onLoad(event);
419
     onLoad && onLoad(event);
430
     onLoadEnd && onLoadEnd(event);
420
     onLoadEnd && onLoadEnd(event);
431
     this.setState({
421
     this.setState({
432
-      viewState: WebViewState.IDLE,
422
+      viewState: WebViewState.IDLE
433
     });
423
     });
434
     this._updateNavigationState(event);
424
     this._updateNavigationState(event);
435
   };
425
   };
439
     onMessage && onMessage(event);
429
     onMessage && onMessage(event);
440
   };
430
   };
441
 
431
 
442
-  _onLoadingProgress = (event: WebViewProgressEvent) => {
443
-    const {onLoadProgress} = this.props;
432
+  _onLoadingProgress = (event: NativeSyntheticEvent<WebViewProgressEvent>) => {
433
+    const { onLoadProgress } = this.props;
444
     onLoadProgress && onLoadProgress(event);
434
     onLoadProgress && onLoadProgress(event);
445
-  }
435
+  };
446
 
436
 
447
   componentDidUpdate(prevProps: WebViewSharedProps) {
437
   componentDidUpdate(prevProps: WebViewSharedProps) {
448
     if (!(prevProps.useWebKit && this.props.useWebKit)) {
438
     if (!(prevProps.useWebKit && this.props.useWebKit)) {
449
       return;
439
       return;
450
     }
440
     }
451
 
441
 
452
-    this._showRedboxOnPropChanges(prevProps, 'allowsInlineMediaPlayback');
453
-    this._showRedboxOnPropChanges(prevProps, 'mediaPlaybackRequiresUserAction');
454
-    this._showRedboxOnPropChanges(prevProps, 'dataDetectorTypes');
442
+    this._showRedboxOnPropChanges(prevProps, "allowsInlineMediaPlayback");
443
+    this._showRedboxOnPropChanges(prevProps, "mediaPlaybackRequiresUserAction");
444
+    this._showRedboxOnPropChanges(prevProps, "dataDetectorTypes");
455
 
445
 
456
     if (this.props.scalesPageToFit !== undefined) {
446
     if (this.props.scalesPageToFit !== undefined) {
457
       console.warn(
447
       console.warn(
458
-        'The scalesPageToFit property is not supported when useWebKit = true',
448
+        "The scalesPageToFit property is not supported when useWebKit = true"
459
       );
449
       );
460
     }
450
     }
461
   }
451
   }
462
 
452
 
463
-  _showRedboxOnPropChanges(prevProps, propName: string) {
453
+  _showRedboxOnPropChanges(
454
+    prevProps: WebViewSharedProps,
455
+    propName:
456
+      | "allowsInlineMediaPlayback"
457
+      | "mediaPlaybackRequiresUserAction"
458
+      | "dataDetectorTypes"
459
+  ) {
464
     if (this.props[propName] !== prevProps[propName]) {
460
     if (this.props[propName] !== prevProps[propName]) {
465
       console.error(
461
       console.error(
466
-        `Changes to property ${propName} do nothing after the initial render.`,
462
+        `Changes to property ${propName} do nothing after the initial render.`
467
       );
463
       );
468
     }
464
     }
469
   }
465
   }
470
 }
466
 }
471
 
467
 
472
-const RNCUIWebView = requireNativeComponent('RNCUIWebView');
473
-const RNCWKWebView = requireNativeComponent('RNCWKWebView');
468
+const RNCUIWebView = requireNativeComponent("RNCUIWebView");
469
+const RNCWKWebView = requireNativeComponent("RNCWKWebView");
474
 
470
 
475
 const styles = StyleSheet.create({
471
 const styles = StyleSheet.create({
476
   container: {
472
   container: {
477
-    flex: 1,
473
+    flex: 1
478
   },
474
   },
479
   errorContainer: {
475
   errorContainer: {
480
     flex: 1,
476
     flex: 1,
481
-    justifyContent: 'center',
482
-    alignItems: 'center',
483
-    backgroundColor: BGWASH,
477
+    justifyContent: "center",
478
+    alignItems: "center",
479
+    backgroundColor: BGWASH
484
   },
480
   },
485
   errorText: {
481
   errorText: {
486
     fontSize: 14,
482
     fontSize: 14,
487
-    textAlign: 'center',
488
-    marginBottom: 2,
483
+    textAlign: "center",
484
+    marginBottom: 2
489
   },
485
   },
490
   errorTextTitle: {
486
   errorTextTitle: {
491
     fontSize: 15,
487
     fontSize: 15,
492
-    fontWeight: '500',
493
-    marginBottom: 10,
488
+    fontWeight: "500",
489
+    marginBottom: 10
494
   },
490
   },
495
   hidden: {
491
   hidden: {
496
     height: 0,
492
     height: 0,
497
-    flex: 0, // disable 'flex:1' when hiding a View
493
+    flex: 0 // disable 'flex:1' when hiding a View
498
   },
494
   },
499
   loadingView: {
495
   loadingView: {
500
     backgroundColor: BGWASH,
496
     backgroundColor: BGWASH,
501
     flex: 1,
497
     flex: 1,
502
-    justifyContent: 'center',
503
-    alignItems: 'center',
504
-    height: 100,
498
+    justifyContent: "center",
499
+    alignItems: "center",
500
+    height: 100
505
   },
501
   },
506
   webView: {
502
   webView: {
507
-    backgroundColor: '#ffffff',
508
-  },
503
+    backgroundColor: "#ffffff"
504
+  }
509
 });
505
 });
510
-
511
-module.exports = WebView;

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

5
  * LICENSE file in the root directory of this source tree.
5
  * LICENSE file in the root directory of this source tree.
6
  *
6
  *
7
  * @format
7
  * @format
8
- * @flow
8
+ * @typescript
9
  */
9
  */
10
 
10
 
11
 'use strict';
11
 'use strict';
23
   },
23
   },
24
 };
24
 };
25
 
25
 
26
-module.exports = WebViewShared;
26
+export default WebViewShared

+ 8
- 0
src/index.ts Vedi File

1
+import IOSWebView from "./WebView.ios"; 
2
+import AndroidWebView from "./WebView.android"; 
3
+
4
+declare var _test1: typeof IOSWebView;
5
+declare var _test2: typeof AndroidWebView;
6
+
7
+/// export to get the shape of the module
8
+export default { WebView: IOSWebView}

typings/index.d.ts → src/types/WebViewTypes.ts Vedi File

1
-import { ComponentType, ReactElement, ReactNode, Component } from 'react';
2
-import { Insets, NativeSyntheticEvent, StyleProp, ViewProps, ViewStyle } from 'react-native';
1
+import { ComponentType, ReactElement, ReactNode } from "react";
2
+import {
3
+  Insets,
4
+  NativeSyntheticEvent,
5
+  StyleProp,
6
+  ViewProps,
7
+  ViewStyle
8
+} from "react-native";
9
+
10
+declare module "react-native" {
11
+  interface UIManagerStatic {
12
+    dispatchViewManagerCommand(node: any, callback: any, x: any): void;
13
+    RNCUIWebView: any;
14
+    RNCWKWebView: any;
15
+    RNCWebView: any;
16
+  }
17
+}
3
 
18
 
4
 export interface WebViewNativeEvent {
19
 export interface WebViewNativeEvent {
5
   readonly url: string;
20
   readonly url: string;
12
 export interface WebViewIOSLoadRequestEvent extends WebViewNativeEvent {
27
 export interface WebViewIOSLoadRequestEvent extends WebViewNativeEvent {
13
   target: number;
28
   target: number;
14
   lockIdentifier: number;
29
   lockIdentifier: number;
15
-  navigationType: "click" | "formsubmit" | "backforward" | "reload" | "formresubmit" | "other";
30
+  navigationType:
31
+    | "click"
32
+    | "formsubmit"
33
+    | "backforward"
34
+    | "reload"
35
+    | "formresubmit"
36
+    | "other";
16
 }
37
 }
17
 
38
 
18
 export interface WebViewProgressEvent extends WebViewNativeEvent {
39
 export interface WebViewProgressEvent extends WebViewNativeEvent {
21
 
42
 
22
 export interface WebViewNavigation extends WebViewNativeEvent {
43
 export interface WebViewNavigation extends WebViewNativeEvent {
23
   readonly navigationType:
44
   readonly navigationType:
24
-    | 'click'
25
-    | 'formsubmit'
26
-    | 'backforward'
27
-    | 'reload'
28
-    | 'formresubmit'
29
-    | 'other';
45
+    | "click"
46
+    | "formsubmit"
47
+    | "backforward"
48
+    | "reload"
49
+    | "formresubmit"
50
+    | "other";
30
 }
51
 }
31
 
52
 
32
 export interface WebViewMessage extends WebViewNativeEvent {
53
 export interface WebViewMessage extends WebViewNativeEvent {
48
 export type WebViewErrorEvent = NativeSyntheticEvent<WebViewError>;
69
 export type WebViewErrorEvent = NativeSyntheticEvent<WebViewError>;
49
 
70
 
50
 export type DataDetectorTypes =
71
 export type DataDetectorTypes =
51
-  | 'phoneNumber'
52
-  | 'link'
53
-  | 'address'
54
-  | 'calendarEvent'
55
-  | 'trackingNumber'
56
-  | 'flightNumber'
57
-  | 'lookupSuggestion'
58
-  | 'none'
59
-  | 'all';
60
-
61
-export type OverScrollModeType = 'always' | 'content' | 'never';
72
+  | "phoneNumber"
73
+  | "link"
74
+  | "address"
75
+  | "calendarEvent"
76
+  | "trackingNumber"
77
+  | "flightNumber"
78
+  | "lookupSuggestion"
79
+  | "none"
80
+  | "all";
81
+
82
+export type OverScrollModeType = "always" | "content" | "never";
62
 
83
 
63
 export interface WebViewSourceUri {
84
 export interface WebViewSourceUri {
64
   /**
85
   /**
76
    * Additional HTTP headers to send with the request.
97
    * Additional HTTP headers to send with the request.
77
    * NOTE: On Android, this can only be used with GET requests.
98
    * NOTE: On Android, this can only be used with GET requests.
78
    */
99
    */
79
-  headers?: {[key: string]: string};
100
+  headers?: { [key: string]: string };
80
 
101
 
81
   /**
102
   /**
82
    * The HTTP body to send with the request. This must be a valid
103
    * The HTTP body to send with the request. This must be a valid
102
 
123
 
103
 export interface WebViewNativeConfig {
124
 export interface WebViewNativeConfig {
104
   /*
125
   /*
105
-    * The native component used to render the WebView.
106
-    */
126
+   * The native component used to render the WebView.
127
+   */
107
   component?: ComponentType<WebViewSharedProps>;
128
   component?: ComponentType<WebViewSharedProps>;
108
   /*
129
   /*
109
-    * Set props directly on the native component WebView. Enables custom props which the
110
-    * original WebView doesn't pass through.
111
-    */
130
+   * Set props directly on the native component WebView. Enables custom props which the
131
+   * original WebView doesn't pass through.
132
+   */
112
   props?: any;
133
   props?: any;
113
   /*
134
   /*
114
-    * Set the ViewManager to use for communication with the native side.
115
-    * @platform ios
116
-    */
135
+   * Set the ViewManager to use for communication with the native side.
136
+   * @platform ios
137
+   */
117
   viewManager?: any;
138
   viewManager?: any;
118
 }
139
 }
119
 
140
 
142
    *   - fast: 0.99 (the default for iOS web view)
163
    *   - fast: 0.99 (the default for iOS web view)
143
    * @platform ios
164
    * @platform ios
144
    */
165
    */
145
-  decelerationRate?: 'fast' | 'normal' | number;
166
+  decelerationRate?: "fast" | "normal" | number;
146
 
167
 
147
   /**
168
   /**
148
    * Boolean value that determines whether scrolling is enabled in the
169
    * Boolean value that determines whether scrolling is enabled in the
157
    * The default value is false.
178
    * The default value is false.
158
    * @platform ios
179
    * @platform ios
159
    */
180
    */
160
-  pagingEnabled?: boolean,
181
+  pagingEnabled?: boolean;
161
 
182
 
162
   /**
183
   /**
163
    * The amount by which the web view content is inset from the edges of
184
    * The amount by which the web view content is inset from the edges of
216
   /**
237
   /**
217
    * If true, this will be able horizontal swipe gestures when using the WKWebView. The default value is `false`.
238
    * If true, this will be able horizontal swipe gestures when using the WKWebView. The default value is `false`.
218
    */
239
    */
219
-  allowsBackForwardNavigationGestures?: boolean
240
+  allowsBackForwardNavigationGestures?: boolean;
220
 }
241
 }
221
 
242
 
222
 export interface AndroidWebViewProps {
243
 export interface AndroidWebViewProps {
262
   saveFormDataDisabled?: boolean;
283
   saveFormDataDisabled?: boolean;
263
 
284
 
264
   /*
285
   /*
265
-    * Used on Android only, controls whether the given list of URL prefixes should
266
-    * make {@link com.facebook.react.views.webview.ReactWebViewClient} to launch a
267
-    * default activity intent for those URL instead of loading it within the webview.
268
-    * Use this to list URLs that WebView cannot handle, e.g. a PDF url.
269
-    * @platform android
270
-    */
286
+   * Used on Android only, controls whether the given list of URL prefixes should
287
+   * make {@link com.facebook.react.views.webview.ReactWebViewClient} to launch a
288
+   * default activity intent for those URL instead of loading it within the webview.
289
+   * Use this to list URLs that WebView cannot handle, e.g. a PDF url.
290
+   * @platform android
291
+   */
271
   urlPrefixesForDefaultIntent?: string[];
292
   urlPrefixesForDefaultIntent?: string[];
272
 
293
 
273
   /**
294
   /**
308
    * - `'compatibility'` -  WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
329
    * - `'compatibility'` -  WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
309
    * @platform android
330
    * @platform android
310
    */
331
    */
311
-  mixedContentMode?: 'never' | 'always' | 'compatibility';
332
+  mixedContentMode?: "never" | "always" | "compatibility";
312
 }
333
 }
313
 
334
 
314
-export interface WebViewSharedProps extends ViewProps, IOSWebViewProps, AndroidWebViewProps {
335
+export interface WebViewSharedProps
336
+  extends ViewProps,
337
+    IOSWebViewProps,
338
+    AndroidWebViewProps {
315
   /**
339
   /**
316
    * @Deprecated. Use `source` instead.
340
    * @Deprecated. Use `source` instead.
317
    */
341
    */
329
   /**
353
   /**
330
    * Function that returns a view to show if there's an error.
354
    * Function that returns a view to show if there's an error.
331
    */
355
    */
332
-  renderError?: (errorDomain: string | undefined, errorCode: number, errorDesc: string) => ReactElement<any>; // view to show if there's an error
356
+  renderError?: (
357
+    errorDomain: string | undefined,
358
+    errorCode: number,
359
+    errorDesc: string
360
+  ) => ReactElement<any>; // view to show if there's an error
333
 
361
 
334
   /**
362
   /**
335
    * Function that returns a loading indicator.
363
    * Function that returns a loading indicator.
429
   style?: StyleProp<ViewStyle>;
457
   style?: StyleProp<ViewStyle>;
430
   children?: ReactNode;
458
   children?: ReactNode;
431
 }
459
 }
432
-
433
-export class WebView extends Component<WebViewSharedProps> {
434
-  public goForward: () => void;
435
-  public goBack: () => void;
436
-  public reload: () => void;
437
-  public stopLoading: () => void;
438
-  public postMessage: (msg: string) => void;
439
-  public injectJavaScript: (js: string) => void;
440
-}

+ 3
- 0
src/utils.ts Vedi File

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

+ 28
- 0
tsconfig.base.json Vedi File

1
+{
2
+  "compilerOptions": {
3
+    "declaration": true,
4
+    "declarationDir": "lib",    
5
+    "esModuleInterop": true,
6
+    "isolatedModules": false,
7
+    "outDir": "./lib",
8
+    "moduleResolution": "node",
9
+    "module": "esnext",
10
+    "experimentalDecorators": true,
11
+    "allowSyntheticDefaultImports": true,
12
+    "lib": ["es6"],
13
+    "sourceMap": true,
14
+    "removeComments": true,
15
+    "jsx": "react-native",
16
+    "strict": true,
17
+    "noImplicitAny": true,
18
+    "strictNullChecks": false,
19
+    "strictFunctionTypes": true,
20
+    "noImplicitThis": true,
21
+    "alwaysStrict": true,
22
+    "noUnusedLocals": true,
23
+    "noImplicitReturns": true,
24
+    "noFallthroughCasesInSwitch": true,
25
+    "resolveJsonModule": true,
26
+    "target": "esnext"
27
+  }
28
+}

+ 5
- 0
tsconfig.json Vedi File

1
+{
2
+  "extends": "./tsconfig.base.json",
3
+  "include": ["src", "./typings.d.ts", "types", "test"],
4
+  "exclude": ["node_modules", "dist"]  
5
+}

+ 11
- 5
yarn.lock Vedi File

739
     into-stream "^4.0.0"
739
     into-stream "^4.0.0"
740
     lodash "^4.17.4"
740
     lodash "^4.17.4"
741
 
741
 
742
+"@types/invariant@^2.2.29":
743
+  version "2.2.29"
744
+  resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.29.tgz#aa845204cd0a289f65d47e0de63a6a815e30cc66"
745
+  integrity sha512-lRVw09gOvgviOfeUrKc/pmTiRZ7g7oDOU6OAutyuSHpm1/o2RaBQvRhgK8QEdu+FFuw/wnWb29A/iuxv9i8OpQ==
746
+
742
 "@types/prop-types@*":
747
 "@types/prop-types@*":
743
   version "15.5.6"
748
   version "15.5.6"
744
   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.6.tgz#9c03d3fed70a8d517c191b7734da2879b50ca26c"
749
   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.6.tgz#9c03d3fed70a8d517c191b7734da2879b50ca26c"
2572
     semver "^5.1.0"
2577
     semver "^5.1.0"
2573
     through2 "^2.0.0"
2578
     through2 "^2.0.0"
2574
 
2579
 
2575
-fbjs@^0.8.17, fbjs@^0.8.9:
2580
+fbjs@^0.8.9:
2576
   version "0.8.17"
2581
   version "0.8.17"
2577
   resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
2582
   resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
2578
   dependencies:
2583
   dependencies:
2673
     array-uniq "^1.0.0"
2678
     array-uniq "^1.0.0"
2674
     semver-regex "^1.0.0"
2679
     semver-regex "^1.0.0"
2675
 
2680
 
2676
-flow-bin@^0.80.0:
2677
-  version "0.80.0"
2678
-  resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.80.0.tgz#04cc1ee626a6f50786f78170c92ebe1745235403"
2679
-
2680
 flush-write-stream@^1.0.0:
2681
 flush-write-stream@^1.0.0:
2681
   version "1.0.3"
2682
   version "1.0.3"
2682
   resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd"
2683
   resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd"
6374
   version "0.0.6"
6375
   version "0.0.6"
6375
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
6376
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
6376
 
6377
 
6378
+typescript@^3.1.6:
6379
+  version "3.1.6"
6380
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68"
6381
+  integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==
6382
+
6377
 ua-parser-js@^0.7.18:
6383
 ua-parser-js@^0.7.18:
6378
   version "0.7.18"
6384
   version "0.7.18"
6379
   resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed"
6385
   resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed"