Markdown svg & image to respect size if available (#6030) (#6034)

(cherry picked from commit c9ce61d28b)

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
Mattermost Build 2022-03-07 19:36:58 +01:00 committed by GitHub
parent 3b63beb9e0
commit 46f683f28f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 182 additions and 6862 deletions

View file

@ -146,6 +146,7 @@ export default class Markdown extends PureComponent {
if (node.type === 'image') {
extraProps.reactChildren = node.react.children;
extraProps.linkDestination = node.linkDestination;
extraProps.size = node.size;
}
return extraProps;
@ -183,7 +184,7 @@ export default class Markdown extends PureComponent {
return <Text style={this.computeTextStyle([this.props.baseTextStyle, this.props.textStyles.code], context)}>{literal}</Text>;
};
renderImage = ({linkDestination, reactChildren, context, src}) => {
renderImage = ({linkDestination, reactChildren, context, src, size}) => {
if (!this.props.imagesMetadata) {
return null;
}
@ -211,6 +212,7 @@ export default class Markdown extends PureComponent {
isReplyPost={this.props.isReplyPost}
postId={this.props.postId}
source={src}
sourceSize={size}
>
{reactChildren}
</MarkdownImage>

View file

@ -22,15 +22,24 @@ import ImageViewPort from '@components/image_viewport';
import ProgressiveImage from '@components/progressive_image';
import TouchableWithFeedback from '@components/touchable_with_feedback';
import mattermostManaged from '@mattermost-managed';
import {changeOpacity, makeStyleFromTheme} from '@mm-redux/utils/theme_utils';
import EphemeralStore from '@store/ephemeral_store';
import BottomSheet from '@utils/bottom_sheet';
import {generateId} from '@utils/file';
import {openGalleryAtIndex} from '@utils/gallery';
import {calculateDimensions, getViewPortWidth, isGifTooLarge} from '@utils/images';
import {getMarkdownImageSize} from '@utils/markdown';
import {normalizeProtocol, tryOpenURL} from '@utils/url';
const ANDROID_MAX_HEIGHT = 4096;
const ANDROID_MAX_WIDTH = 4096;
const getStyleSheet = makeStyleFromTheme((theme) => ({
svg: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.06),
borderRadius: 8,
flex: 1,
},
}));
export default class MarkdownImage extends ImageViewPort {
static propTypes = {
@ -42,6 +51,7 @@ export default class MarkdownImage extends ImageViewPort {
linkDestination: PropTypes.string,
postId: PropTypes.string,
source: PropTypes.string.isRequired,
sourceSize: PropTypes.object,
theme: PropTypes.object,
};
@ -53,10 +63,12 @@ export default class MarkdownImage extends ImageViewPort {
super(props);
const metadata = props.imagesMetadata?.[props.source] || Object.values(props.imagesMetadata || {})?.[0];
const size = getMarkdownImageSize(props.isReplyPost, this.hasPermanentSidebar(), props.sourceSize, metadata);
this.fileId = generateId();
this.state = {
originalHeight: metadata?.height || 0,
originalWidth: metadata?.width || 0,
originalHeight: size.height,
originalWidth: size.width,
failed: isGifTooLarge(metadata),
format: metadata?.format,
uri: null,
@ -207,6 +219,18 @@ export default class MarkdownImage extends ImageViewPort {
{this.props.children}
</Text>
);
} else if (fileInfo?.format === 'svg') {
const style = getStyleSheet(this.props.theme);
image = (
<SvgUri
uri={fileInfo.uri}
style={style.svg}
width={width}
height={height}
onError={this.handleSizeFailed}
/>
);
} else {
// React Native complains if we try to pass resizeMode as a style
const source = fileInfo.uri ? {uri: fileInfo.uri} : null;
@ -225,14 +249,6 @@ export default class MarkdownImage extends ImageViewPort {
</TouchableWithFeedback>
);
}
} else if (fileInfo?.format === 'svg') {
image = (
<SvgUri
uri={fileInfo.uri}
style={{flex: 1}}
onError={this.handleSizeFailed}
/>
);
}
if (image && this.props.linkDestination) {

View file

@ -112,6 +112,8 @@ const MarkTableImage = ({disable, imagesMetadata, postId, serverURL, source, the
<SvgUri
uri={source}
style={styles.container}
width={width}
height={height}
//@ts-expect-error onError not defined in the types
onError={onLoadFailed}

View file

@ -3,6 +3,7 @@
import {Platform, StyleSheet} from 'react-native';
import {getViewPortWidth} from '@utils/images';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
export function getCodeFont() {
@ -206,3 +207,41 @@ export function switchKeyboardForCodeBlocks(value, cursorPosition) {
return 'default';
}
export const getMarkdownImageSize = (isReplyPost, isTablet, sourceSize, knownSize) => {
let ratioW;
let ratioH;
if (sourceSize?.width && sourceSize?.height) {
// if the source image is set with HxW
return {width: sourceSize.width, height: sourceSize.height};
} else if (knownSize?.width && knownSize.height) {
// If the metadata size is set calculate the ratio
ratioW = knownSize.width > 0 ? knownSize.height / knownSize.width : 1;
ratioH = knownSize.height > 0 ? knownSize.width / knownSize.height : 1;
}
if (sourceSize?.width && !sourceSize.height && ratioW) {
// If source Width is set calculate the height using the ratio
return {width: sourceSize.width, height: sourceSize.width * ratioW};
} else if (sourceSize?.height && !sourceSize.width && ratioH) {
// If source Height is set calculate the width using the ratio
return {width: sourceSize.height * ratioH, height: sourceSize.height};
}
if (sourceSize?.width || sourceSize?.height) {
// if at least one size is set and we do not have metadata (svg's)
const width = sourceSize.width;
const height = sourceSize.height;
return {width: width || height, height: height || width};
}
if (knownSize?.width && knownSize.height) {
// When metadata values are set
return {width: knownSize.width, height: knownSize.height};
}
// When no metadata and source size is not specified (full size svg's)
const width = getViewPortWidth(isReplyPost, isTablet);
return {width, height: width};
};

128
package-lock.json generated
View file

@ -27,8 +27,8 @@
"array.prototype.flat": "1.2.5",
"base-64": "1.0.0",
"buffer": "6.0.3",
"commonmark": "0.30.0",
"commonmark-react-renderer": "4.3.5",
"commonmark": "github:mattermost/commonmark.js#90a62d97ed2dbd2d4711a5adda327128f5827983",
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
"deep-equal": "2.0.5",
"deepmerge": "4.2.2",
"emoji-regex": "10.0.0",
@ -1925,6 +1925,18 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/runtime-corejs3": {
"version": "7.17.2",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz",
"integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==",
"dependencies": {
"core-js-pure": "^3.20.2",
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
@ -7199,13 +7211,14 @@
},
"node_modules/commonmark": {
"version": "0.30.0",
"resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.30.0.tgz",
"integrity": "sha512-j1yoUo4gxPND1JWV9xj5ELih0yMv1iCWDG6eEQIPLSWLxzCXiFoyS7kvB+WwU+tZMf4snwJMMtaubV0laFpiBA==",
"resolved": "git+ssh://git@github.com/mattermost/commonmark.js.git#90a62d97ed2dbd2d4711a5adda327128f5827983",
"license": "BSD-2-Clause",
"dependencies": {
"entities": "~2.0",
"entities": "~3.0.1",
"mdurl": "~1.0.1",
"minimist": ">=1.2.2",
"string.prototype.repeat": "^0.2.0"
"minimist": "~1.2.5",
"string.prototype.repeat": "^1.0.0",
"xregexp": "5.1.0"
},
"bin": {
"commonmark": "bin/commonmark"
@ -7216,8 +7229,8 @@
},
"node_modules/commonmark-react-renderer": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/commonmark-react-renderer/-/commonmark-react-renderer-4.3.5.tgz",
"integrity": "sha512-UwUgplz8kFSMCe9+Dg/BcV75lc7R/V6mvMYJq2p29i5aaIBd0252k9HeSGa2VtEPHfg2/trS9qC7iAxnO7r6ng==",
"resolved": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
"license": "MIT",
"dependencies": {
"lodash.assign": "^4.2.0",
"lodash.isplainobject": "^4.0.6",
@ -7225,10 +7238,21 @@
"xss-filters": "^1.2.6"
},
"peerDependencies": {
"commonmark": "^0.27.0 || ^0.26.0 || ^0.24.0",
"commonmark": "^0.30.0",
"react": ">=0.14.0"
}
},
"node_modules/commonmark/node_modules/entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
@ -7365,6 +7389,16 @@
"semver": "bin/semver.js"
}
},
"node_modules/core-js-pure": {
"version": "3.21.1",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz",
"integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
@ -22038,9 +22072,13 @@
}
},
"node_modules/string.prototype.repeat": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz",
"integrity": "sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8="
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
"integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
"dependencies": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"node_modules/string.prototype.trim": {
"version": "1.2.5",
@ -23774,6 +23812,14 @@
"sax": "^1.2.1"
}
},
"node_modules/xregexp": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.0.tgz",
"integrity": "sha512-PynwUWtXnSZr8tpQlDPMZfPTyv78EYuA4oI959ukxcQ0a9O/lvndLVKy5wpImzzA26eMxpZmnAXJYiQA13AtWA==",
"dependencies": {
"@babel/runtime-corejs3": "^7.14.9"
}
},
"node_modules/xss-filters": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/xss-filters/-/xss-filters-1.2.7.tgz",
@ -25084,6 +25130,15 @@
"regenerator-runtime": "^0.13.4"
}
},
"@babel/runtime-corejs3": {
"version": "7.17.2",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz",
"integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==",
"requires": {
"core-js-pure": "^3.20.2",
"regenerator-runtime": "^0.13.4"
}
},
"@babel/template": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
@ -29158,20 +29213,26 @@
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
},
"commonmark": {
"version": "0.30.0",
"resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.30.0.tgz",
"integrity": "sha512-j1yoUo4gxPND1JWV9xj5ELih0yMv1iCWDG6eEQIPLSWLxzCXiFoyS7kvB+WwU+tZMf4snwJMMtaubV0laFpiBA==",
"version": "git+ssh://git@github.com/mattermost/commonmark.js.git#90a62d97ed2dbd2d4711a5adda327128f5827983",
"from": "commonmark@github:mattermost/commonmark.js#90a62d97ed2dbd2d4711a5adda327128f5827983",
"requires": {
"entities": "~2.0",
"entities": "~3.0.1",
"mdurl": "~1.0.1",
"minimist": ">=1.2.2",
"string.prototype.repeat": "^0.2.0"
"minimist": "~1.2.5",
"string.prototype.repeat": "^1.0.0",
"xregexp": "5.1.0"
},
"dependencies": {
"entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
}
}
},
"commonmark-react-renderer": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/commonmark-react-renderer/-/commonmark-react-renderer-4.3.5.tgz",
"integrity": "sha512-UwUgplz8kFSMCe9+Dg/BcV75lc7R/V6mvMYJq2p29i5aaIBd0252k9HeSGa2VtEPHfg2/trS9qC7iAxnO7r6ng==",
"version": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
"from": "commonmark-react-renderer@github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
"requires": {
"lodash.assign": "^4.2.0",
"lodash.isplainobject": "^4.0.6",
@ -29303,6 +29364,11 @@
}
}
},
"core-js-pure": {
"version": "3.21.1",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz",
"integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ=="
},
"core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
@ -40754,9 +40820,13 @@
}
},
"string.prototype.repeat": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz",
"integrity": "sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8="
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
"integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"string.prototype.trim": {
"version": "1.2.5",
@ -42057,6 +42127,14 @@
"sax": "^1.2.1"
}
},
"xregexp": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.0.tgz",
"integrity": "sha512-PynwUWtXnSZr8tpQlDPMZfPTyv78EYuA4oI959ukxcQ0a9O/lvndLVKy5wpImzzA26eMxpZmnAXJYiQA13AtWA==",
"requires": {
"@babel/runtime-corejs3": "^7.14.9"
}
},
"xss-filters": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/xss-filters/-/xss-filters-1.2.7.tgz",

View file

@ -25,8 +25,8 @@
"array.prototype.flat": "1.2.5",
"base-64": "1.0.0",
"buffer": "6.0.3",
"commonmark": "0.30.0",
"commonmark-react-renderer": "4.3.5",
"commonmark": "github:mattermost/commonmark.js#90a62d97ed2dbd2d4711a5adda327128f5827983",
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
"deep-equal": "2.0.5",
"deepmerge": "4.2.2",
"emoji-regex": "10.0.0",

File diff suppressed because it is too large Load diff

View file

@ -1,351 +0,0 @@
diff --git a/node_modules/commonmark-react-renderer/src/commonmark-react-renderer.js b/node_modules/commonmark-react-renderer/src/commonmark-react-renderer.js
index 91b0001..05b80fa 100644
--- a/node_modules/commonmark-react-renderer/src/commonmark-react-renderer.js
+++ b/node_modules/commonmark-react-renderer/src/commonmark-react-renderer.js
@@ -12,7 +12,12 @@ var typeAliases = {
htmlblock: 'html_block',
htmlinline: 'html_inline',
codeblock: 'code_block',
- hardbreak: 'linebreak'
+ hardbreak: 'linebreak',
+ atmention: 'at_mention',
+ channellink: 'channel_link',
+ editedindicator: 'edited_indicator',
+ tableRow: 'table_row',
+ tableCell: 'table_cell'
};
var defaultRenderers = {
@@ -24,6 +29,7 @@ var defaultRenderers = {
link: 'a',
paragraph: 'p',
strong: 'strong',
+ del: 'del',
thematic_break: 'hr', // eslint-disable-line camelcase
html_block: HtmlRenderer, // eslint-disable-line camelcase
@@ -52,7 +58,71 @@ var defaultRenderers = {
},
text: null,
- softbreak: null
+ softbreak: null,
+
+ at_mention: function AtMention(props) {
+ var newProps = getCoreProps(props);
+ if (props.username) {
+ props['data-mention-name'] = props.username;
+ }
+
+ return createElement('span', newProps, props.children);
+ },
+ channel_link: function ChannelLink(props) {
+ var newProps = getCoreProps(props);
+ if (props.channelName) {
+ props['data-channel-name'] = props.channelName;
+ }
+
+ return createElement('span', newProps, props.children);
+ },
+ emoji: function Emoji(props) {
+ var newProps = getCoreProps(props);
+ if (props.emojiName) {
+ props['data-emoji-name'] = props.emojiName;
+ }
+
+ return createElement('span', newProps, props.children);
+ },
+ edited_indicator: null,
+ hashtag: function Hashtag(props) {
+ var newProps = getCoreProps(props);
+ if (props.hashtag) {
+ props['data-hashtag'] = props.hashtag;
+ }
+
+ return createElement('span', newProps, props.children);
+ },
+ mention_highlight: function MentionHighlight(props) {
+ var newProps = getCoreProps(props);
+ newProps['data-mention-highlight'] = 'true';
+ return createElement('span', newProps, props.children);
+ },
+ search_highlight: function SearchHighlight(props) {
+ var newProps = getCoreProps(props);
+ newProps['data-search-highlight'] = 'true';
+ return createElement('span', newProps, props.children);
+ },
+
+ table: function Table(props) {
+ var childrenArray = React.Children.toArray(props.children);
+
+ var children = [createElement('thead', {'key': 'thead'}, childrenArray.slice(0, 1))];
+ if (childrenArray.length > 1) {
+ children.push(createElement('tbody', {'key': 'tbody'}, childrenArray.slice(1)));
+ }
+
+ return createElement('table', getCoreProps(props), children);
+ },
+ table_row: 'tr',
+ table_cell: function TableCell(props) {
+ var newProps = getCoreProps(props);
+ if (props.align) {
+ newProps.className = 'align-' + props.align;
+ }
+
+ return createElement('td', newProps, props.children);
+ }
};
var coreTypes = Object.keys(defaultRenderers);
@@ -147,7 +217,7 @@ function flattenPosition(pos) {
}
// For some nodes, we want to include more props than for others
-function getNodeProps(node, key, opts, renderer) {
+function getNodeProps(node, key, opts, renderer, context) {
var props = { key: key }, undef;
// `sourcePos` is true if the user wants source information (line/column info from markdown source)
@@ -194,16 +264,49 @@ function getNodeProps(node, key, opts, renderer) {
// Commonmark treats image description as children. We just want the text
props.alt = node.react.children.join('');
- node.react.children = undef;
break;
case 'list':
props.start = node.listStart;
props.type = node.listType;
props.tight = node.listTight;
break;
+ case 'at_mention':
+ props.mentionName = node.mentionName;
+ break;
+ case 'channel_link':
+ props.channelName = node.channelName;
+ break;
+ case 'emoji':
+ props.emojiName = node.emojiName;
+ props.literal = node.literal;
+ break;
+ case 'hashtag':
+ props.hashtag = node.hashtag;
+ break;
+ case 'paragraph':
+ props.first = !(node._prev && node._prev.type === 'paragraph');
+ props.last = !(node._next && node._next.type === 'paragraph');
+ break;
+ case 'edited_indicator':
+ break;
+ case 'table':
+ props.numRows = countRows(node);
+ props.numColumns = countColumns(node);
+ break;
+ case 'table_row':
+ props.isHeading = node.isHeading;
+ break;
+ case 'table_cell':
+ props.isHeading = node.isHeading;
+ props.align = node.align;
+ break;
default:
}
+ if (opts.getExtraPropsForNode) {
+ props = Object.assign(props, opts.getExtraPropsForNode(node));
+ }
+
if (typeof renderer !== 'string') {
props.literal = node.literal;
}
@@ -213,9 +316,29 @@ function getNodeProps(node, key, opts, renderer) {
props.children = children.reduce(reduceChildren, []) || null;
}
+ props.context = context.slice();
+
return props;
}
+function countChildren(node) {
+ var count = 0;
+
+ for (var child = node.firstChild; child; child = child.next) {
+ count += 1;
+ }
+
+ return count;
+}
+
+function countRows(table) {
+ return countChildren(table);
+}
+
+function countColumns(table) {
+ return countChildren(table.firstChild);
+}
+
function getPosition(node) {
if (!node) {
return null;
@@ -238,26 +361,23 @@ function renderNodes(block) {
transformLinkUri: this.transformLinkUri,
transformImageUri: this.transformImageUri,
softBreak: this.softBreak,
- linkTarget: this.linkTarget
+ linkTarget: this.linkTarget,
+ getExtraPropsForNode: this.getExtraPropsForNode
};
- var e, node, entering, leaving, type, doc, key, nodeProps, prevPos, prevIndex = 0;
+ var e;
+ var doc;
+ var context = [];
+ var index = 0;
while ((e = walker.next())) {
- var pos = getPosition(e.node.sourcepos ? e.node : e.node.parent);
- if (prevPos === pos) {
- key = pos + prevIndex;
- prevIndex++;
- } else {
- key = pos;
- prevIndex = 0;
- }
+ var key = String(index);
+ index += 1;
- prevPos = pos;
- entering = e.entering;
- leaving = !entering;
- node = e.node;
- type = normalizeTypeName(node.type);
- nodeProps = null;
+ var entering = e.entering;
+ var leaving = !entering;
+ var node = e.node;
+ var type = normalizeTypeName(node.type);
+ var nodeProps = null;
// If we have not assigned a document yet, assume the current node is just that
if (!doc) {
@@ -270,7 +390,7 @@ function renderNodes(block) {
}
// In HTML, we don't want paragraphs inside of list items
- if (type === 'paragraph' && isGrandChildOfList(node)) {
+ if (!this.renderParagraphsInLists && type === 'paragraph' && isGrandChildOfList(node)) {
continue;
}
@@ -289,7 +409,7 @@ function renderNodes(block) {
if (this.allowNode && (isCompleteParent || !node.isContainer)) {
var nodeChildren = isCompleteParent ? node.react.children : [];
- nodeProps = getNodeProps(node, key, propOptions, renderer);
+ nodeProps = getNodeProps(node, key, propOptions, renderer, context);
disallowedByUser = !this.allowNode({
type: pascalCase(type),
renderer: this.renderers[type],
@@ -298,6 +418,30 @@ function renderNodes(block) {
});
}
+ if (node.isContainer) {
+ var contextType = node.type;
+ if (node.level) {
+ contextType = node.type + node.level;
+ } else if (node.type === 'table_row' && node.parent.firstChild === node) {
+ contextType = 'table_header_row';
+ } else {
+ contextType = node.type;
+ }
+
+ if (entering) {
+ context.push(contextType);
+ } else {
+ var popped = context.pop();
+
+ if (!popped) {
+ throw new Error('Attempted to pop empty stack');
+ } else if (!popped === contextType) {
+ throw new Error('Popped context of type `' + pascalCase(popped) +
+ '` when expecting context of type `' + pascalCase(contextType) + '`');
+ }
+ }
+ }
+
if (!isDocument && (disallowedByUser || disallowedByConfig)) {
if (!this.unwrapDisallowed && entering && node.isContainer) {
walker.resumeAt(node, false);
@@ -313,15 +457,25 @@ function renderNodes(block) {
);
}
- if (node.isContainer && entering) {
+ if (context.length > this.maxDepth) {
+ // Do nothing, we should not regularly be nested this deeply and we don't want to cause React to
+ // overflow the stack
+ } else if (node.isContainer && entering) {
node.react = {
component: renderer,
props: {},
children: []
};
} else {
- var childProps = nodeProps || getNodeProps(node, key, propOptions, renderer);
- if (renderer) {
+ var childProps = nodeProps || getNodeProps(node, key, propOptions, renderer, context);
+ if (renderer === ReactRenderer.forwardChildren) {
+ if (childProps.children) {
+ for (var i = 0; i < childProps.children.length; i++) {
+ var child = childProps.children[i];
+ addChild(node, child);
+ }
+ }
+ } else if (renderer) {
childProps = typeof renderer === 'string'
? childProps
: assign(childProps, {nodeKey: childProps.key});
@@ -341,6 +495,10 @@ function renderNodes(block) {
}
}
+ if (context.length !== 0) {
+ throw new Error('Expected context to be empty after rendering, but has `' + context.join(', ') + '`');
+ }
+
return doc.react.children;
}
@@ -401,21 +559,31 @@ function ReactRenderer(options) {
renderers: assign({}, defaultRenderers, normalizeRenderers(opts.renderers)),
escapeHtml: Boolean(opts.escapeHtml),
skipHtml: Boolean(opts.skipHtml),
+ renderParagraphsInLists: Boolean(opts.renderParagraphsInLists),
transformLinkUri: linkFilter,
transformImageUri: imageFilter,
allowNode: opts.allowNode,
allowedTypes: allowedTypes,
unwrapDisallowed: Boolean(opts.unwrapDisallowed),
render: renderNodes,
- linkTarget: opts.linkTarget || false
+ linkTarget: opts.linkTarget || false,
+ maxDepth: opts.maxDepth || 30,
+ getExtraPropsForNode: opts.getExtraPropsForNode
};
}
+function forwardChildren(props) {
+ return props.children;
+}
+
ReactRenderer.uriTransformer = defaultLinkUriFilter;
ReactRenderer.types = coreTypes.map(pascalCase);
ReactRenderer.renderers = coreTypes.reduce(function(renderers, type) {
renderers[pascalCase(type)] = defaultRenderers[type];
return renderers;
}, {});
+ReactRenderer.countRows = countRows;
+ReactRenderer.countColumns = countColumns;
+ReactRenderer.forwardChildren = forwardChildren;
module.exports = ReactRenderer;

View file

@ -1,14 +1,14 @@
diff --git a/node_modules/react-native-svg/src/xml.tsx b/node_modules/react-native-svg/src/xml.tsx
index 828f104..b480cee 100644
index 828f104..462be2e 100644
--- a/node_modules/react-native-svg/src/xml.tsx
+++ b/node_modules/react-native-svg/src/xml.tsx
@@ -133,7 +133,13 @@ export function SvgUri(props: UriProps) {
@@ -133,10 +133,17 @@ export function SvgUri(props: UriProps) {
useEffect(() => {
uri
? fetchText(uri)
- .then(setXml)
+ .then((xml) => {
+ if (xml) {
+ if (xml && /xmlns="http:\/\/www.w3.org\/[0-9]*\/svg"/.test(xml)) {
+ setXml(xml);
+ return;
+ }
@ -17,3 +17,7 @@ index 828f104..b480cee 100644
.catch(onError)
: setXml(null);
}, [onError, uri]);
+
return <SvgXml xml={xml} override={props} />;
}