Bez popisu

index.js 3.5KB

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