From 6db4d066d2a52a90ade9e2ee15fdd6e1132f6ea2 Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Fri, 27 Nov 2020 15:39:43 -0300 Subject: [PATCH 01/13] Upgrade react-native-render-html to v6.0.0.alpha-7 --- package-lock.json | 146 +++++++++++++++++++++++++++++----- package.json | 4 +- src/components/RenderHTML.js | 148 +++++++++++++++++++++++++++++++++++ 3 files changed, 278 insertions(+), 20 deletions(-) create mode 100644 src/components/RenderHTML.js diff --git a/package-lock.json b/package-lock.json index 04200605df51..5ed04e02002d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2913,6 +2913,74 @@ "chalk": "^3.0.0" } }, + "@native-html/css-processor": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@native-html/css-processor/-/css-processor-1.6.0.tgz", + "integrity": "sha512-NBXwaJU3y19pBoJBq6sHXJs64duPQ0oBWMJCY+R6D9hDAH1KJ0q2lulPj7yHrCiwjrCDQ+HdI0wy7xNZx6MIvw==", + "requires": { + "css-to-react-native": "^3.0.0" + } + }, + "@native-html/transient-render-engine": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@native-html/transient-render-engine/-/transient-render-engine-3.5.4.tgz", + "integrity": "sha512-2oSsaFHq6xIa35XqzIdtxC2yhTlCafOHIHgvI4V4dgOl8TYbzSKqF08Hg2Aa07E9q6ARNckPdo+/+xBs1Uxq/A==", + "requires": { + "@native-html/css-processor": "1.6.0", + "htmlparser2": "^5.0.1" + }, + "dependencies": { + "dom-serializer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.1.0.tgz", + "integrity": "sha512-ox7bvGXt2n+uLWtCRLybYx60IrOlWL/aCebWJk1T0d4m3y2tzf4U3ij9wBMUb6YJZpz06HCCYuyCDveE2xXmzQ==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==" + }, + "domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "requires": { + "domelementtype": "^2.0.1" + } + }, + "domutils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.2.tgz", + "integrity": "sha512-NKbgaM8ZJOecTZsIzW5gSuplsX2IWW2mIK7xVr8hTQF2v1CJWTmLZ1HOCh5sH+IzVPAGE5IucooOkvwBRAdowA==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^3.3.0" + } + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" + }, + "htmlparser2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", + "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.3.0", + "domutils": "^2.4.2", + "entities": "^2.0.0" + } + } + } + }, "@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", @@ -3471,6 +3539,14 @@ "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==", "dev": true }, + "@types/ramda": { + "version": "0.27.32", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.27.32.tgz", + "integrity": "sha512-vdwZcWC+hlTxB//LZQLS1+VEdArImGI4yVKUpeqB8b9mBXgDFXCuQoOt8spQbi8fTyNLOdqRv6liSm2ckxWLog==", + "requires": { + "ts-toolbelt": "^6.15.1" + } + }, "@types/semver": { "version": "7.3.4", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.4.tgz", @@ -5745,6 +5821,11 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, + "camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + }, "caniuse-lite": { "version": "1.0.30001148", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001148.tgz", @@ -6608,6 +6689,11 @@ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true }, + "css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" + }, "css-hot-loader": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/css-hot-loader/-/css-hot-loader-1.4.4.tgz", @@ -6758,6 +6844,16 @@ } } }, + "css-to-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", + "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", + "requires": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "css-what": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", @@ -7376,6 +7472,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, "requires": { "domelementtype": "^2.0.1", "entities": "^2.0.0" @@ -7384,12 +7481,14 @@ "domelementtype": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", - "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==" + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==", + "dev": true }, "entities": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true } } }, @@ -7407,7 +7506,8 @@ "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true }, "domexception": { "version": "2.0.1", @@ -7430,6 +7530,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, "requires": { "domelementtype": "1" } @@ -7438,6 +7539,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, "requires": { "dom-serializer": "0", "domelementtype": "1" @@ -7999,7 +8101,8 @@ "entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true }, "env-paths": { "version": "2.2.0", @@ -9502,11 +9605,6 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, "eventsource": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", @@ -11204,6 +11302,7 @@ "version": "3.10.1", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, "requires": { "domelementtype": "^1.3.1", "domhandler": "^2.3.0", @@ -11217,6 +11316,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -18639,8 +18739,7 @@ "postcss-value-parser": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "dev": true + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" }, "prelude-ls": { "version": "1.2.1", @@ -19459,14 +19558,20 @@ } }, "react-native-render-html": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/react-native-render-html/-/react-native-render-html-4.2.4.tgz", - "integrity": "sha512-OiLItEzKgS7dzD9XI5bHhjcUEfpWdzH1FgexzjbBdICPfYjmmcefpcRmLZY1+HMfxJ7wL8iF1PzTF48LchGTBA==", + "version": "6.0.0-alpha.7", + "resolved": "https://registry.npmjs.org/react-native-render-html/-/react-native-render-html-6.0.0-alpha.7.tgz", + "integrity": "sha512-lfxE1nmuxSczOKwIN+2LVq7WMzHPNLTXSdP/lR975Mzt4lZs5Q7F7OWHVC/6OXXw7UEVpJPyErdAPKxObUuGHA==", "requires": { - "buffer": "^4.5.1", - "events": "^1.1.0", - "html-entities": "^1.2.0", - "htmlparser2": "3.10.1" + "@native-html/transient-render-engine": "^3.5.4", + "@types/ramda": "^0.27.32", + "ramda": "^0.27.1" + }, + "dependencies": { + "ramda": { + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", + "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==" + } } }, "react-native-safe-area-context": { @@ -22181,6 +22286,11 @@ "utf8-byte-length": "^1.0.1" } }, + "ts-toolbelt": { + "version": "6.15.5", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz", + "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==" + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", diff --git a/package.json b/package.json index d3566f35131a..c43cb721705f 100644 --- a/package.json +++ b/package.json @@ -60,9 +60,9 @@ "react-native-image-picker": "^2.3.3", "react-native-keyboard-spacer": "^0.4.1", "react-native-modal": "^11.5.6", - "react-native-pdf": "^6.2.2", "react-native-onyx": "git+https://git@github.com:Expensify/react-native-onyx.git#8e29d1807382c8a1325c92858c551f6b19e1aaad", - "react-native-render-html": "^4.2.3", + "react-native-pdf": "^6.2.2", + "react-native-render-html": "^6.0.0-alpha.7", "react-native-safe-area-context": "^3.1.4", "react-native-web": "^0.14.0", "react-native-web-webview": "^1.0.2", diff --git a/src/components/RenderHTML.js b/src/components/RenderHTML.js new file mode 100644 index 000000000000..38db08dac9ca --- /dev/null +++ b/src/components/RenderHTML.js @@ -0,0 +1,148 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Platform, View, useWindowDimensions} from 'react-native'; +import HTML, { + defaultHTMLElementModels, + TNodeChildrenRenderer, + splitBoxModelStyle +} from 'react-native-render-html'; +import Config from '../CONFIG'; +import {getAuthToken} from '../libs/API'; +import styles, {webViewStyles} from '../styles/StyleSheet'; +import fontFamily from '../styles/fontFamily'; +import AnchorForCommentsOnly from './AnchorForCommentsOnly'; +import ImageThumbnailWithModal from './ImageThumbnailWithModal'; + +const MAX_IMG_DIMENSIONS = 512; + +const EXTRA_FONTS = [ + fontFamily.GTA, + fontFamily.GTA_BOLD, + fontFamily.GTA_ITALIC, + fontFamily.MONOSPACE, + fontFamily.SYSTEM, +]; + +function computeImagesMaxWidth(contentWidth) { + return Math.min(MAX_IMG_DIMENSIONS, contentWidth); +} + +function PreRenderer({key, tnode}) { + return ( + + + + ); +} + +function AnchorRenderer({tnode, key, style}) { + const htmlAttribs = tnode.attributes; + return ( + + + + ); +} + +function CodeRenderer({key, style, TDefaultRenderer, ...defaultProps}) { + // We split wrapper and inner styles + // "boxModel" corresponds to border, margin, padding and backgroundColor + const { boxModel, rest } = splitBoxModelStyle(style); + return ( + + + + ); +} + +function ImgRenderer({key, tnode}) { + const htmlAttribs = tnode.attributes; + // Attaches authTokens as a URL parameter to load image attachments + let previewSource = htmlAttribs['data-expensify-source'] + ? `${htmlAttribs.src}?authToken=${getAuthToken()}` + : htmlAttribs.src; + + let source = htmlAttribs['data-expensify-source'] + ? `${htmlAttribs['data-expensify-source']}?authToken=${getAuthToken()}` + : htmlAttribs.src; + + // Update the image URL so the images can be accessed depending on the config environment + previewSource = previewSource.replace( + Config.EXPENSIFY.URL_EXPENSIFY_COM, + Config.EXPENSIFY.URL_API_ROOT, + ); + source = source.replace( + Config.EXPENSIFY.URL_EXPENSIFY_COM, + Config.EXPENSIFY.URL_API_ROOT, + ); + + return ( + + ); +} + +AnchorRenderer.model = defaultHTMLElementModels.a; +PreRenderer.model = defaultHTMLElementModels.pre; +CodeRenderer.model = defaultHTMLElementModels.code; +ImgRenderer.model = defaultHTMLElementModels.img; + +// Define the custom render methods +const renderers = { + a: AnchorRenderer, + pre: PreRenderer, + code: CodeRenderer, + img: ImgRenderer, +}; + +const propTypes = { + html: PropTypes.string.isRequired, + debug: PropTypes.bool +}; + +const RenderHTML = ({html, debug = false}) => { + const {width} = useWindowDimensions(); + const containerWidth = width * 0.8; + return ( + + ); +}; + +RenderHTML.displayName = 'RenderHTML'; +RenderHTML.propTypes = propTypes; + +export default RenderHTML; From b1c9e02ea555fc8269e493d2c646db9d61eb3d7a Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Fri, 27 Nov 2020 15:40:40 -0300 Subject: [PATCH 02/13] Refactor src/styles/StyleSheet, webViewStyles preTagStyle, codeTagStyle and blockquoteTagStyle have been merged into tagStyles, since those styles are passed to custom renderers via "style" prop in the new v6 renderer API. It is more consistent with the recommended way to proceed with the new release of react-native-render-html. --- src/styles/StyleSheet.js | 69 +++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/src/styles/StyleSheet.js b/src/styles/StyleSheet.js index 87ee3dec7461..351e0aee79fe 100644 --- a/src/styles/StyleSheet.js +++ b/src/styles/StyleSheet.js @@ -134,7 +134,7 @@ const styles = { }, flexWrap: { - flexWrap: 'wrap' + flexWrap: 'wrap', }, flexGrow1: { @@ -283,7 +283,7 @@ const styles = { navText: { color: colors.heading, fontSize: 17, - fontWeight: '700' + fontWeight: '700', }, reportOptions: { @@ -841,7 +841,7 @@ const styles = { height: 0, }, shadowOpacity: 0.3, - shadowRadius: 20 + shadowRadius: 20, }, hamburgerOpen: { @@ -939,27 +939,11 @@ const baseCodeTagStyles = { }; const webViewStyles = { - preTagStyle: { - ...baseCodeTagStyles, - paddingTop: 4, - paddingBottom: 5, - paddingRight: 8, - paddingLeft: 8, - }, - codeTagStyle: { - ...baseCodeTagStyles, - paddingLeft: 5, - paddingRight: 5, - paddingBottom: 2, - alignSelf: 'flex-start', - }, - blockquoteTagStyle: { - borderLeftColor: colors.border, - borderLeftWidth: 4, - paddingLeft: 12, - marginTop: 4, - marginBottom: 4, - }, + // As of react-native-render-html v6, don't declare distinct styles for + // custom renderers, the API for custom renderers has changed. Declare the + // styles in the below "tagStyles" instead. If you need to reuse those + // styles from the renderer, just pass the "style" prop to the underlying + // component. tagStyles: { em: { fontFamily: fontFamily.GTA_ITALIC, @@ -968,7 +952,7 @@ const webViewStyles = { del: { textDecorationLine: 'line-through', - textDecorationStyle: 'solid' + textDecorationStyle: 'solid', }, strong: { @@ -977,14 +961,37 @@ const webViewStyles = { }, a: { - color: colors.blue + color: colors.blue, + textDecorationColor: colors.blue + }, + + blockquote: { + borderLeftColor: colors.border, + borderLeftWidth: 4, + paddingLeft: 12, + marginTop: 4, + marginBottom: 4, }, pre: { + ...baseCodeTagStyles, + paddingTop: 4, + paddingBottom: 5, + paddingRight: 8, + paddingLeft: 8, fontFamily: fontFamily.MONOSPACE, + + // override user agent styles + marginTop: 0, + marginBottom: 0 }, code: { + ...baseCodeTagStyles, + paddingLeft: 5, + paddingRight: 5, + paddingBottom: 2, + alignSelf: 'flex-start', fontFamily: fontFamily.MONOSPACE, }, @@ -992,17 +999,16 @@ const webViewStyles = { borderColor: colors.border, borderRadius: 8, borderWidth: 1, - } + }, }, baseFontStyle: { color: colors.text, fontSize: 15, fontFamily: fontFamily.GTA, - } + }, }; - /** * Takes safe area insets and returns padding to use for a View * @@ -1010,7 +1016,10 @@ const webViewStyles = { * @returns {{paddingBottom: number, paddingTop: number}} */ function getSafeAreaPadding(insets) { - return {paddingTop: insets.top, paddingBottom: insets.bottom * safeInsertPercentage}; + return { + paddingTop: insets.top, + paddingBottom: insets.bottom * safeInsertPercentage, + }; } /** From e0af40051abd8956dd709bcea9ffb250f62bdb0f Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Fri, 27 Nov 2020 15:43:30 -0300 Subject: [PATCH 03/13] Move HTML rendering logic from ReportActionItemFragment to RenderHTML A new RenderHTML component is available in src/components/RenderHTML.js. It lightens the aforementioned component, and help refine HTML logic. The new blockquoteRenderer has been dropped since it only inject styles to the renderer. --- src/components/RenderHTML.js | 54 ++++----- .../home/report/ReportActionItemFragment.js | 113 ++---------------- 2 files changed, 35 insertions(+), 132 deletions(-) diff --git a/src/components/RenderHTML.js b/src/components/RenderHTML.js index 38db08dac9ca..753c37b6dc15 100644 --- a/src/components/RenderHTML.js +++ b/src/components/RenderHTML.js @@ -1,17 +1,19 @@ +/* eslint-disable react/prop-types */ import React from 'react'; import PropTypes from 'prop-types'; -import {Platform, View, useWindowDimensions} from 'react-native'; +import {useWindowDimensions} from 'react-native'; import HTML, { defaultHTMLElementModels, TNodeChildrenRenderer, - splitBoxModelStyle + splitBoxModelStyle, } from 'react-native-render-html'; import Config from '../CONFIG'; import {getAuthToken} from '../libs/API'; -import styles, {webViewStyles} from '../styles/StyleSheet'; +import {webViewStyles} from '../styles/StyleSheet'; import fontFamily from '../styles/fontFamily'; import AnchorForCommentsOnly from './AnchorForCommentsOnly'; import ImageThumbnailWithModal from './ImageThumbnailWithModal'; +import InlineCodeBlock from './InlineCodeBlock'; const MAX_IMG_DIMENSIONS = 512; @@ -27,19 +29,12 @@ function computeImagesMaxWidth(contentWidth) { return Math.min(MAX_IMG_DIMENSIONS, contentWidth); } -function PreRenderer({key, tnode}) { - return ( - - - - ); -} - function AnchorRenderer({tnode, key, style}) { const htmlAttribs = tnode.attributes; return ( + key={key} + > ); } -function CodeRenderer({key, style, TDefaultRenderer, ...defaultProps}) { +function CodeRenderer({ + key, + style, + TDefaultRenderer, ...defaultRendererProps +}) { // We split wrapper and inner styles - // "boxModel" corresponds to border, margin, padding and backgroundColor - const { boxModel, rest } = splitBoxModelStyle(style); + // "boxModelStyle" corresponds to border, margin, padding and backgroundColor + const {boxModelStyle, otherStyle: textStyle} = splitBoxModelStyle(style); return ( - - - + ); } function ImgRenderer({key, tnode}) { const htmlAttribs = tnode.attributes; + // Attaches authTokens as a URL parameter to load image attachments let previewSource = htmlAttribs['data-expensify-source'] ? `${htmlAttribs.src}?authToken=${getAuthToken()}` @@ -102,21 +101,19 @@ function ImgRenderer({key, tnode}) { } AnchorRenderer.model = defaultHTMLElementModels.a; -PreRenderer.model = defaultHTMLElementModels.pre; CodeRenderer.model = defaultHTMLElementModels.code; ImgRenderer.model = defaultHTMLElementModels.img; // Define the custom render methods const renderers = { a: AnchorRenderer, - pre: PreRenderer, code: CodeRenderer, img: ImgRenderer, }; const propTypes = { html: PropTypes.string.isRequired, - debug: PropTypes.bool + debug: PropTypes.bool, }; const RenderHTML = ({html, debug = false}) => { @@ -144,5 +141,8 @@ const RenderHTML = ({html, debug = false}) => { RenderHTML.displayName = 'RenderHTML'; RenderHTML.propTypes = propTypes; +RenderHTML.defaultProps = { + debug: false, +}; export default RenderHTML; diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js index 363e9cc4bf73..0ec35ffcf925 100644 --- a/src/pages/home/report/ReportActionItemFragment.js +++ b/src/pages/home/report/ReportActionItemFragment.js @@ -1,18 +1,11 @@ import React from 'react'; -import HTML from 'react-native-render-html'; -import { - Linking, ActivityIndicator, View, Dimensions -} from 'react-native'; +import {ActivityIndicator, View} from 'react-native'; import PropTypes from 'prop-types'; import Str from 'expensify-common/lib/str'; import ReportActionFragmentPropTypes from './ReportActionFragmentPropTypes'; -import styles, {webViewStyles, colors} from '../../../styles/StyleSheet'; +import styles, {colors} from '../../../styles/StyleSheet'; +import RenderHTML from '../../../components/RenderHTML'; import Text from '../../../components/Text'; -import AnchorForCommentsOnly from '../../../components/AnchorForCommentsOnly'; -import InlineCodeBlock from '../../../components/InlineCodeBlock'; -import * as API from '../../../libs/API'; -import ImageThumbnailWithModal from '../../../components/ImageThumbnailWithModal'; -import Config from '../../../CONFIG'; const propTypes = { // The message fragment needing to be displayed @@ -31,85 +24,8 @@ const defaultProps = { }; class ReportActionItemFragment extends React.PureComponent { - constructor(props) { - super(props); - - // Define the custom render methods - // For tags, the attribute is used to be more cross-platform friendly - this.customRenderers = { - a: (htmlAttribs, children, convertedCSSStyles, passProps) => ( - - {children} - - ), - pre: (htmlAttribs, children, convertedCSSStyles, passProps) => ( - - {children} - - ), - code: (htmlAttribs, children, convertedCSSStyles, passProps) => ( - - {children} - - ), - blockquote: (htmlAttribs, children, convertedCSSStyles, passProps) => ( - - {children} - - ), - img: (htmlAttribs, children, convertedCSSStyles, passProps) => { - // Attaches authTokens as a URL parameter to load image attachments - let previewSource = htmlAttribs['data-expensify-source'] - ? `${htmlAttribs.src}?authToken=${API.getAuthToken()}` - : htmlAttribs.src; - - let source = htmlAttribs['data-expensify-source'] - ? `${htmlAttribs['data-expensify-source']}?authToken=${API.getAuthToken()}` - : htmlAttribs.src; - - // Update the image URL so the images can be accessed depending on the config environment - previewSource = previewSource.replace( - Config.EXPENSIFY.URL_EXPENSIFY_COM, - Config.EXPENSIFY.URL_API_ROOT - ); - source = source.replace( - Config.EXPENSIFY.URL_EXPENSIFY_COM, - Config.EXPENSIFY.URL_API_ROOT - ); - - return ( - - ); - }, - }; - } - render() { const {fragment} = this.props; - const maxImageDimensions = 512; - const windowWidth = Dimensions.get('window').width; switch (fragment.type) { case 'COMMENT': // If this is an attachment placeholder, return the placeholder component @@ -126,24 +42,11 @@ class ReportActionItemFragment extends React.PureComponent { } // Only render HTML if we have html in the fragment - return fragment.html !== fragment.text - ? ( - Linking.openURL(href)} - html={fragment.html} - imagesMaxWidth={Math.min(maxImageDimensions, windowWidth * 0.8)} - imagesInitialDimensions={{width: maxImageDimensions, height: maxImageDimensions}} - /> - ) - : ( - - {Str.htmlDecode(fragment.text)} - - ); + return fragment.html !== fragment.text ? ( + + ) : ( + {Str.htmlDecode(fragment.text)} + ); case 'TEXT': return ( Date: Fri, 27 Nov 2020 15:46:29 -0300 Subject: [PATCH 04/13] Adapted InlineCodeBlock to the new API The component has been simplified from 3 to 2 target variants, and has been rewritten to fit the new Renderer API. --- .../InlineCodeBlock/index.android.js | 18 ------------- src/components/InlineCodeBlock/index.ios.js | 18 ------------- src/components/InlineCodeBlock/index.js | 23 +++++++++-------- .../InlineCodeBlock/index.native.js | 25 +++++++++++++++++++ src/components/InlineCodeBlock/propTypes.js | 10 ++++++++ 5 files changed, 47 insertions(+), 47 deletions(-) delete mode 100644 src/components/InlineCodeBlock/index.android.js delete mode 100644 src/components/InlineCodeBlock/index.ios.js create mode 100644 src/components/InlineCodeBlock/index.native.js create mode 100644 src/components/InlineCodeBlock/propTypes.js diff --git a/src/components/InlineCodeBlock/index.android.js b/src/components/InlineCodeBlock/index.android.js deleted file mode 100644 index 00f294e3a327..000000000000 --- a/src/components/InlineCodeBlock/index.android.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {View} from 'react-native'; -import {webViewStyles} from '../../styles/StyleSheet'; - -const propTypes = { - children: PropTypes.node.isRequired, -}; - -const InlineCodeBlock = ({children}) => ( - - {children} - -); - -InlineCodeBlock.propTypes = propTypes; -InlineCodeBlock.displayName = 'InlineCodeBlock'; -export default InlineCodeBlock; diff --git a/src/components/InlineCodeBlock/index.ios.js b/src/components/InlineCodeBlock/index.ios.js deleted file mode 100644 index 40ce39772dc8..000000000000 --- a/src/components/InlineCodeBlock/index.ios.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {View} from 'react-native'; -import styles, {webViewStyles} from '../../styles/StyleSheet'; - -const propTypes = { - children: PropTypes.node.isRequired, -}; - -const InlineCodeBlock = ({children}) => ( - - {children} - -); - -InlineCodeBlock.propTypes = propTypes; -InlineCodeBlock.displayName = 'InlineCodeBlock'; -export default InlineCodeBlock; diff --git a/src/components/InlineCodeBlock/index.js b/src/components/InlineCodeBlock/index.js index 6264e55b0264..cffffbd6d1d9 100644 --- a/src/components/InlineCodeBlock/index.js +++ b/src/components/InlineCodeBlock/index.js @@ -1,16 +1,17 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import {Text} from 'react-native'; -import {webViewStyles} from '../../styles/StyleSheet'; +import propTypes from './propTypes'; -const propTypes = { - children: PropTypes.node.isRequired, -}; - -const InlineCodeBlock = ({children}) => ( - - {children} - +const InlineCodeBlock = ({ + TDefaultRenderer, + defaultRendererProps, + boxModelStyle, + textStyle, +}) => ( + ); InlineCodeBlock.propTypes = propTypes; diff --git a/src/components/InlineCodeBlock/index.native.js b/src/components/InlineCodeBlock/index.native.js new file mode 100644 index 000000000000..566686b09cf8 --- /dev/null +++ b/src/components/InlineCodeBlock/index.native.js @@ -0,0 +1,25 @@ +/* eslint-disable react/jsx-props-no-spreading */ +import React from 'react'; +import {View, Platform} from 'react-native'; +import styles from '../../styles/StyleSheet'; +import propTypes from './propTypes'; + +const InlineCodeBlock = ({ + TDefaultRenderer, + defaultRendererProps, + boxModelStyle, + textStyle, +}) => ( + + + +); + +InlineCodeBlock.propTypes = propTypes; +InlineCodeBlock.displayName = 'InlineCodeBlock'; +export default InlineCodeBlock; diff --git a/src/components/InlineCodeBlock/propTypes.js b/src/components/InlineCodeBlock/propTypes.js new file mode 100644 index 000000000000..8b2ebdef8eb4 --- /dev/null +++ b/src/components/InlineCodeBlock/propTypes.js @@ -0,0 +1,10 @@ +import PropTypes from 'prop-types'; + +const propTypes = { + TDefaultRenderer: PropTypes.func.isRequired, + defaultRendererProps: PropTypes.object.isRequired, + boxModelStyle: PropTypes.any.isRequired, + textStyle: PropTypes.any.isRequired +}; + +export default propTypes; From 6fd467ac4dd793eb1a393f7d8ed8f911c7bcff28 Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Fri, 27 Nov 2020 15:48:30 -0300 Subject: [PATCH 05/13] Refactor propTypes in AnchorForCommentsOnly component Those types were duplicated! --- src/components/AnchorForCommentsOnly/index.js | 24 +---------------- .../AnchorForCommentsOnly/index.native.js | 27 +------------------ .../AnchorForCommentsOnly/propTypes.js | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 49 deletions(-) create mode 100644 src/components/AnchorForCommentsOnly/propTypes.js diff --git a/src/components/AnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/index.js index 96244d347278..10d3f4a9727d 100644 --- a/src/components/AnchorForCommentsOnly/index.js +++ b/src/components/AnchorForCommentsOnly/index.js @@ -1,28 +1,6 @@ import React from 'react'; -import PropTypes from 'prop-types'; import {StyleSheet} from 'react-native'; - -/** - * Text based component that is passed a URL to open onPress - */ - -const propTypes = { - // The URL to open - href: PropTypes.string, - - // What headers to send to the linked page (usually noopener and noreferrer) - rel: PropTypes.string, - - // Used to determine where to open a link ("_blank" is passed for a new tab) - target: PropTypes.string, - - // Any children to display - children: PropTypes.node, - - // Any additional styles to apply - // eslint-disable-next-line react/forbid-prop-types - style: PropTypes.any, -}; +import propTypes from './propTypes'; const defaultProps = { href: '', diff --git a/src/components/AnchorForCommentsOnly/index.native.js b/src/components/AnchorForCommentsOnly/index.native.js index d4ed3dfc944b..bd4158af0fe7 100644 --- a/src/components/AnchorForCommentsOnly/index.native.js +++ b/src/components/AnchorForCommentsOnly/index.native.js @@ -1,31 +1,6 @@ import React from 'react'; -import PropTypes from 'prop-types'; import {Linking, StyleSheet, Text} from 'react-native'; - -/** - * Text based component that is passed a URL to open onPress - */ - -const propTypes = { - // The URL to open - href: PropTypes.string, - - // What headers to send to the linked page (usually noopener and noreferrer) - // This is unused in native, but is here for parity with web - rel: PropTypes.string, - - // Used to determine where to open a link ("_blank" is passed for a new tab) - // This is unused in native, but is here for parity with web - target: PropTypes.string, - - - // Any children to display - children: PropTypes.node, - - // Any additional styles to apply - // eslint-disable-next-line react/forbid-prop-types - style: PropTypes.any, -}; +import propTypes from './propTypes'; const defaultProps = { href: '', diff --git a/src/components/AnchorForCommentsOnly/propTypes.js b/src/components/AnchorForCommentsOnly/propTypes.js new file mode 100644 index 000000000000..623ab040a492 --- /dev/null +++ b/src/components/AnchorForCommentsOnly/propTypes.js @@ -0,0 +1,27 @@ +import PropTypes from 'prop-types'; + +/** + * Text based component that is passed a URL to open onPress + */ +const propTypes = { + // The URL to open + href: PropTypes.string, + + // What headers to send to the linked page (usually noopener and noreferrer) + // This is unused in native, but is here for parity with web + rel: PropTypes.string, + + // Used to determine where to open a link ("_blank" is passed for a new tab) + // This is unused in native, but is here for parity with web + target: PropTypes.string, + + + // Any children to display + children: PropTypes.node, + + // Any additional styles to apply + // eslint-disable-next-line react/forbid-prop-types + style: PropTypes.any, +}; + +export default propTypes; From 0290473aace1730ce0252f83f01f3ead41080c06 Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Sat, 28 Nov 2020 08:47:46 -0300 Subject: [PATCH 06/13] Add __DEV__ global variable in webpack environment This variable is provided by React Native JavaScript environment, and required by react-native-render-html. Reference: https://reactnative.dev/docs/javascript-environment --- config/webpack/webpack.dev.js | 9 +++++++-- config/webpack/webpack.prod.js | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js index 871b46e53e55..4f6e0bd32fe9 100644 --- a/config/webpack/webpack.dev.js +++ b/config/webpack/webpack.dev.js @@ -16,6 +16,11 @@ module.exports = merge(common, { plugins: [ new webpack.DefinePlugin({ __REACT_WEB_CONFIG__: JSON.stringify(env), - }) - ] + + // React Native JavaScript environment requires the global __DEV__ variable to be accessible. + // react-native-render-html uses variable to log exclusively during development. + // See https://reactnative.dev/docs/javascript-environment + __DEV__: true, + }), + ], }); diff --git a/config/webpack/webpack.prod.js b/config/webpack/webpack.prod.js index 3a1604c44c3a..6cccd5242175 100644 --- a/config/webpack/webpack.prod.js +++ b/config/webpack/webpack.prod.js @@ -12,6 +12,11 @@ module.exports = merge(common, { plugins: [ new webpack.DefinePlugin({ __REACT_WEB_CONFIG__: JSON.stringify(env), + + // React Native JavaScript environment requires the global __DEV__ variable to be accessible. + // react-native-render-html uses variable to log exclusively during development. + // See https://reactnative.dev/docs/javascript-environment + __DEV__: false, }) ], }); From 7e8cfac63f908bc398cfef105ee68718648a0efd Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Sat, 28 Nov 2020 08:49:14 -0300 Subject: [PATCH 07/13] Remove react-native-render-html from files transpiled by babel-loader The new version of this library already provide transpiled sources (no JSX). --- config/webpack/webpack.common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index 28b397f7bc72..334d52593a75 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -52,7 +52,7 @@ module.exports = { */ exclude: [ // eslint-disable-next-line max-len - /node_modules\/(?!(react-native-render-html|react-native-webview|react-native-onyx)\/).*|\.native\.js$/, + /node_modules\/(?!(react-native-webview|react-native-onyx)\/).*|\.native\.js$/, platformExclude ], }, From e6244661c0db3b0b48c254c69ed6fb606bffa568 Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Mon, 30 Nov 2020 19:06:16 -0300 Subject: [PATCH 08/13] Upgrade react-native-render-html to v6.0.0-alpha.8 --- package-lock.json | 31 +++++++++++++++++++------------ package.json | 2 +- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5ed04e02002d..4076bdab8592 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2914,20 +2914,22 @@ } }, "@native-html/css-processor": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@native-html/css-processor/-/css-processor-1.6.0.tgz", - "integrity": "sha512-NBXwaJU3y19pBoJBq6sHXJs64duPQ0oBWMJCY+R6D9hDAH1KJ0q2lulPj7yHrCiwjrCDQ+HdI0wy7xNZx6MIvw==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@native-html/css-processor/-/css-processor-1.6.1.tgz", + "integrity": "sha512-3l4SmYU5CIwL7f8GSssypWfFd7W/FcqVrOomhDRbaWYsxKh2T0zNcIjJbkr8ZbpXJk3qKrV1EMoTJ8vt6H8M9Q==", "requires": { "css-to-react-native": "^3.0.0" } }, "@native-html/transient-render-engine": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/@native-html/transient-render-engine/-/transient-render-engine-3.5.4.tgz", - "integrity": "sha512-2oSsaFHq6xIa35XqzIdtxC2yhTlCafOHIHgvI4V4dgOl8TYbzSKqF08Hg2Aa07E9q6ARNckPdo+/+xBs1Uxq/A==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@native-html/transient-render-engine/-/transient-render-engine-3.6.0.tgz", + "integrity": "sha512-fvPIzD+b2xq7+cIcFwItze3IS59eneht7h31VqRQ5CyN7mCTfcuxCmMzLDdM7/1Chn4A79tG0yEWeJQSt2565Q==", "requires": { - "@native-html/css-processor": "1.6.0", - "htmlparser2": "^5.0.1" + "@native-html/css-processor": "1.6.1", + "@types/ramda": "^0.27.32", + "htmlparser2": "^5.0.1", + "ramda": "^0.27.1" }, "dependencies": { "dom-serializer": { @@ -2978,6 +2980,11 @@ "domutils": "^2.4.2", "entities": "^2.0.0" } + }, + "ramda": { + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", + "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==" } } }, @@ -19558,11 +19565,11 @@ } }, "react-native-render-html": { - "version": "6.0.0-alpha.7", - "resolved": "https://registry.npmjs.org/react-native-render-html/-/react-native-render-html-6.0.0-alpha.7.tgz", - "integrity": "sha512-lfxE1nmuxSczOKwIN+2LVq7WMzHPNLTXSdP/lR975Mzt4lZs5Q7F7OWHVC/6OXXw7UEVpJPyErdAPKxObUuGHA==", + "version": "6.0.0-alpha.8", + "resolved": "https://registry.npmjs.org/react-native-render-html/-/react-native-render-html-6.0.0-alpha.8.tgz", + "integrity": "sha512-iMXnJ59mB9bV0O/w/GEqcTQ1PnV7/tjmxC8eDZv8vTIbN3wVvpgwvPWS/aTndDtvBC9mHYGG+CazH7ALqJjJMw==", "requires": { - "@native-html/transient-render-engine": "^3.5.4", + "@native-html/transient-render-engine": "^3.6.0", "@types/ramda": "^0.27.32", "ramda": "^0.27.1" }, diff --git a/package.json b/package.json index c43cb721705f..903c3be491f1 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "react-native-modal": "^11.5.6", "react-native-onyx": "git+https://git@github.com:Expensify/react-native-onyx.git#8e29d1807382c8a1325c92858c551f6b19e1aaad", "react-native-pdf": "^6.2.2", - "react-native-render-html": "^6.0.0-alpha.7", + "react-native-render-html": "^6.0.0-alpha.8", "react-native-safe-area-context": "^3.1.4", "react-native-web": "^0.14.0", "react-native-web-webview": "^1.0.2", From 1e1f64b935ee881c038083137f2e338f44df3218 Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Mon, 30 Nov 2020 19:14:46 -0300 Subject: [PATCH 09/13] Add documentation for computeImagesMaxWidth function --- src/components/RenderHTML.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/components/RenderHTML.js b/src/components/RenderHTML.js index 753c37b6dc15..ca064b3afc69 100644 --- a/src/components/RenderHTML.js +++ b/src/components/RenderHTML.js @@ -25,6 +25,14 @@ const EXTRA_FONTS = [ fontFamily.SYSTEM, ]; +/** + * Compute images maximum width from the available screen width. This function + * is used by the HTML component in the default renderer for img tags to scale + * down images that would otherwise overflow horizontally. + * + * @param {number} contentWidth - The content width provided to the HTML + * component. + */ function computeImagesMaxWidth(contentWidth) { return Math.min(MAX_IMG_DIMENSIONS, contentWidth); } @@ -100,6 +108,7 @@ function ImgRenderer({key, tnode}) { ); } +// Define default element models for these renderers. AnchorRenderer.model = defaultHTMLElementModels.a; CodeRenderer.model = defaultHTMLElementModels.code; ImgRenderer.model = defaultHTMLElementModels.img; From 88bf063455cd5bbc760b7bcdd045cc656f174bea Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Wed, 2 Dec 2020 14:05:40 -0300 Subject: [PATCH 10/13] Add .vscode to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 8efffec2c5f8..0c4904335d51 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,9 @@ build/ local.properties *.iml +# Vscode +.vscode + # node.js # node_modules/ From b13059268096c8913f6eb4ca71bfde94ab423877 Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Wed, 2 Dec 2020 14:23:08 -0300 Subject: [PATCH 11/13] Rename propTypes to anchorForCommentsOnlyPropTypes in AnchorForCommentsOnly component --- .../{propTypes.js => anchorForCommentsOnlyPropTypes.js} | 4 ++-- src/components/AnchorForCommentsOnly/index.js | 4 ++-- src/components/AnchorForCommentsOnly/index.native.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename src/components/AnchorForCommentsOnly/{propTypes.js => anchorForCommentsOnlyPropTypes.js} (88%) diff --git a/src/components/AnchorForCommentsOnly/propTypes.js b/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js similarity index 88% rename from src/components/AnchorForCommentsOnly/propTypes.js rename to src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js index 623ab040a492..eb61cdc7d3a1 100644 --- a/src/components/AnchorForCommentsOnly/propTypes.js +++ b/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; /** * Text based component that is passed a URL to open onPress */ -const propTypes = { +const anchorForCommentsOnlyPropTypes = { // The URL to open href: PropTypes.string, @@ -24,4 +24,4 @@ const propTypes = { style: PropTypes.any, }; -export default propTypes; +export default anchorForCommentsOnlyPropTypes; diff --git a/src/components/AnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/index.js index 10d3f4a9727d..6e70e859cf96 100644 --- a/src/components/AnchorForCommentsOnly/index.js +++ b/src/components/AnchorForCommentsOnly/index.js @@ -1,6 +1,6 @@ import React from 'react'; import {StyleSheet} from 'react-native'; -import propTypes from './propTypes'; +import anchorForCommentsOnlyPropTypes from './anchorForCommentsOnlyPropTypes'; const defaultProps = { href: '', @@ -30,7 +30,7 @@ const AnchorForCommentsOnly = ({ ); -AnchorForCommentsOnly.propTypes = propTypes; +AnchorForCommentsOnly.propTypes = anchorForCommentsOnlyPropTypes; AnchorForCommentsOnly.defaultProps = defaultProps; AnchorForCommentsOnly.displayName = 'AnchorForCommentsOnly'; diff --git a/src/components/AnchorForCommentsOnly/index.native.js b/src/components/AnchorForCommentsOnly/index.native.js index bd4158af0fe7..a5b184a8a6b3 100644 --- a/src/components/AnchorForCommentsOnly/index.native.js +++ b/src/components/AnchorForCommentsOnly/index.native.js @@ -1,6 +1,6 @@ import React from 'react'; import {Linking, StyleSheet, Text} from 'react-native'; -import propTypes from './propTypes'; +import anchorForCommentsOnlyPropTypes from './anchorForCommentsOnlyPropTypes'; const defaultProps = { href: '', @@ -20,7 +20,7 @@ const AnchorForCommentsOnly = ({ Linking.openURL(href)} {...props}>{children} ); -AnchorForCommentsOnly.propTypes = propTypes; +AnchorForCommentsOnly.propTypes = anchorForCommentsOnlyPropTypes; AnchorForCommentsOnly.defaultProps = defaultProps; AnchorForCommentsOnly.displayName = 'AnchorForCommentsOnly'; From 1eff1d19d18e7cd5da55d89e3ec4d70da32dd17c Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Wed, 2 Dec 2020 14:26:03 -0300 Subject: [PATCH 12/13] Split android and ios sources for InlineCodeBlock component --- .../InlineCodeBlock/index.android.js | 19 +++++++++++++++++++ .../{index.native.js => index.ios.js} | 8 ++++---- src/components/InlineCodeBlock/index.js | 4 ++-- ...opTypes.js => inlineCodeBlockPropTypes.js} | 4 ++-- 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 src/components/InlineCodeBlock/index.android.js rename src/components/InlineCodeBlock/{index.native.js => index.ios.js} (72%) rename src/components/InlineCodeBlock/{propTypes.js => inlineCodeBlockPropTypes.js} (75%) diff --git a/src/components/InlineCodeBlock/index.android.js b/src/components/InlineCodeBlock/index.android.js new file mode 100644 index 000000000000..d68ca0031b84 --- /dev/null +++ b/src/components/InlineCodeBlock/index.android.js @@ -0,0 +1,19 @@ +/* eslint-disable react/jsx-props-no-spreading */ +import React from 'react'; +import {View} from 'react-native'; +import inlineCodeBlockPropTypes from './inlineCodeBlockPropTypes'; + +const InlineCodeBlock = ({ + TDefaultRenderer, + defaultRendererProps, + boxModelStyle, + textStyle, +}) => ( + + + +); + +InlineCodeBlock.propTypes = inlineCodeBlockPropTypes; +InlineCodeBlock.displayName = 'InlineCodeBlock'; +export default InlineCodeBlock; diff --git a/src/components/InlineCodeBlock/index.native.js b/src/components/InlineCodeBlock/index.ios.js similarity index 72% rename from src/components/InlineCodeBlock/index.native.js rename to src/components/InlineCodeBlock/index.ios.js index 566686b09cf8..65b3d26d1f19 100644 --- a/src/components/InlineCodeBlock/index.native.js +++ b/src/components/InlineCodeBlock/index.ios.js @@ -1,8 +1,8 @@ /* eslint-disable react/jsx-props-no-spreading */ import React from 'react'; -import {View, Platform} from 'react-native'; +import {View} from 'react-native'; import styles from '../../styles/StyleSheet'; -import propTypes from './propTypes'; +import inlineCodeBlockPropTypes from './inlineCodeBlockPropTypes'; const InlineCodeBlock = ({ TDefaultRenderer, @@ -13,13 +13,13 @@ const InlineCodeBlock = ({ ); -InlineCodeBlock.propTypes = propTypes; +InlineCodeBlock.propTypes = inlineCodeBlockPropTypes; InlineCodeBlock.displayName = 'InlineCodeBlock'; export default InlineCodeBlock; diff --git a/src/components/InlineCodeBlock/index.js b/src/components/InlineCodeBlock/index.js index cffffbd6d1d9..aa6edab7018e 100644 --- a/src/components/InlineCodeBlock/index.js +++ b/src/components/InlineCodeBlock/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import propTypes from './propTypes'; +import inlineCodeBlockPropTypes from './inlineCodeBlockPropTypes'; const InlineCodeBlock = ({ TDefaultRenderer, @@ -14,6 +14,6 @@ const InlineCodeBlock = ({ /> ); -InlineCodeBlock.propTypes = propTypes; +InlineCodeBlock.propTypes = inlineCodeBlockPropTypes; InlineCodeBlock.displayName = 'InlineCodeBlock'; export default InlineCodeBlock; diff --git a/src/components/InlineCodeBlock/propTypes.js b/src/components/InlineCodeBlock/inlineCodeBlockPropTypes.js similarity index 75% rename from src/components/InlineCodeBlock/propTypes.js rename to src/components/InlineCodeBlock/inlineCodeBlockPropTypes.js index 8b2ebdef8eb4..f880d3a1e4ae 100644 --- a/src/components/InlineCodeBlock/propTypes.js +++ b/src/components/InlineCodeBlock/inlineCodeBlockPropTypes.js @@ -1,10 +1,10 @@ import PropTypes from 'prop-types'; -const propTypes = { +const inlineCodeBlockPropTypes = { TDefaultRenderer: PropTypes.func.isRequired, defaultRendererProps: PropTypes.object.isRequired, boxModelStyle: PropTypes.any.isRequired, textStyle: PropTypes.any.isRequired }; -export default propTypes; +export default inlineCodeBlockPropTypes; From fc7e33faed77cf6b15964a4a80d1aaab617f3bdf Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Wed, 2 Dec 2020 14:37:12 -0300 Subject: [PATCH 13/13] Comply with eslint rules --- src/components/RenderHTML.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/RenderHTML.js b/src/components/RenderHTML.js index ca064b3afc69..3f05c055736c 100644 --- a/src/components/RenderHTML.js +++ b/src/components/RenderHTML.js @@ -29,9 +29,10 @@ const EXTRA_FONTS = [ * Compute images maximum width from the available screen width. This function * is used by the HTML component in the default renderer for img tags to scale * down images that would otherwise overflow horizontally. - * + * * @param {number} contentWidth - The content width provided to the HTML * component. + * @returns {number} The minimum between contentWidth and MAX_IMG_DIMENSIONS */ function computeImagesMaxWidth(contentWidth) { return Math.min(MAX_IMG_DIMENSIONS, contentWidth); @@ -59,9 +60,7 @@ function AnchorRenderer({tnode, key, style}) { } function CodeRenderer({ - key, - style, - TDefaultRenderer, ...defaultRendererProps + key, style, TDefaultRenderer, ...defaultRendererProps }) { // We split wrapper and inner styles // "boxModelStyle" corresponds to border, margin, padding and backgroundColor