No Description

index.js 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. 'use strict';
  2. import React, { useState, useEffect, useMemo, useRef, useImperativeHandle, forwardRef } from 'react';
  3. import { StyleSheet, Platform, ViewPropTypes } from 'react-native';
  4. import PropTypes from 'prop-types';
  5. import { WebView } from 'react-native-webview';
  6. import { getMemoInputProps, getMemoResult, getWidth, isSizeChanged } from './utils';
  7. const AutoHeightWebView = forwardRef((props, ref) => {
  8. let webView = useRef();
  9. useImperativeHandle(ref, () => ({
  10. stopLoading: () => webView.current.stopLoading(),
  11. goForward: () => webView.current.goForward(),
  12. goBack: () => webView.current.goBack(),
  13. reload: () => webView.current.reload(),
  14. injectJavaScript: script => webView.current.injectJavaScript(script)
  15. }));
  16. const { style, onMessage, onSizeUpdated } = props;
  17. const [size, setSize] = useState(() => ({
  18. height: style && style.height ? style.height : 0,
  19. width: getWidth(style)
  20. }));
  21. const hanldeMessage = event => {
  22. if (!event.nativeEvent) {
  23. return;
  24. }
  25. let data = {};
  26. // Sometimes the message is invalid JSON, so we ignore that case
  27. try {
  28. data = JSON.parse(event.nativeEvent.data);
  29. } catch (error) {
  30. console.error(error);
  31. return;
  32. }
  33. const { height, width } = data;
  34. const { height: previousHeight, width: previousWidth } = size;
  35. isSizeChanged({ height, previousHeight, width, previousWidth }) &&
  36. setSize({
  37. height,
  38. width
  39. });
  40. onMessage && onMessage(event);
  41. };
  42. const { source, script } = useMemo(() => getMemoResult(props), [getMemoInputProps(props)]);
  43. const { width, height } = size;
  44. useEffect(
  45. () =>
  46. onSizeUpdated &&
  47. onSizeUpdated({
  48. height,
  49. width
  50. }),
  51. [width, height]
  52. );
  53. return (
  54. <WebView
  55. {...props}
  56. ref={webView}
  57. onMessage={hanldeMessage}
  58. style={[
  59. styles.webView,
  60. {
  61. width,
  62. height
  63. },
  64. style
  65. ]}
  66. injectedJavaScript={script}
  67. source={source}
  68. />
  69. );
  70. });
  71. AutoHeightWebView.propTypes = {
  72. onSizeUpdated: PropTypes.func,
  73. // 'web/' by default on iOS
  74. // 'file:///android_asset/web/' by default on Android
  75. baseUrl: PropTypes.string,
  76. // add baseUrl/files... to android/app/src/assets/ on android
  77. // add baseUrl/files... to project root on iOS
  78. files: PropTypes.arrayOf(
  79. PropTypes.shape({
  80. href: PropTypes.string,
  81. type: PropTypes.string,
  82. rel: PropTypes.string
  83. })
  84. ),
  85. style: ViewPropTypes.style,
  86. customScript: PropTypes.string,
  87. customStyle: PropTypes.string,
  88. // webview props
  89. originWhitelist: PropTypes.arrayOf(PropTypes.string),
  90. onMessage: PropTypes.func,
  91. zoomable: PropTypes.bool,
  92. };
  93. let defaultProps = {
  94. showsVerticalScrollIndicator: false,
  95. showsHorizontalScrollIndicator: false,
  96. originWhitelist: ['*'],
  97. baseUrl: 'web/',
  98. zoomable: true,
  99. };
  100. Platform.OS === 'android' &&
  101. Object.assign(defaultProps, {
  102. baseUrl: 'file:///android_asset/web/',
  103. // if set to true may cause some layout issues (width of container will be than width of screen) on android
  104. scalesPageToFit: false
  105. });
  106. AutoHeightWebView.defaultProps = defaultProps;
  107. const styles = StyleSheet.create({
  108. webView: {
  109. backgroundColor: 'transparent'
  110. }
  111. });
  112. export default AutoHeightWebView;