[IMPROVEMENT] Markdown refactored (#1151)
This commit is contained in:
parent
664563bd6f
commit
c78732729d
File diff suppressed because it is too large
Load Diff
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import Markdown from '../message/Markdown';
|
import Markdown from '../markdown';
|
||||||
import { getCustomEmoji } from '../message/utils';
|
import { getCustomEmoji } from '../message/utils';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import sharedStyles from '../../views/Styles';
|
import sharedStyles from '../../views/Styles';
|
||||||
|
@ -50,6 +50,7 @@ const styles = StyleSheet.create({
|
||||||
|
|
||||||
class ReplyPreview extends Component {
|
class ReplyPreview extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
useMarkdown: PropTypes.bool,
|
||||||
message: PropTypes.object.isRequired,
|
message: PropTypes.object.isRequired,
|
||||||
Message_TimeFormat: PropTypes.string.isRequired,
|
Message_TimeFormat: PropTypes.string.isRequired,
|
||||||
close: PropTypes.func.isRequired,
|
close: PropTypes.func.isRequired,
|
||||||
|
@ -68,7 +69,7 @@ class ReplyPreview extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
message, Message_TimeFormat, baseUrl, username
|
message, Message_TimeFormat, baseUrl, username, useMarkdown
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const time = moment(message.ts).format(Message_TimeFormat);
|
const time = moment(message.ts).format(Message_TimeFormat);
|
||||||
return (
|
return (
|
||||||
|
@ -78,7 +79,7 @@ class ReplyPreview extends Component {
|
||||||
<Text style={styles.username}>{message.u.username}</Text>
|
<Text style={styles.username}>{message.u.username}</Text>
|
||||||
<Text style={styles.time}>{time}</Text>
|
<Text style={styles.time}>{time}</Text>
|
||||||
</View>
|
</View>
|
||||||
<Markdown msg={message.msg} baseUrl={baseUrl} username={username} getCustomEmoji={getCustomEmoji} numberOfLines={1} />
|
<Markdown msg={message.msg} baseUrl={baseUrl} username={username} getCustomEmoji={getCustomEmoji} numberOfLines={1} useMarkdown={useMarkdown} />
|
||||||
</View>
|
</View>
|
||||||
<CustomIcon name='cross' color={COLOR_TEXT_DESCRIPTION} size={20} style={styles.close} onPress={this.close} />
|
<CustomIcon name='cross' color={COLOR_TEXT_DESCRIPTION} size={20} style={styles.close} onPress={this.close} />
|
||||||
</View>
|
</View>
|
||||||
|
@ -87,6 +88,7 @@ class ReplyPreview extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
useMarkdown: state.markdown.useMarkdown,
|
||||||
Message_TimeFormat: state.settings.Message_TimeFormat,
|
Message_TimeFormat: state.settings.Message_TimeFormat,
|
||||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
|
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Text } from 'react-native';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const AtMention = React.memo(({
|
||||||
|
mention, mentions, username, navToRoomInfo
|
||||||
|
}) => {
|
||||||
|
let mentionStyle = styles.mention;
|
||||||
|
if (mention === 'all' || mention === 'here') {
|
||||||
|
mentionStyle = {
|
||||||
|
...mentionStyle,
|
||||||
|
...styles.mentionAll
|
||||||
|
};
|
||||||
|
} else if (mention === username) {
|
||||||
|
mentionStyle = {
|
||||||
|
...mentionStyle,
|
||||||
|
...styles.mentionLoggedUser
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePress = () => {
|
||||||
|
if (mentions && mentions.length && mentions.findIndex(m => m.username === mention) !== -1) {
|
||||||
|
const index = mentions.findIndex(m => m.username === mention);
|
||||||
|
const navParam = {
|
||||||
|
t: 'd',
|
||||||
|
rid: mentions[index]._id
|
||||||
|
};
|
||||||
|
navToRoomInfo(navParam);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
style={mentionStyle}
|
||||||
|
onPress={handlePress}
|
||||||
|
>
|
||||||
|
{`@${ mention }`}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
AtMention.propTypes = {
|
||||||
|
mention: PropTypes.string,
|
||||||
|
username: PropTypes.string,
|
||||||
|
navToRoomInfo: PropTypes.func,
|
||||||
|
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AtMention;
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const BlockQuote = React.memo(({ children }) => (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.quote} />
|
||||||
|
<View style={styles.childContainer}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
));
|
||||||
|
|
||||||
|
BlockQuote.propTypes = {
|
||||||
|
children: PropTypes.node.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BlockQuote;
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Text } from 'react-native';
|
||||||
|
import { emojify } from 'react-emojione';
|
||||||
|
|
||||||
|
import CustomEmoji from '../EmojiPicker/CustomEmoji';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const Emoji = React.memo(({
|
||||||
|
emojiName, literal, isMessageContainsOnlyEmoji, getCustomEmoji, baseUrl
|
||||||
|
}) => {
|
||||||
|
const emojiUnicode = emojify(literal, { output: 'unicode' });
|
||||||
|
const emoji = getCustomEmoji && getCustomEmoji(emojiName);
|
||||||
|
if (emoji) {
|
||||||
|
return (
|
||||||
|
<CustomEmoji
|
||||||
|
baseUrl={baseUrl}
|
||||||
|
style={isMessageContainsOnlyEmoji ? styles.customEmojiBig : styles.customEmoji}
|
||||||
|
emoji={emoji}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return <Text style={isMessageContainsOnlyEmoji ? styles.textBig : styles.text}>{emojiUnicode}</Text>;
|
||||||
|
});
|
||||||
|
|
||||||
|
Emoji.propTypes = {
|
||||||
|
emojiName: PropTypes.string,
|
||||||
|
literal: PropTypes.string,
|
||||||
|
isMessageContainsOnlyEmoji: PropTypes.bool,
|
||||||
|
getCustomEmoji: PropTypes.func,
|
||||||
|
baseUrl: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Emoji;
|
|
@ -0,0 +1,38 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { Text } from 'react-native';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const Hashtag = React.memo(({
|
||||||
|
hashtag, channels, navToRoomInfo
|
||||||
|
}) => {
|
||||||
|
const handlePress = () => {
|
||||||
|
const index = channels.findIndex(channel => channel.name === hashtag);
|
||||||
|
const navParam = {
|
||||||
|
t: 'c',
|
||||||
|
rid: channels[index]._id
|
||||||
|
};
|
||||||
|
navToRoomInfo(navParam);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (channels && channels.length && channels.findIndex(channel => channel.name === hashtag) !== -1) {
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
style={styles.mention}
|
||||||
|
onPress={handlePress}
|
||||||
|
>
|
||||||
|
{`#${ hashtag }`}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return `#${ hashtag }`;
|
||||||
|
});
|
||||||
|
|
||||||
|
Hashtag.propTypes = {
|
||||||
|
hashtag: PropTypes.string,
|
||||||
|
navToRoomInfo: PropTypes.func,
|
||||||
|
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Hashtag;
|
|
@ -0,0 +1,36 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Text } from 'react-native';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
import openLink from '../../utils/openLink';
|
||||||
|
|
||||||
|
const Link = React.memo(({
|
||||||
|
children, link
|
||||||
|
}) => {
|
||||||
|
const handlePress = () => {
|
||||||
|
if (!link) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openLink(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
const childLength = React.Children.toArray(children).filter(o => o).length;
|
||||||
|
|
||||||
|
// if you have a [](https://rocket.chat) render https://rocket.chat
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
onPress={handlePress}
|
||||||
|
style={styles.link}
|
||||||
|
>
|
||||||
|
{ childLength !== 0 ? children : link }
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Link.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
link: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Link;
|
|
@ -0,0 +1,39 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const List = React.memo(({
|
||||||
|
children, ordered, start, tight
|
||||||
|
}) => {
|
||||||
|
let bulletWidth = 15;
|
||||||
|
|
||||||
|
if (ordered) {
|
||||||
|
const lastNumber = (start + children.length) - 1;
|
||||||
|
bulletWidth = (9 * lastNumber.toString().length) + 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _children = React.Children.map(children, (child, index) => React.cloneElement(child, {
|
||||||
|
bulletWidth,
|
||||||
|
ordered,
|
||||||
|
tight,
|
||||||
|
index: start + index
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{_children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
List.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
ordered: PropTypes.bool,
|
||||||
|
start: PropTypes.number,
|
||||||
|
tight: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
|
List.defaultProps = {
|
||||||
|
start: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
export default List;
|
|
@ -0,0 +1,60 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
View
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
const style = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'flex-start'
|
||||||
|
},
|
||||||
|
bullet: {
|
||||||
|
alignItems: 'flex-end',
|
||||||
|
marginRight: 5
|
||||||
|
},
|
||||||
|
contents: {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ListItem = React.memo(({
|
||||||
|
children, level, bulletWidth, continue: _continue, ordered, index
|
||||||
|
}) => {
|
||||||
|
let bullet;
|
||||||
|
if (_continue) {
|
||||||
|
bullet = '';
|
||||||
|
} else if (ordered) {
|
||||||
|
bullet = `${ index }.`;
|
||||||
|
} else if (level % 2 === 0) {
|
||||||
|
bullet = '◦';
|
||||||
|
} else {
|
||||||
|
bullet = '•';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={style.container}>
|
||||||
|
<View style={[{ width: bulletWidth }, style.bullet]}>
|
||||||
|
<Text>
|
||||||
|
{bullet}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={style.contents}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ListItem.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
bulletWidth: PropTypes.number,
|
||||||
|
level: PropTypes.number,
|
||||||
|
ordered: PropTypes.bool,
|
||||||
|
continue: PropTypes.bool,
|
||||||
|
index: PropTypes.number
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ListItem;
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { PropTypes } from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
ScrollView,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
Text
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
import { CELL_WIDTH } from './TableCell';
|
||||||
|
import styles from './styles';
|
||||||
|
import Navigation from '../../lib/Navigation';
|
||||||
|
import I18n from '../../i18n';
|
||||||
|
|
||||||
|
const MAX_HEIGHT = 300;
|
||||||
|
|
||||||
|
const Table = React.memo(({
|
||||||
|
children, numColumns
|
||||||
|
}) => {
|
||||||
|
const getTableWidth = () => numColumns * CELL_WIDTH;
|
||||||
|
|
||||||
|
const renderRows = (drawExtraBorders = true) => {
|
||||||
|
const tableStyle = [styles.table];
|
||||||
|
if (drawExtraBorders) {
|
||||||
|
tableStyle.push(styles.tableExtraBorders);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = React.Children.toArray(children);
|
||||||
|
rows[rows.length - 1] = React.cloneElement(rows[rows.length - 1], {
|
||||||
|
isLastRow: true
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={tableStyle}>
|
||||||
|
{rows}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPress = () => Navigation.navigate('TableView', { renderRows, tableWidth: getTableWidth() });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity onPress={onPress}>
|
||||||
|
<ScrollView
|
||||||
|
contentContainerStyle={{ width: getTableWidth() }}
|
||||||
|
scrollEnabled={false}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
style={[styles.containerTable, { maxWidth: getTableWidth(), maxHeight: MAX_HEIGHT }]}
|
||||||
|
>
|
||||||
|
{renderRows(false)}
|
||||||
|
</ScrollView>
|
||||||
|
<Text style={styles.textInfo}>{I18n.t('Full_table')}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Table.propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
numColumns: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Table;
|
|
@ -0,0 +1,39 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { Text, View } from 'react-native';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
export const CELL_WIDTH = 100;
|
||||||
|
|
||||||
|
const TableCell = React.memo(({
|
||||||
|
isLastCell, align, children
|
||||||
|
}) => {
|
||||||
|
const cellStyle = [styles.cell];
|
||||||
|
if (!isLastCell) {
|
||||||
|
cellStyle.push(styles.cellRightBorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
let textStyle = null;
|
||||||
|
if (align === 'center') {
|
||||||
|
textStyle = styles.alignCenter;
|
||||||
|
} else if (align === 'right') {
|
||||||
|
textStyle = styles.alignRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={[...cellStyle, { width: CELL_WIDTH }]}>
|
||||||
|
<Text style={textStyle}>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
TableCell.propTypes = {
|
||||||
|
align: PropTypes.oneOf(['', 'left', 'center', 'right']),
|
||||||
|
children: PropTypes.node,
|
||||||
|
isLastCell: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableCell;
|
|
@ -0,0 +1,28 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const TableRow = React.memo(({
|
||||||
|
isLastRow, children: _children
|
||||||
|
}) => {
|
||||||
|
const rowStyle = [styles.row];
|
||||||
|
if (!isLastRow) {
|
||||||
|
rowStyle.push(styles.rowBottomBorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
const children = React.Children.toArray(_children);
|
||||||
|
children[children.length - 1] = React.cloneElement(children[children.length - 1], {
|
||||||
|
isLastCell: true
|
||||||
|
});
|
||||||
|
|
||||||
|
return <View style={rowStyle}>{children}</View>;
|
||||||
|
});
|
||||||
|
|
||||||
|
TableRow.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
isLastRow: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableRow;
|
|
@ -0,0 +1,295 @@
|
||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import { View, Text, Image } from 'react-native';
|
||||||
|
import { Parser, Node } from 'commonmark';
|
||||||
|
import Renderer from 'commonmark-react-renderer';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import I18n from '../../i18n';
|
||||||
|
|
||||||
|
import MarkdownLink from './Link';
|
||||||
|
import MarkdownList from './List';
|
||||||
|
import MarkdownListItem from './ListItem';
|
||||||
|
import MarkdownAtMention from './AtMention';
|
||||||
|
import MarkdownHashtag from './Hashtag';
|
||||||
|
import MarkdownBlockQuote from './BlockQuote';
|
||||||
|
import MarkdownEmoji from './Emoji';
|
||||||
|
import MarkdownTable from './Table';
|
||||||
|
import MarkdownTableRow from './TableRow';
|
||||||
|
import MarkdownTableCell from './TableCell';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
// Support <http://link|Text>
|
||||||
|
const formatText = text => text.replace(
|
||||||
|
new RegExp('(?:<|<)((?:https|http):\\/\\/[^\\|]+)\\|(.+?)(?=>|>)(?:>|>)', 'gm'),
|
||||||
|
(match, url, title) => `[${ title }](${ url })`
|
||||||
|
);
|
||||||
|
|
||||||
|
const emojiRanges = [
|
||||||
|
'\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]', // unicode emoji from https://www.regextester.com/106421
|
||||||
|
':.{1,40}:', // custom emoji
|
||||||
|
' |\n' // allow spaces and line breaks
|
||||||
|
].join('|');
|
||||||
|
|
||||||
|
const removeAllEmoji = str => str.replace(new RegExp(emojiRanges, 'g'), '');
|
||||||
|
|
||||||
|
const isOnlyEmoji = str => !removeAllEmoji(str).length;
|
||||||
|
|
||||||
|
const removeOneEmoji = str => str.replace(new RegExp(emojiRanges), '');
|
||||||
|
|
||||||
|
const emojiCount = (str) => {
|
||||||
|
let oldLength = 0;
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
while (oldLength !== str.length) {
|
||||||
|
oldLength = str.length;
|
||||||
|
str = removeOneEmoji(str);
|
||||||
|
if (oldLength !== str.length) {
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Markdown extends PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
msg: PropTypes.string,
|
||||||
|
getCustomEmoji: PropTypes.func,
|
||||||
|
baseUrl: PropTypes.string,
|
||||||
|
username: PropTypes.string,
|
||||||
|
tmid: PropTypes.string,
|
||||||
|
isEdited: PropTypes.bool,
|
||||||
|
numberOfLines: PropTypes.number,
|
||||||
|
useMarkdown: PropTypes.bool,
|
||||||
|
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||||
|
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||||
|
navToRoomInfo: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.parser = this.createParser();
|
||||||
|
this.renderer = this.createRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
createParser = () => new Parser();
|
||||||
|
|
||||||
|
createRenderer = () => new Renderer({
|
||||||
|
renderers: {
|
||||||
|
text: this.renderText,
|
||||||
|
|
||||||
|
emph: Renderer.forwardChildren,
|
||||||
|
strong: Renderer.forwardChildren,
|
||||||
|
del: Renderer.forwardChildren,
|
||||||
|
code: this.renderCodeInline,
|
||||||
|
link: this.renderLink,
|
||||||
|
image: this.renderImage,
|
||||||
|
atMention: this.renderAtMention,
|
||||||
|
emoji: this.renderEmoji,
|
||||||
|
hashtag: this.renderHashtag,
|
||||||
|
|
||||||
|
paragraph: this.renderParagraph,
|
||||||
|
heading: this.renderHeading,
|
||||||
|
codeBlock: this.renderCodeBlock,
|
||||||
|
blockQuote: this.renderBlockQuote,
|
||||||
|
|
||||||
|
list: this.renderList,
|
||||||
|
item: this.renderListItem,
|
||||||
|
|
||||||
|
hardBreak: this.renderBreak,
|
||||||
|
thematicBreak: this.renderBreak,
|
||||||
|
softBreak: this.renderBreak,
|
||||||
|
|
||||||
|
htmlBlock: this.renderText,
|
||||||
|
htmlInline: this.renderText,
|
||||||
|
|
||||||
|
table: this.renderTable,
|
||||||
|
table_row: this.renderTableRow,
|
||||||
|
table_cell: this.renderTableCell,
|
||||||
|
|
||||||
|
editedIndicator: this.renderEditedIndicator
|
||||||
|
},
|
||||||
|
renderParagraphsInLists: true
|
||||||
|
});
|
||||||
|
|
||||||
|
editedMessage = (ast) => {
|
||||||
|
const { isEdited } = this.props;
|
||||||
|
if (isEdited) {
|
||||||
|
const editIndicatorNode = new Node('edited_indicator');
|
||||||
|
if (ast.lastChild && ['heading', 'paragraph'].includes(ast.lastChild.type)) {
|
||||||
|
ast.lastChild.appendChild(editIndicatorNode);
|
||||||
|
} else {
|
||||||
|
const node = new Node('paragraph');
|
||||||
|
node.appendChild(editIndicatorNode);
|
||||||
|
|
||||||
|
ast.appendChild(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderText = ({ context, literal }) => {
|
||||||
|
const { numberOfLines } = this.props;
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
this.isMessageContainsOnlyEmoji ? styles.textBig : styles.text,
|
||||||
|
...context.map(type => styles[type])
|
||||||
|
]}
|
||||||
|
numberOfLines={numberOfLines}
|
||||||
|
>
|
||||||
|
{literal}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCodeInline = ({ literal }) => <Text style={styles.codeInline}>{literal}</Text>;
|
||||||
|
|
||||||
|
renderCodeBlock = ({ literal }) => <Text style={styles.codeBlock}>{literal}</Text>;
|
||||||
|
|
||||||
|
renderBreak = () => {
|
||||||
|
const { tmid } = this.props;
|
||||||
|
return <Text>{tmid ? ' ' : '\n'}</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderParagraph = ({ children }) => {
|
||||||
|
const { numberOfLines } = this.props;
|
||||||
|
|
||||||
|
if (!children || children.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<View style={styles.block}>
|
||||||
|
<Text numberOfLines={numberOfLines}>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderLink = ({ children, href }) => (
|
||||||
|
<MarkdownLink link={href}>
|
||||||
|
{children}
|
||||||
|
</MarkdownLink>
|
||||||
|
);
|
||||||
|
|
||||||
|
renderHashtag = ({ hashtag }) => {
|
||||||
|
const { channels, navToRoomInfo } = this.props;
|
||||||
|
return (
|
||||||
|
<MarkdownHashtag
|
||||||
|
hashtag={hashtag}
|
||||||
|
channels={channels}
|
||||||
|
navToRoomInfo={navToRoomInfo}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAtMention = ({ mentionName }) => {
|
||||||
|
const { username, mentions, navToRoomInfo } = this.props;
|
||||||
|
return (
|
||||||
|
<MarkdownAtMention
|
||||||
|
mentions={mentions}
|
||||||
|
mention={mentionName}
|
||||||
|
username={username}
|
||||||
|
navToRoomInfo={navToRoomInfo}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEmoji = ({ emojiName, literal }) => {
|
||||||
|
const { getCustomEmoji, baseUrl } = this.props;
|
||||||
|
return (
|
||||||
|
<MarkdownEmoji
|
||||||
|
emojiName={emojiName}
|
||||||
|
literal={literal}
|
||||||
|
isMessageContainsOnlyEmoji={this.isMessageContainsOnlyEmoji}
|
||||||
|
getCustomEmoji={getCustomEmoji}
|
||||||
|
baseUrl={baseUrl}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderImage = ({ src }) => <Image style={styles.inlineImage} source={{ uri: src }} />;
|
||||||
|
|
||||||
|
renderEditedIndicator = () => <Text style={styles.edited}> ({I18n.t('edited')})</Text>;
|
||||||
|
|
||||||
|
renderHeading = ({ children, level }) => {
|
||||||
|
const textStyle = styles[`heading${ level }Text`];
|
||||||
|
return (
|
||||||
|
<Text style={textStyle}>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderList = ({
|
||||||
|
children, start, tight, type
|
||||||
|
}) => (
|
||||||
|
<MarkdownList
|
||||||
|
ordered={type !== 'bullet'}
|
||||||
|
start={start}
|
||||||
|
tight={tight}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</MarkdownList>
|
||||||
|
);
|
||||||
|
|
||||||
|
renderListItem = ({
|
||||||
|
children, context, ...otherProps
|
||||||
|
}) => {
|
||||||
|
const level = context.filter(type => type === 'list').length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MarkdownListItem
|
||||||
|
level={level}
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</MarkdownListItem>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderBlockQuote = ({ children }) => (
|
||||||
|
<MarkdownBlockQuote>
|
||||||
|
{children}
|
||||||
|
</MarkdownBlockQuote>
|
||||||
|
);
|
||||||
|
|
||||||
|
renderTable = ({ children, numColumns }) => (
|
||||||
|
<MarkdownTable numColumns={numColumns}>
|
||||||
|
{children}
|
||||||
|
</MarkdownTable>
|
||||||
|
);
|
||||||
|
|
||||||
|
renderTableRow = args => <MarkdownTableRow {...args} />;
|
||||||
|
|
||||||
|
renderTableCell = args => <MarkdownTableCell {...args} />;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
msg, useMarkdown = true, numberOfLines
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (!msg) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let m = formatText(msg);
|
||||||
|
|
||||||
|
// Ex: '[ ](https://open.rocket.chat/group/test?msg=abcdef) Test'
|
||||||
|
// Return: 'Test'
|
||||||
|
m = m.replace(/^\[([\s]]*)\]\(([^)]*)\)\s/, '').trim();
|
||||||
|
|
||||||
|
if (!useMarkdown) {
|
||||||
|
return <Text style={styles.text} numberOfLines={numberOfLines}>{m}</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ast = this.parser.parse(m);
|
||||||
|
this.isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3;
|
||||||
|
|
||||||
|
this.editedMessage(ast);
|
||||||
|
|
||||||
|
return this.renderer.render(ast);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
import { StyleSheet, Platform } from 'react-native';
|
||||||
|
|
||||||
|
import sharedStyles from '../../views/Styles';
|
||||||
|
import {
|
||||||
|
COLOR_BORDER, COLOR_PRIMARY, COLOR_WHITE, COLOR_BACKGROUND_CONTAINER
|
||||||
|
} from '../../constants/colors';
|
||||||
|
|
||||||
|
const codeFontFamily = Platform.select({
|
||||||
|
ios: { fontFamily: 'Courier New' },
|
||||||
|
android: { fontFamily: 'monospace' }
|
||||||
|
});
|
||||||
|
|
||||||
|
export default StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
childContainer: {
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
block: {
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap'
|
||||||
|
},
|
||||||
|
emph: {
|
||||||
|
fontStyle: 'italic'
|
||||||
|
},
|
||||||
|
strong: {
|
||||||
|
fontWeight: 'bold'
|
||||||
|
},
|
||||||
|
del: {
|
||||||
|
textDecorationLine: 'line-through'
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 16,
|
||||||
|
...sharedStyles.textColorNormal,
|
||||||
|
...sharedStyles.textRegular
|
||||||
|
},
|
||||||
|
textInfo: {
|
||||||
|
fontStyle: 'italic',
|
||||||
|
fontSize: 16,
|
||||||
|
...sharedStyles.textColorDescription,
|
||||||
|
...sharedStyles.textRegular
|
||||||
|
},
|
||||||
|
textBig: {
|
||||||
|
fontSize: 30,
|
||||||
|
...sharedStyles.textColorNormal,
|
||||||
|
...sharedStyles.textRegular
|
||||||
|
},
|
||||||
|
customEmoji: {
|
||||||
|
width: 20,
|
||||||
|
height: 20
|
||||||
|
},
|
||||||
|
customEmojiBig: {
|
||||||
|
width: 30,
|
||||||
|
height: 30
|
||||||
|
},
|
||||||
|
temp: { opacity: 0.3 },
|
||||||
|
mention: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#0072FE',
|
||||||
|
padding: 5,
|
||||||
|
...sharedStyles.textMedium,
|
||||||
|
backgroundColor: '#E8F2FF'
|
||||||
|
},
|
||||||
|
mentionLoggedUser: {
|
||||||
|
color: COLOR_WHITE,
|
||||||
|
backgroundColor: COLOR_PRIMARY
|
||||||
|
},
|
||||||
|
mentionAll: {
|
||||||
|
color: COLOR_WHITE,
|
||||||
|
backgroundColor: '#FF5B5A'
|
||||||
|
},
|
||||||
|
paragraph: {
|
||||||
|
marginTop: 0,
|
||||||
|
marginBottom: 0,
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
justifyContent: 'flex-start'
|
||||||
|
},
|
||||||
|
inlineImage: {
|
||||||
|
width: 300,
|
||||||
|
height: 300,
|
||||||
|
resizeMode: 'contain'
|
||||||
|
},
|
||||||
|
codeInline: {
|
||||||
|
...sharedStyles.textRegular,
|
||||||
|
...codeFontFamily,
|
||||||
|
borderWidth: 1,
|
||||||
|
backgroundColor: COLOR_BACKGROUND_CONTAINER,
|
||||||
|
borderRadius: 4
|
||||||
|
},
|
||||||
|
codeBlock: {
|
||||||
|
...sharedStyles.textRegular,
|
||||||
|
...codeFontFamily,
|
||||||
|
backgroundColor: COLOR_BACKGROUND_CONTAINER,
|
||||||
|
borderColor: COLOR_BORDER,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 4,
|
||||||
|
padding: 4
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: COLOR_PRIMARY,
|
||||||
|
...sharedStyles.textRegular
|
||||||
|
},
|
||||||
|
edited: {
|
||||||
|
fontSize: 14,
|
||||||
|
...sharedStyles.textColorDescription,
|
||||||
|
...sharedStyles.textRegular
|
||||||
|
},
|
||||||
|
heading1: {
|
||||||
|
...sharedStyles.textBold,
|
||||||
|
fontSize: 24
|
||||||
|
},
|
||||||
|
heading2: {
|
||||||
|
...sharedStyles.textBold,
|
||||||
|
fontSize: 22
|
||||||
|
},
|
||||||
|
heading3: {
|
||||||
|
...sharedStyles.textSemibold,
|
||||||
|
fontSize: 20
|
||||||
|
},
|
||||||
|
heading4: {
|
||||||
|
...sharedStyles.textSemibold,
|
||||||
|
fontSize: 18
|
||||||
|
},
|
||||||
|
heading5: {
|
||||||
|
...sharedStyles.textMedium,
|
||||||
|
fontSize: 16
|
||||||
|
},
|
||||||
|
heading6: {
|
||||||
|
...sharedStyles.textMedium,
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
quote: {
|
||||||
|
height: '100%',
|
||||||
|
width: 2,
|
||||||
|
backgroundColor: COLOR_BORDER,
|
||||||
|
marginRight: 5
|
||||||
|
},
|
||||||
|
touchableTable: {
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
containerTable: {
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderColor: COLOR_BORDER,
|
||||||
|
borderRightWidth: 1
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
borderColor: COLOR_BORDER,
|
||||||
|
borderLeftWidth: 1,
|
||||||
|
borderTopWidth: 1
|
||||||
|
},
|
||||||
|
tableExtraBorders: {
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderRightWidth: 1
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
rowBottomBorder: {
|
||||||
|
borderColor: COLOR_BORDER,
|
||||||
|
borderBottomWidth: 1
|
||||||
|
},
|
||||||
|
cell: {
|
||||||
|
borderColor: COLOR_BORDER,
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
paddingHorizontal: 13,
|
||||||
|
paddingVertical: 6
|
||||||
|
},
|
||||||
|
cellRightBorder: {
|
||||||
|
borderRightWidth: 1
|
||||||
|
},
|
||||||
|
alignCenter: {
|
||||||
|
textAlign: 'center'
|
||||||
|
},
|
||||||
|
alignRight: {
|
||||||
|
textAlign: 'right'
|
||||||
|
}
|
||||||
|
});
|
|
@ -9,7 +9,7 @@ import moment from 'moment';
|
||||||
import equal from 'deep-equal';
|
import equal from 'deep-equal';
|
||||||
import Touchable from 'react-native-platform-touchable';
|
import Touchable from 'react-native-platform-touchable';
|
||||||
|
|
||||||
import Markdown from './Markdown';
|
import Markdown from '../markdown';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import sharedStyles from '../../views/Styles';
|
import sharedStyles from '../../views/Styles';
|
||||||
import { COLOR_BACKGROUND_CONTAINER, COLOR_BORDER, COLOR_PRIMARY } from '../../constants/colors';
|
import { COLOR_BACKGROUND_CONTAINER, COLOR_BORDER, COLOR_PRIMARY } from '../../constants/colors';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import Markdown from './Markdown';
|
import Markdown from '../markdown';
|
||||||
import { getInfoMessage } from './utils';
|
import { getInfoMessage } from './utils';
|
||||||
|
|
||||||
const Content = React.memo((props) => {
|
const Content = React.memo((props) => {
|
||||||
|
@ -21,14 +21,15 @@ const Content = React.memo((props) => {
|
||||||
<Markdown
|
<Markdown
|
||||||
msg={props.msg}
|
msg={props.msg}
|
||||||
baseUrl={props.baseUrl}
|
baseUrl={props.baseUrl}
|
||||||
|
getCustomEmoji={props.getCustomEmoji}
|
||||||
username={props.user.username}
|
username={props.user.username}
|
||||||
isEdited={props.isEdited}
|
isEdited={props.isEdited}
|
||||||
mentions={props.mentions}
|
|
||||||
channels={props.channels}
|
|
||||||
numberOfLines={props.tmid ? 1 : 0}
|
numberOfLines={props.tmid ? 1 : 0}
|
||||||
getCustomEmoji={props.getCustomEmoji}
|
channels={props.channels}
|
||||||
|
mentions={props.mentions}
|
||||||
useMarkdown={props.useMarkdown}
|
useMarkdown={props.useMarkdown}
|
||||||
navToRoomInfo={props.navToRoomInfo}
|
navToRoomInfo={props.navToRoomInfo}
|
||||||
|
tmid={props.tmid}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -43,16 +44,16 @@ const Content = React.memo((props) => {
|
||||||
Content.propTypes = {
|
Content.propTypes = {
|
||||||
isTemp: PropTypes.bool,
|
isTemp: PropTypes.bool,
|
||||||
isInfo: PropTypes.bool,
|
isInfo: PropTypes.bool,
|
||||||
isEdited: PropTypes.bool,
|
|
||||||
useMarkdown: PropTypes.bool,
|
|
||||||
tmid: PropTypes.string,
|
tmid: PropTypes.string,
|
||||||
msg: PropTypes.string,
|
msg: PropTypes.string,
|
||||||
|
isEdited: PropTypes.bool,
|
||||||
|
useMarkdown: PropTypes.bool,
|
||||||
baseUrl: PropTypes.string,
|
baseUrl: PropTypes.string,
|
||||||
user: PropTypes.object,
|
user: PropTypes.object,
|
||||||
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
getCustomEmoji: PropTypes.func,
|
||||||
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||||
navToRoomInfo: PropTypes.func,
|
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||||
getCustomEmoji: PropTypes.func
|
navToRoomInfo: PropTypes.func
|
||||||
};
|
};
|
||||||
Content.displayName = 'MessageContent';
|
Content.displayName = 'MessageContent';
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import FastImage from 'react-native-fast-image';
|
||||||
import equal from 'deep-equal';
|
import equal from 'deep-equal';
|
||||||
import Touchable from 'react-native-platform-touchable';
|
import Touchable from 'react-native-platform-touchable';
|
||||||
|
|
||||||
import Markdown from './Markdown';
|
import Markdown from '../markdown';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { formatAttachmentUrl } from '../../lib/utils';
|
import { formatAttachmentUrl } from '../../lib/utils';
|
||||||
|
|
||||||
|
|
|
@ -1,187 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { Text, Image } from 'react-native';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { emojify } from 'react-emojione';
|
|
||||||
import MarkdownRenderer, { PluginContainer } from 'react-native-markdown-renderer';
|
|
||||||
import MarkdownFlowdock from 'markdown-it-flowdock';
|
|
||||||
|
|
||||||
import styles from './styles';
|
|
||||||
import CustomEmoji from '../EmojiPicker/CustomEmoji';
|
|
||||||
import MarkdownEmojiPlugin from './MarkdownEmojiPlugin';
|
|
||||||
import I18n from '../../i18n';
|
|
||||||
|
|
||||||
const EmojiPlugin = new PluginContainer(MarkdownEmojiPlugin);
|
|
||||||
const MentionsPlugin = new PluginContainer(MarkdownFlowdock);
|
|
||||||
const plugins = [EmojiPlugin, MentionsPlugin];
|
|
||||||
|
|
||||||
// Support <http://link|Text>
|
|
||||||
const formatText = text => text.replace(
|
|
||||||
new RegExp('(?:<|<)((?:https|http):\\/\\/[^\\|]+)\\|(.+?)(?=>|>)(?:>|>)', 'gm'),
|
|
||||||
(match, url, title) => `[${ title }](${ url })`
|
|
||||||
);
|
|
||||||
|
|
||||||
const emojiRanges = [
|
|
||||||
'\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]', // unicode emoji from https://www.regextester.com/106421
|
|
||||||
':.{1,40}:', // custom emoji
|
|
||||||
' |\n' // allow spaces and line breaks
|
|
||||||
].join('|');
|
|
||||||
|
|
||||||
const removeAllEmoji = str => str.replace(new RegExp(emojiRanges, 'g'), '');
|
|
||||||
|
|
||||||
const isOnlyEmoji = str => !removeAllEmoji(str).length;
|
|
||||||
|
|
||||||
const removeOneEmoji = str => str.replace(new RegExp(emojiRanges), '');
|
|
||||||
|
|
||||||
const emojiCount = (str) => {
|
|
||||||
let oldLength = 0;
|
|
||||||
let counter = 0;
|
|
||||||
|
|
||||||
while (oldLength !== str.length) {
|
|
||||||
oldLength = str.length;
|
|
||||||
str = removeOneEmoji(str);
|
|
||||||
if (oldLength !== str.length) {
|
|
||||||
counter += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return counter;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Markdown = React.memo(({
|
|
||||||
msg, style, rules, baseUrl, username, isEdited, numberOfLines, mentions, channels, getCustomEmoji, useMarkdown = true, navToRoomInfo
|
|
||||||
}) => {
|
|
||||||
if (!msg) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let m = formatText(msg);
|
|
||||||
if (m) {
|
|
||||||
m = emojify(m, { output: 'unicode' });
|
|
||||||
}
|
|
||||||
m = m.replace(/^\[([^\]]*)\]\(([^)]*)\)\s/, '').trim();
|
|
||||||
if (numberOfLines > 0) {
|
|
||||||
m = m.replace(/[\n]+/g, '\n').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!useMarkdown) {
|
|
||||||
return <Text style={styles.text} numberOfLines={numberOfLines}>{m}</Text>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MarkdownRenderer
|
|
||||||
rules={{
|
|
||||||
paragraph: (node, children) => (
|
|
||||||
<Text key={node.key} style={styles.paragraph} numberOfLines={numberOfLines}>
|
|
||||||
{children}
|
|
||||||
{isEdited ? <Text style={styles.edited}> ({I18n.t('edited')})</Text> : null}
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
mention: (node) => {
|
|
||||||
const { content, key } = node;
|
|
||||||
let mentionStyle = styles.mention;
|
|
||||||
if (content === 'all' || content === 'here') {
|
|
||||||
mentionStyle = {
|
|
||||||
...mentionStyle,
|
|
||||||
...styles.mentionAll
|
|
||||||
};
|
|
||||||
} else if (content === username) {
|
|
||||||
mentionStyle = {
|
|
||||||
...mentionStyle,
|
|
||||||
...styles.mentionLoggedUser
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (mentions && mentions.length && mentions.findIndex(mention => mention.username === content) !== -1) {
|
|
||||||
const index = mentions.findIndex(mention => mention.username === content);
|
|
||||||
const navParam = {
|
|
||||||
t: 'd',
|
|
||||||
rid: mentions[index]._id
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Text
|
|
||||||
style={mentionStyle}
|
|
||||||
key={key}
|
|
||||||
onPress={() => navToRoomInfo(navParam)}
|
|
||||||
>
|
|
||||||
{content}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return `@${ content }`;
|
|
||||||
},
|
|
||||||
hashtag: (node) => {
|
|
||||||
const { content, key } = node;
|
|
||||||
if (channels && channels.length && channels.findIndex(channel => channel.name === content) !== -1) {
|
|
||||||
const index = channels.findIndex(channel => channel.name === content);
|
|
||||||
const navParam = {
|
|
||||||
t: 'c',
|
|
||||||
rid: channels[index]._id
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Text
|
|
||||||
key={key}
|
|
||||||
style={styles.mention}
|
|
||||||
onPress={() => navToRoomInfo(navParam)}
|
|
||||||
>
|
|
||||||
#{content}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return `#${ content }`;
|
|
||||||
},
|
|
||||||
emoji: (node) => {
|
|
||||||
if (node.children && node.children.length && node.children[0].content) {
|
|
||||||
const { content } = node.children[0];
|
|
||||||
const emoji = getCustomEmoji && getCustomEmoji(content);
|
|
||||||
if (emoji) {
|
|
||||||
return (
|
|
||||||
<CustomEmoji
|
|
||||||
key={node.key}
|
|
||||||
baseUrl={baseUrl}
|
|
||||||
style={isMessageContainsOnlyEmoji ? styles.customEmojiBig : styles.customEmoji}
|
|
||||||
emoji={emoji}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <Text key={node.key}>:{content}:</Text>;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
hardbreak: () => null,
|
|
||||||
blocklink: () => null,
|
|
||||||
image: node => (
|
|
||||||
<Image key={node.key} style={styles.inlineImage} source={{ uri: node.attributes.src }} />
|
|
||||||
),
|
|
||||||
...rules
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
paragraph: styles.paragraph,
|
|
||||||
text: isMessageContainsOnlyEmoji ? styles.textBig : styles.text,
|
|
||||||
codeInline: styles.codeInline,
|
|
||||||
codeBlock: styles.codeBlock,
|
|
||||||
link: styles.link,
|
|
||||||
...style
|
|
||||||
}}
|
|
||||||
plugins={plugins}
|
|
||||||
>{m}
|
|
||||||
</MarkdownRenderer>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Markdown.propTypes = {
|
|
||||||
msg: PropTypes.string,
|
|
||||||
username: PropTypes.string,
|
|
||||||
baseUrl: PropTypes.string,
|
|
||||||
style: PropTypes.any,
|
|
||||||
rules: PropTypes.object,
|
|
||||||
isEdited: PropTypes.bool,
|
|
||||||
numberOfLines: PropTypes.number,
|
|
||||||
useMarkdown: PropTypes.bool,
|
|
||||||
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
|
||||||
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
|
||||||
getCustomEmoji: PropTypes.func,
|
|
||||||
navToRoomInfo: PropTypes.func
|
|
||||||
};
|
|
||||||
Markdown.displayName = 'MessageMarkdown';
|
|
||||||
|
|
||||||
export default Markdown;
|
|
|
@ -1,78 +0,0 @@
|
||||||
export default function(md) {
|
|
||||||
function tokenize(state, silent) {
|
|
||||||
let token;
|
|
||||||
const start = state.pos;
|
|
||||||
const marker = state.src.charCodeAt(start);
|
|
||||||
|
|
||||||
if (silent) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// :
|
|
||||||
if (marker !== 58) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const scanned = state.scanDelims(state.pos, true);
|
|
||||||
const len = scanned.length;
|
|
||||||
const ch = String.fromCharCode(marker);
|
|
||||||
|
|
||||||
for (let i = 0; i < len; i += 1) {
|
|
||||||
token = state.push('text', '', 0);
|
|
||||||
token.content = ch;
|
|
||||||
|
|
||||||
state.delimiters.push({
|
|
||||||
marker,
|
|
||||||
jump: i,
|
|
||||||
token: state.tokens.length - 1,
|
|
||||||
level: state.level,
|
|
||||||
end: -1,
|
|
||||||
open: scanned.can_open,
|
|
||||||
close: scanned.can_close
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
state.pos += scanned.length;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function postProcess(state) {
|
|
||||||
let startDelim;
|
|
||||||
let endDelim;
|
|
||||||
let token;
|
|
||||||
const { delimiters } = state;
|
|
||||||
const max = delimiters.length;
|
|
||||||
|
|
||||||
for (let i = 0; i < max; i += 1) {
|
|
||||||
startDelim = delimiters[i];
|
|
||||||
|
|
||||||
// :
|
|
||||||
if (startDelim.marker !== 58) {
|
|
||||||
continue; // eslint-disable-line
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startDelim.end === -1) {
|
|
||||||
continue; // eslint-disable-line
|
|
||||||
}
|
|
||||||
|
|
||||||
endDelim = delimiters[startDelim.end];
|
|
||||||
|
|
||||||
token = state.tokens[startDelim.token];
|
|
||||||
token.type = 'emoji_open';
|
|
||||||
token.tag = 'emoji';
|
|
||||||
token.nesting = 1;
|
|
||||||
token.markup = ':';
|
|
||||||
token.content = '';
|
|
||||||
|
|
||||||
token = state.tokens[endDelim.token];
|
|
||||||
token.type = 'emoji_close';
|
|
||||||
token.tag = 'emoji';
|
|
||||||
token.nesting = -1;
|
|
||||||
token.markup = ':';
|
|
||||||
token.content = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
md.inline.ruler.before('emphasis', 'emoji', tokenize);
|
|
||||||
md.inline.ruler2.before('emphasis', 'emoji', postProcess);
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ import moment from 'moment';
|
||||||
import Touchable from 'react-native-platform-touchable';
|
import Touchable from 'react-native-platform-touchable';
|
||||||
import isEqual from 'deep-equal';
|
import isEqual from 'deep-equal';
|
||||||
|
|
||||||
import Markdown from './Markdown';
|
import Markdown from '../markdown';
|
||||||
import openLink from '../../utils/openLink';
|
import openLink from '../../utils/openLink';
|
||||||
import sharedStyles from '../../views/Styles';
|
import sharedStyles from '../../views/Styles';
|
||||||
import { COLOR_BACKGROUND_CONTAINER, COLOR_BORDER } from '../../constants/colors';
|
import { COLOR_BACKGROUND_CONTAINER, COLOR_BORDER } from '../../constants/colors';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { StyleSheet } from 'react-native';
|
||||||
import Touchable from 'react-native-platform-touchable';
|
import Touchable from 'react-native-platform-touchable';
|
||||||
import isEqual from 'deep-equal';
|
import isEqual from 'deep-equal';
|
||||||
|
|
||||||
import Markdown from './Markdown';
|
import Markdown from '../markdown';
|
||||||
import openLink from '../../utils/openLink';
|
import openLink from '../../utils/openLink';
|
||||||
import { isIOS } from '../../utils/deviceInfo';
|
import { isIOS } from '../../utils/deviceInfo';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
import { StyleSheet, Platform } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
import sharedStyles from '../../views/Styles';
|
import sharedStyles from '../../views/Styles';
|
||||||
import {
|
import {
|
||||||
COLOR_BORDER, COLOR_PRIMARY, COLOR_WHITE, COLOR_BACKGROUND_CONTAINER
|
COLOR_BORDER, COLOR_PRIMARY, COLOR_WHITE
|
||||||
} from '../../constants/colors';
|
} from '../../constants/colors';
|
||||||
|
|
||||||
const codeFontFamily = Platform.select({
|
|
||||||
ios: { fontFamily: 'Courier New' },
|
|
||||||
android: { fontFamily: 'monospace' }
|
|
||||||
});
|
|
||||||
|
|
||||||
export default StyleSheet.create({
|
export default StyleSheet.create({
|
||||||
root: {
|
root: {
|
||||||
flexDirection: 'row'
|
flexDirection: 'row'
|
||||||
|
@ -34,30 +29,6 @@ export default StyleSheet.create({
|
||||||
flexDirection: 'row'
|
flexDirection: 'row'
|
||||||
// flex: 1
|
// flex: 1
|
||||||
},
|
},
|
||||||
text: {
|
|
||||||
fontSize: 16,
|
|
||||||
...sharedStyles.textColorNormal,
|
|
||||||
...sharedStyles.textRegular
|
|
||||||
},
|
|
||||||
textBig: {
|
|
||||||
fontSize: 30,
|
|
||||||
...sharedStyles.textColorNormal,
|
|
||||||
...sharedStyles.textRegular
|
|
||||||
},
|
|
||||||
textInfo: {
|
|
||||||
fontStyle: 'italic',
|
|
||||||
fontSize: 16,
|
|
||||||
...sharedStyles.textColorDescription,
|
|
||||||
...sharedStyles.textRegular
|
|
||||||
},
|
|
||||||
customEmoji: {
|
|
||||||
width: 20,
|
|
||||||
height: 20
|
|
||||||
},
|
|
||||||
customEmojiBig: {
|
|
||||||
width: 30,
|
|
||||||
height: 30
|
|
||||||
},
|
|
||||||
temp: { opacity: 0.3 },
|
temp: { opacity: 0.3 },
|
||||||
marginTop: {
|
marginTop: {
|
||||||
marginTop: 6
|
marginTop: 6
|
||||||
|
@ -143,28 +114,6 @@ export default StyleSheet.create({
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
...sharedStyles.textMedium
|
...sharedStyles.textMedium
|
||||||
},
|
},
|
||||||
mention: {
|
|
||||||
...sharedStyles.textMedium,
|
|
||||||
color: '#0072FE',
|
|
||||||
padding: 5,
|
|
||||||
backgroundColor: '#E8F2FF'
|
|
||||||
},
|
|
||||||
mentionLoggedUser: {
|
|
||||||
color: COLOR_WHITE,
|
|
||||||
backgroundColor: COLOR_PRIMARY
|
|
||||||
},
|
|
||||||
mentionAll: {
|
|
||||||
color: COLOR_WHITE,
|
|
||||||
backgroundColor: '#FF5B5A'
|
|
||||||
},
|
|
||||||
paragraph: {
|
|
||||||
marginTop: 0,
|
|
||||||
marginBottom: 0,
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'flex-start',
|
|
||||||
justifyContent: 'flex-start'
|
|
||||||
},
|
|
||||||
imageContainer: {
|
imageContainer: {
|
||||||
// flex: 1,
|
// flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
@ -186,29 +135,15 @@ export default StyleSheet.create({
|
||||||
height: 300,
|
height: 300,
|
||||||
resizeMode: 'contain'
|
resizeMode: 'contain'
|
||||||
},
|
},
|
||||||
edited: {
|
text: {
|
||||||
fontSize: 14,
|
fontSize: 16,
|
||||||
...sharedStyles.textColorDescription,
|
...sharedStyles.textColorNormal,
|
||||||
...sharedStyles.textRegular
|
...sharedStyles.textRegular
|
||||||
},
|
},
|
||||||
codeInline: {
|
textInfo: {
|
||||||
...sharedStyles.textRegular,
|
fontStyle: 'italic',
|
||||||
...codeFontFamily,
|
fontSize: 16,
|
||||||
borderWidth: 1,
|
...sharedStyles.textColorDescription,
|
||||||
backgroundColor: COLOR_BACKGROUND_CONTAINER,
|
|
||||||
borderRadius: 4
|
|
||||||
},
|
|
||||||
codeBlock: {
|
|
||||||
...sharedStyles.textRegular,
|
|
||||||
...codeFontFamily,
|
|
||||||
backgroundColor: COLOR_BACKGROUND_CONTAINER,
|
|
||||||
borderColor: COLOR_BORDER,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderRadius: 4,
|
|
||||||
padding: 4
|
|
||||||
},
|
|
||||||
link: {
|
|
||||||
color: COLOR_PRIMARY,
|
|
||||||
...sharedStyles.textRegular
|
...sharedStyles.textRegular
|
||||||
},
|
},
|
||||||
startedDiscussion: {
|
startedDiscussion: {
|
||||||
|
|
|
@ -181,6 +181,7 @@ export default {
|
||||||
Forgot_password_If_this_email_is_registered: 'If this email is registered, we\'ll send instructions on how to reset your password. If you do not receive an email shortly, please come back and try again.',
|
Forgot_password_If_this_email_is_registered: 'If this email is registered, we\'ll send instructions on how to reset your password. If you do not receive an email shortly, please come back and try again.',
|
||||||
Forgot_password: 'Forgot password',
|
Forgot_password: 'Forgot password',
|
||||||
Forgot_Password: 'Forgot Password',
|
Forgot_Password: 'Forgot Password',
|
||||||
|
Full_table: 'Click to see full table',
|
||||||
Group_by_favorites: 'Group favorites',
|
Group_by_favorites: 'Group favorites',
|
||||||
Group_by_type: 'Group by type',
|
Group_by_type: 'Group by type',
|
||||||
Hide: 'Hide',
|
Hide: 'Hide',
|
||||||
|
@ -360,6 +361,7 @@ export default {
|
||||||
Start_of_conversation: 'Start of conversation',
|
Start_of_conversation: 'Start of conversation',
|
||||||
Started_discussion: 'Started a discussion:',
|
Started_discussion: 'Started a discussion:',
|
||||||
Submit: 'Submit',
|
Submit: 'Submit',
|
||||||
|
Table: 'Table',
|
||||||
Take_a_photo: 'Take a photo',
|
Take_a_photo: 'Take a photo',
|
||||||
Take_a_video: 'Take a video',
|
Take_a_video: 'Take a video',
|
||||||
tap_to_change_status: 'tap to change status',
|
tap_to_change_status: 'tap to change status',
|
||||||
|
|
|
@ -178,6 +178,7 @@ export default {
|
||||||
Forgot_password_If_this_email_is_registered: 'Se este e-mail estiver cadastrado, enviaremos instruções sobre como redefinir sua senha. Se você não receber um e-mail em breve, volte e tente novamente.',
|
Forgot_password_If_this_email_is_registered: 'Se este e-mail estiver cadastrado, enviaremos instruções sobre como redefinir sua senha. Se você não receber um e-mail em breve, volte e tente novamente.',
|
||||||
Forgot_password: 'Esqueci minha senha',
|
Forgot_password: 'Esqueci minha senha',
|
||||||
Forgot_Password: 'Esqueci minha senha',
|
Forgot_Password: 'Esqueci minha senha',
|
||||||
|
Full_table: 'Clique para ver a tabela completa',
|
||||||
Group_by_favorites: 'Agrupar favoritos',
|
Group_by_favorites: 'Agrupar favoritos',
|
||||||
Group_by_type: 'Agrupar por tipo',
|
Group_by_type: 'Agrupar por tipo',
|
||||||
Has_joined_the_channel: 'Entrou no canal',
|
Has_joined_the_channel: 'Entrou no canal',
|
||||||
|
@ -326,6 +327,7 @@ export default {
|
||||||
Start_of_conversation: 'Início da conversa',
|
Start_of_conversation: 'Início da conversa',
|
||||||
Started_discussion: 'Iniciou uma discussão:',
|
Started_discussion: 'Iniciou uma discussão:',
|
||||||
Submit: 'Enviar',
|
Submit: 'Enviar',
|
||||||
|
Table: 'Tabela',
|
||||||
Take_a_photo: 'Tirar uma foto',
|
Take_a_photo: 'Tirar uma foto',
|
||||||
Take_a_video: 'Gravar um vídeo',
|
Take_a_video: 'Gravar um vídeo',
|
||||||
Terms_of_Service: ' Termos de Serviço ',
|
Terms_of_Service: ' Termos de Serviço ',
|
||||||
|
|
|
@ -122,6 +122,9 @@ const ChatsStack = createStackNavigator({
|
||||||
DirectoryView: {
|
DirectoryView: {
|
||||||
getScreen: () => require('./views/DirectoryView').default
|
getScreen: () => require('./views/DirectoryView').default
|
||||||
},
|
},
|
||||||
|
TableView: {
|
||||||
|
getScreen: () => require('./views/TableView').default
|
||||||
|
},
|
||||||
NotificationPrefView: {
|
NotificationPrefView: {
|
||||||
getScreen: () => require('./views/NotificationPreferencesView').default
|
getScreen: () => require('./views/NotificationPreferencesView').default
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import equal from 'deep-equal';
|
||||||
import RCTextInput from '../../containers/TextInput';
|
import RCTextInput from '../../containers/TextInput';
|
||||||
import RCActivityIndicator from '../../containers/ActivityIndicator';
|
import RCActivityIndicator from '../../containers/ActivityIndicator';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import Markdown from '../../containers/message/Markdown';
|
import Markdown from '../../containers/markdown';
|
||||||
import debounce from '../../utils/debounce';
|
import debounce from '../../utils/debounce';
|
||||||
import RocketChat from '../../lib/rocketchat';
|
import RocketChat from '../../lib/rocketchat';
|
||||||
import Message from '../../containers/message/Message';
|
import Message from '../../containers/message/Message';
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { ScrollView } from 'react-native';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import I18n from '../i18n';
|
||||||
|
import { isIOS } from '../utils/deviceInfo';
|
||||||
|
|
||||||
|
export default class TableView extends React.Component {
|
||||||
|
static navigationOptions = () => ({
|
||||||
|
title: I18n.t('Table')
|
||||||
|
});
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
navigation: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
const renderRows = navigation.getParam('renderRows');
|
||||||
|
const tableWidth = navigation.getParam('tableWidth');
|
||||||
|
|
||||||
|
if (isIOS) {
|
||||||
|
return (
|
||||||
|
<ScrollView contentContainerStyle={{ width: tableWidth }}>
|
||||||
|
{renderRows()}
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView>
|
||||||
|
<ScrollView horizontal>
|
||||||
|
{renderRows()}
|
||||||
|
</ScrollView>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,8 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rocket.chat/sdk": "1.0.0-alpha.30",
|
"@rocket.chat/sdk": "1.0.0-alpha.30",
|
||||||
|
"commonmark": "git+https://github.com/RocketChat/commonmark.js.git",
|
||||||
|
"commonmark-react-renderer": "git+https://github.com/RocketChat/commonmark-react-renderer.git",
|
||||||
"bugsnag-react-native": "^2.22.3",
|
"bugsnag-react-native": "^2.22.3",
|
||||||
"deep-equal": "^1.0.1",
|
"deep-equal": "^1.0.1",
|
||||||
"ejson": "2.2.0",
|
"ejson": "2.2.0",
|
||||||
|
@ -34,7 +36,6 @@
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
"js-sha256": "^0.9.0",
|
"js-sha256": "^0.9.0",
|
||||||
"lodash": "4.17.15",
|
"lodash": "4.17.15",
|
||||||
"markdown-it-flowdock": "0.3.8",
|
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"prop-types": "15.7.2",
|
"prop-types": "15.7.2",
|
||||||
"react": "16.8.6",
|
"react": "16.8.6",
|
||||||
|
@ -56,7 +57,6 @@
|
||||||
"react-native-keyboard-input": "^5.3.1",
|
"react-native-keyboard-input": "^5.3.1",
|
||||||
"react-native-keyboard-tracking-view": "^5.5.0",
|
"react-native-keyboard-tracking-view": "^5.5.0",
|
||||||
"react-native-localize": "^1.1.4",
|
"react-native-localize": "^1.1.4",
|
||||||
"react-native-markdown-renderer": "^3.2.8",
|
|
||||||
"react-native-mime-types": "^2.2.1",
|
"react-native-mime-types": "^2.2.1",
|
||||||
"react-native-modal": "^11.3.0",
|
"react-native-modal": "^11.3.0",
|
||||||
"react-native-notifications": "^2.0.6",
|
"react-native-notifications": "^2.0.6",
|
||||||
|
@ -90,7 +90,8 @@
|
||||||
"rn-user-defaults": "^1.3.5",
|
"rn-user-defaults": "^1.3.5",
|
||||||
"semver": "6.3.0",
|
"semver": "6.3.0",
|
||||||
"snyk": "1.210.0",
|
"snyk": "1.210.0",
|
||||||
"strip-ansi": "5.2.0"
|
"strip-ansi": "5.2.0",
|
||||||
|
"url-parse": "^1.4.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.5.5",
|
"@babel/core": "^7.5.5",
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
diff --git a/node_modules/react-native-markdown-renderer/src/index.js b/node_modules/react-native-markdown-renderer/src/index.js
|
|
||||||
index 653bba2..e5cb521 100644
|
|
||||||
--- a/node_modules/react-native-markdown-renderer/src/index.js
|
|
||||||
+++ b/node_modules/react-native-markdown-renderer/src/index.js
|
|
||||||
@@ -88,9 +88,15 @@ export default class Markdown extends Component {
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
- copy = '';
|
|
||||||
- renderer = null;
|
|
||||||
- markdownParser = null;
|
|
||||||
+ constructor(props) {
|
|
||||||
+ super(props);
|
|
||||||
+ this.copy = '';
|
|
||||||
+ this.renderer = null;
|
|
||||||
+ this.markdownParser = null;
|
|
||||||
+ }
|
|
||||||
+ // copy = '';
|
|
||||||
+ // renderer = null;
|
|
||||||
+ // markdownParser = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only when the copy changes will the markdown render again.
|
|
|
@ -91,6 +91,20 @@ export default (
|
||||||
<Separator title='Edited' />
|
<Separator title='Edited' />
|
||||||
<Message msg='Message' edited />
|
<Message msg='Message' edited />
|
||||||
|
|
||||||
|
<Separator title='Block Quote' />
|
||||||
|
<Message msg='> Testing block quote' />
|
||||||
|
<Message msg={'> Testing block quote\nTesting block quote'} />
|
||||||
|
|
||||||
|
<Separator title='Lists' />
|
||||||
|
<Message msg={'* Dogs\n * cats\n - cats'} />
|
||||||
|
|
||||||
|
<Separator title='Numerated lists' />
|
||||||
|
<Message msg={'1. Dogs \n 2. Cats'} />
|
||||||
|
|
||||||
|
<Separator title='Numerated lists in separated messages' />
|
||||||
|
<Message msg='1. Dogs' />
|
||||||
|
<Message msg='2. Cats' isHeader={false} />
|
||||||
|
|
||||||
<Separator title='Static avatar' />
|
<Separator title='Static avatar' />
|
||||||
<Message
|
<Message
|
||||||
msg='Message'
|
msg='Message'
|
||||||
|
@ -714,7 +728,7 @@ export default (
|
||||||
<Message msg='Message' style={[styles.normalize, { backgroundColor: '#ddd' }]} />
|
<Message msg='Message' style={[styles.normalize, { backgroundColor: '#ddd' }]} />
|
||||||
|
|
||||||
<Separator title='Markdown emphasis' />
|
<Separator title='Markdown emphasis' />
|
||||||
<Message msg='Italic with *asterisks* or _underscores_. Bold with **asterisks** or __underscores__. ~~Strikethrough~~' />
|
<Message msg='Italic with single _underscore_ or double __underscores__. Bold with single *asterisk* or double **asterisks**. Strikethrough with single ~Strikethrough~ or double ~~Strikethrough~~' />
|
||||||
|
|
||||||
<Separator title='Markdown headers' />
|
<Separator title='Markdown headers' />
|
||||||
<Message
|
<Message
|
||||||
|
|
135
yarn.lock
135
yarn.lock
|
@ -1692,11 +1692,6 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-4.1.1.tgz#b2d87a5e3df8d4b18ca426c5105cd701c2306d40"
|
resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-4.1.1.tgz#b2d87a5e3df8d4b18ca426c5105cd701c2306d40"
|
||||||
integrity sha512-8mNEUG6diOrI6pMqOHrHPDBB1JsrpedeMK9AWGzVCQ7StRRribiT9BRvUmF8aUws9iBbVlgVekOT5Sgzc1MTKw==
|
integrity sha512-8mNEUG6diOrI6pMqOHrHPDBB1JsrpedeMK9AWGzVCQ7StRRribiT9BRvUmF8aUws9iBbVlgVekOT5Sgzc1MTKw==
|
||||||
|
|
||||||
"@types/markdown-it@^0.0.4":
|
|
||||||
version "0.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.4.tgz#c5f67365916044b342dae8d702724788ba0b5b74"
|
|
||||||
integrity sha512-FWR7QB7EqBRq1s9BMk0ccOSOuRLfVEWYpHQYpFPaXtCoqN6dJx2ttdsdQbUxLLnAlKpYeVjveGGhQ3583TTa7g==
|
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "12.6.9"
|
version "12.6.9"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.9.tgz#ffeee23afdc19ab16e979338e7b536fdebbbaeaf"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.9.tgz#ffeee23afdc19ab16e979338e7b536fdebbbaeaf"
|
||||||
|
@ -1722,27 +1717,6 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
|
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
|
||||||
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
|
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
|
||||||
|
|
||||||
"@types/prop-types@*":
|
|
||||||
version "15.5.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.8.tgz#8ae4e0ea205fe95c3901a5a1df7f66495e3a56ce"
|
|
||||||
integrity sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==
|
|
||||||
|
|
||||||
"@types/react-native@>=0.50.0":
|
|
||||||
version "0.57.33"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.57.33.tgz#1d35a883c6e30d6f0b40385230fde2d8213b4dca"
|
|
||||||
integrity sha512-mn6u8aeh7nxBGO82z/vQeFrlfkBIAAk69MIxSK0aIn8cQnaFqmsoaeSBPhc1K+oIbMXytfehl0w5U1H20OIk+A==
|
|
||||||
dependencies:
|
|
||||||
"@types/prop-types" "*"
|
|
||||||
"@types/react" "*"
|
|
||||||
|
|
||||||
"@types/react@*":
|
|
||||||
version "16.7.22"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.22.tgz#5bc6d166d5ac34b835756f0b736c7b1af0043e81"
|
|
||||||
integrity sha512-j/3tVoY09kHcTfbia4l67ofQn9xvktUvlC/4QN0KuBHAXlbU/wuGKMb8WfEb/vIcWxsOxHv559uYprkFDFfP8Q==
|
|
||||||
dependencies:
|
|
||||||
"@types/prop-types" "*"
|
|
||||||
csstype "^2.2.0"
|
|
||||||
|
|
||||||
"@types/stack-utils@^1.0.1":
|
"@types/stack-utils@^1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
|
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
|
||||||
|
@ -3180,6 +3154,25 @@ commondir@^1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
|
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
|
||||||
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
|
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
|
||||||
|
|
||||||
|
"commonmark-react-renderer@git+https://github.com/RocketChat/commonmark-react-renderer.git":
|
||||||
|
version "4.3.4"
|
||||||
|
resolved "git+https://github.com/RocketChat/commonmark-react-renderer.git#1264ac7b1c13d9be3e2f67eec6702a3132f4fac2"
|
||||||
|
dependencies:
|
||||||
|
lodash.assign "^4.2.0"
|
||||||
|
lodash.isplainobject "^4.0.6"
|
||||||
|
pascalcase "^0.1.1"
|
||||||
|
xss-filters "^1.2.6"
|
||||||
|
|
||||||
|
"commonmark@git+https://github.com/RocketChat/commonmark.js.git":
|
||||||
|
version "0.29.0"
|
||||||
|
resolved "git+https://github.com/RocketChat/commonmark.js.git#005849af59002665dea50353ae9991c49abb1380"
|
||||||
|
dependencies:
|
||||||
|
entities "~ 1.1.1"
|
||||||
|
mdurl "~ 1.0.1"
|
||||||
|
minimist "~ 1.2.0"
|
||||||
|
string.prototype.repeat "^0.2.0"
|
||||||
|
xregexp "4.1.1"
|
||||||
|
|
||||||
compare-versions@^3.4.0:
|
compare-versions@^3.4.0:
|
||||||
version "3.4.0"
|
version "3.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26"
|
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26"
|
||||||
|
@ -3473,11 +3466,6 @@ cssstyle@^1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
cssom "0.3.x"
|
cssom "0.3.x"
|
||||||
|
|
||||||
csstype@^2.2.0:
|
|
||||||
version "2.6.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.2.tgz#3043d5e065454579afc7478a18de41909c8a2f01"
|
|
||||||
integrity sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==
|
|
||||||
|
|
||||||
csstype@^2.5.7:
|
csstype@^2.5.7:
|
||||||
version "2.6.6"
|
version "2.6.6"
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.6.tgz#c34f8226a94bbb10c32cc0d714afdf942291fc41"
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.6.tgz#c34f8226a94bbb10c32cc0d714afdf942291fc41"
|
||||||
|
@ -3940,7 +3928,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
once "^1.4.0"
|
once "^1.4.0"
|
||||||
|
|
||||||
entities@~1.1.1:
|
"entities@~ 1.1.1":
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
|
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
|
||||||
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
|
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
|
||||||
|
@ -7262,13 +7250,6 @@ lines-and-columns@^1.1.6:
|
||||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
|
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
|
||||||
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
|
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
|
||||||
|
|
||||||
linkify-it@^2.0.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.1.0.tgz#c4caf38a6cd7ac2212ef3c7d2bde30a91561f9db"
|
|
||||||
integrity sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg==
|
|
||||||
dependencies:
|
|
||||||
uc.micro "^1.0.1"
|
|
||||||
|
|
||||||
load-json-file@^1.0.0:
|
load-json-file@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
|
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
|
||||||
|
@ -7363,6 +7344,11 @@ lodash.isequal@^4.5.0:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||||
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
||||||
|
|
||||||
|
lodash.isplainobject@^4.0.6:
|
||||||
|
version "4.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
|
||||||
|
integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
|
||||||
|
|
||||||
lodash.memoize@^4.1.2:
|
lodash.memoize@^4.1.2:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||||
|
@ -7492,22 +7478,6 @@ map-visit@^1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
object-visit "^1.0.0"
|
object-visit "^1.0.0"
|
||||||
|
|
||||||
markdown-it-flowdock@0.3.8:
|
|
||||||
version "0.3.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/markdown-it-flowdock/-/markdown-it-flowdock-0.3.8.tgz#fb768485e648d90f596c579d51aa70397d33d916"
|
|
||||||
integrity sha512-VcI3/ZPC9Gb72KUKmf4VvVA9atvpbt+Hame8dMtyEXsp0Cdw6RF/wbgjcjh1+7EVvcvASm2Gw3zjXio8S3evJg==
|
|
||||||
|
|
||||||
markdown-it@^8.4.0:
|
|
||||||
version "8.4.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54"
|
|
||||||
integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==
|
|
||||||
dependencies:
|
|
||||||
argparse "^1.0.7"
|
|
||||||
entities "~1.1.1"
|
|
||||||
linkify-it "^2.0.0"
|
|
||||||
mdurl "^1.0.1"
|
|
||||||
uc.micro "^1.0.5"
|
|
||||||
|
|
||||||
markdown-to-jsx@^6.9.1:
|
markdown-to-jsx@^6.9.1:
|
||||||
version "6.10.3"
|
version "6.10.3"
|
||||||
resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-6.10.3.tgz#7f0946684acd321125ff2de7fd258a9b9c7c40b7"
|
resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-6.10.3.tgz#7f0946684acd321125ff2de7fd258a9b9c7c40b7"
|
||||||
|
@ -7530,7 +7500,7 @@ md5.js@^1.3.4:
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
safe-buffer "^5.1.2"
|
safe-buffer "^5.1.2"
|
||||||
|
|
||||||
mdurl@^1.0.1:
|
"mdurl@~ 1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
||||||
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
|
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
|
||||||
|
@ -7962,7 +7932,7 @@ minimist@0.0.8:
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||||
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
||||||
|
|
||||||
minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0:
|
minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0, "minimist@~ 1.2.0":
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||||
|
@ -9391,6 +9361,11 @@ querystringify@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef"
|
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef"
|
||||||
integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==
|
integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==
|
||||||
|
|
||||||
|
querystringify@^2.1.1:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
|
||||||
|
integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
|
||||||
|
|
||||||
random-bytes@~1.0.0:
|
random-bytes@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b"
|
resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b"
|
||||||
|
@ -9597,13 +9572,6 @@ react-native-firebase@^5.5.5:
|
||||||
opencollective-postinstall "^2.0.0"
|
opencollective-postinstall "^2.0.0"
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
|
|
||||||
react-native-fit-image@^1.5.2:
|
|
||||||
version "1.5.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-native-fit-image/-/react-native-fit-image-1.5.4.tgz#73d2fccc7ad902cf2ffcd008a2a74749ad50134a"
|
|
||||||
integrity sha512-wNHlGdDWsUU31qlM5SsvZrMH4eXBZt586FQNXFRFuOiXVqdA++6Xait7aiZ+5vxglgqLf+zzSnoICn0NEvDfrw==
|
|
||||||
dependencies:
|
|
||||||
prop-types "^15.5.10"
|
|
||||||
|
|
||||||
react-native-gesture-handler@^1.3.0:
|
react-native-gesture-handler@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.3.0.tgz#d0386f565928ccc1849537f03f2e37fd5f6ad43f"
|
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.3.0.tgz#d0386f565928ccc1849537f03f2e37fd5f6ad43f"
|
||||||
|
@ -9660,17 +9628,6 @@ react-native-localize@^1.1.4:
|
||||||
resolved "https://registry.yarnpkg.com/react-native-localize/-/react-native-localize-1.1.4.tgz#d48aa4f75afd39a42dcd0bdf40f7f44a8ccd604c"
|
resolved "https://registry.yarnpkg.com/react-native-localize/-/react-native-localize-1.1.4.tgz#d48aa4f75afd39a42dcd0bdf40f7f44a8ccd604c"
|
||||||
integrity sha512-NHsA812yvoH9ktPl1IqIxwDDwykipyH7K4zeW/nnipZuQb2g73SQEB3ryqKHmRASWD0DZl0hIxHr9IszzG5W5w==
|
integrity sha512-NHsA812yvoH9ktPl1IqIxwDDwykipyH7K4zeW/nnipZuQb2g73SQEB3ryqKHmRASWD0DZl0hIxHr9IszzG5W5w==
|
||||||
|
|
||||||
react-native-markdown-renderer@^3.2.8:
|
|
||||||
version "3.2.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-native-markdown-renderer/-/react-native-markdown-renderer-3.2.8.tgz#217046cf198eca632a65f93cdf7dd7766f718070"
|
|
||||||
integrity sha512-gDT5r3lwecNsEfpKagSaidEGfmCbpVcmV+HHLjaGYRALJoHkpOFni0rJZW1rCerOR9sjaUNGXE66U7BUrlEw0w==
|
|
||||||
dependencies:
|
|
||||||
"@types/markdown-it" "^0.0.4"
|
|
||||||
"@types/react-native" ">=0.50.0"
|
|
||||||
markdown-it "^8.4.0"
|
|
||||||
prop-types "^15.5.10"
|
|
||||||
react-native-fit-image "^1.5.2"
|
|
||||||
|
|
||||||
react-native-mime-types@^2.2.1:
|
react-native-mime-types@^2.2.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-mime-types/-/react-native-mime-types-2.2.1.tgz#a9760e9916e4e7df03512c60516668f23543f2c0"
|
resolved "https://registry.yarnpkg.com/react-native-mime-types/-/react-native-mime-types-2.2.1.tgz#a9760e9916e4e7df03512c60516668f23543f2c0"
|
||||||
|
@ -11442,6 +11399,11 @@ string-width@^3.1.0:
|
||||||
is-fullwidth-code-point "^2.0.0"
|
is-fullwidth-code-point "^2.0.0"
|
||||||
strip-ansi "^5.1.0"
|
strip-ansi "^5.1.0"
|
||||||
|
|
||||||
|
string.prototype.repeat@^0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz#aba36de08dcee6a5a337d49b2ea1da1b28fc0ecf"
|
||||||
|
integrity sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8=
|
||||||
|
|
||||||
string_decoder@^1.1.1:
|
string_decoder@^1.1.1:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
|
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
|
||||||
|
@ -12003,11 +11965,6 @@ ua-parser-js@^0.7.19:
|
||||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.20.tgz#7527178b82f6a62a0f243d1f94fd30e3e3c21098"
|
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.20.tgz#7527178b82f6a62a0f243d1f94fd30e3e3c21098"
|
||||||
integrity sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==
|
integrity sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==
|
||||||
|
|
||||||
uc.micro@^1.0.1, uc.micro@^1.0.5:
|
|
||||||
version "1.0.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
|
|
||||||
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
|
|
||||||
|
|
||||||
uglify-es@^3.1.9:
|
uglify-es@^3.1.9:
|
||||||
version "3.3.9"
|
version "3.3.9"
|
||||||
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
|
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
|
||||||
|
@ -12235,6 +12192,14 @@ url-parse@^1.4.4:
|
||||||
querystringify "^2.0.0"
|
querystringify "^2.0.0"
|
||||||
requires-port "^1.0.0"
|
requires-port "^1.0.0"
|
||||||
|
|
||||||
|
url-parse@^1.4.7:
|
||||||
|
version "1.4.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
|
||||||
|
integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
|
||||||
|
dependencies:
|
||||||
|
querystringify "^2.1.1"
|
||||||
|
requires-port "^1.0.0"
|
||||||
|
|
||||||
urlgrey@^0.4.4:
|
urlgrey@^0.4.4:
|
||||||
version "0.4.4"
|
version "0.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f"
|
resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f"
|
||||||
|
@ -12605,6 +12570,16 @@ xregexp@2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943"
|
resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943"
|
||||||
integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=
|
integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=
|
||||||
|
|
||||||
|
xregexp@4.1.1:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.1.1.tgz#eb8a032aa028d403f7b1b22c47a5f16c24b21d8d"
|
||||||
|
integrity sha512-QJ1gfSUV7kEOLfpKFCjBJRnfPErUzkNKFMso4kDSmGpp3x6ZgkyKf74inxI7PnnQCFYq5TqYJCd7DrgDN8Q05A==
|
||||||
|
|
||||||
|
xss-filters@^1.2.6:
|
||||||
|
version "1.2.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/xss-filters/-/xss-filters-1.2.7.tgz#59fa1de201f36f2f3470dcac5f58ccc2830b0a9a"
|
||||||
|
integrity sha1-Wfod4gHzby80cNysX1jMwoMLCpo=
|
||||||
|
|
||||||
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1:
|
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||||
|
|
Loading…
Reference in New Issue