No Description

index.js 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. 'use strict';
  2. import React, {useState, useEffect, 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 {
  10. style,
  11. onMessage,
  12. onSizeUpdated,
  13. scrollEnabledWithZoomedin,
  14. scrollEnabled,
  15. } = props;
  16. const [size, setSize] = useState({
  17. height: style && style.height ? style.height : 0,
  18. width: getWidth(style),
  19. });
  20. const [scrollable, setScrollable] = useState(false);
  21. const handleMessage = (event) => {
  22. onMessage && onMessage(event);
  23. if (!event.nativeEvent) {
  24. return;
  25. }
  26. let data = {};
  27. // Sometimes the message is invalid JSON, so we ignore that case
  28. try {
  29. data = JSON.parse(event.nativeEvent.data);
  30. } catch (error) {
  31. console.error(error);
  32. return;
  33. }
  34. const {height, width, zoomedin} = data;
  35. !scrollEnabled && scrollEnabledWithZoomedin && setScrollable(!!zoomedin);
  36. const {height: previousHeight, width: previousWidth} = size;
  37. isSizeChanged({height, previousHeight, width, previousWidth}) &&
  38. setSize({
  39. height,
  40. width,
  41. });
  42. };
  43. const currentScrollEnabled =
  44. scrollEnabled === false && scrollEnabledWithZoomedin
  45. ? scrollable
  46. : scrollEnabled;
  47. const {currentSource, script} = reduceData(props);
  48. const {width, height} = size;
  49. useEffect(
  50. () =>
  51. onSizeUpdated &&
  52. onSizeUpdated({
  53. height,
  54. width,
  55. }),
  56. [width, height, onSizeUpdated],
  57. );
  58. return (
  59. <WebView
  60. {...props}
  61. ref={ref}
  62. onMessage={handleMessage}
  63. style={[
  64. styles.webView,
  65. {
  66. width,
  67. height,
  68. },
  69. style,
  70. ]}
  71. injectedJavaScript={script}
  72. source={currentSource}
  73. scrollEnabled={currentScrollEnabled}
  74. />
  75. );
  76. }),
  77. (prevProps, nextProps) => !shouldUpdate({prevProps, nextProps}),
  78. );
  79. AutoHeightWebView.propTypes = {
  80. onSizeUpdated: PropTypes.func,
  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. viewportContent: PropTypes.string,
  92. scrollEnabledWithZoomedin: PropTypes.bool,
  93. // webview props
  94. originWhitelist: PropTypes.arrayOf(PropTypes.string),
  95. onMessage: PropTypes.func,
  96. scalesPageToFit: PropTypes.bool,
  97. source: PropTypes.object,
  98. };
  99. let defaultProps = {
  100. showsVerticalScrollIndicator: false,
  101. showsHorizontalScrollIndicator: false,
  102. originWhitelist: ['*'],
  103. };
  104. Platform.OS === 'android' &&
  105. Object.assign(defaultProps, {
  106. scalesPageToFit: false,
  107. });
  108. Platform.OS === 'ios' &&
  109. Object.assign(defaultProps, {
  110. viewportContent: 'width=device-width',
  111. });
  112. AutoHeightWebView.defaultProps = defaultProps;
  113. const styles = StyleSheet.create({
  114. webView: {
  115. backgroundColor: 'transparent',
  116. },
  117. });
  118. export default AutoHeightWebView;