[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 { connect } from 'react-redux';
|
||||
|
||||
import Markdown from '../message/Markdown';
|
||||
import Markdown from '../markdown';
|
||||
import { getCustomEmoji } from '../message/utils';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
|
@ -50,6 +50,7 @@ const styles = StyleSheet.create({
|
|||
|
||||
class ReplyPreview extends Component {
|
||||
static propTypes = {
|
||||
useMarkdown: PropTypes.bool,
|
||||
message: PropTypes.object.isRequired,
|
||||
Message_TimeFormat: PropTypes.string.isRequired,
|
||||
close: PropTypes.func.isRequired,
|
||||
|
@ -68,7 +69,7 @@ class ReplyPreview extends Component {
|
|||
|
||||
render() {
|
||||
const {
|
||||
message, Message_TimeFormat, baseUrl, username
|
||||
message, Message_TimeFormat, baseUrl, username, useMarkdown
|
||||
} = this.props;
|
||||
const time = moment(message.ts).format(Message_TimeFormat);
|
||||
return (
|
||||
|
@ -78,7 +79,7 @@ class ReplyPreview extends Component {
|
|||
<Text style={styles.username}>{message.u.username}</Text>
|
||||
<Text style={styles.time}>{time}</Text>
|
||||
</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>
|
||||
<CustomIcon name='cross' color={COLOR_TEXT_DESCRIPTION} size={20} style={styles.close} onPress={this.close} />
|
||||
</View>
|
||||
|
@ -87,6 +88,7 @@ class ReplyPreview extends Component {
|
|||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
useMarkdown: state.markdown.useMarkdown,
|
||||
Message_TimeFormat: state.settings.Message_TimeFormat,
|
||||
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 Touchable from 'react-native-platform-touchable';
|
||||
|
||||
import Markdown from './Markdown';
|
||||
import Markdown from '../markdown';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
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 styles from './styles';
|
||||
import Markdown from './Markdown';
|
||||
import Markdown from '../markdown';
|
||||
import { getInfoMessage } from './utils';
|
||||
|
||||
const Content = React.memo((props) => {
|
||||
|
@ -21,14 +21,15 @@ const Content = React.memo((props) => {
|
|||
<Markdown
|
||||
msg={props.msg}
|
||||
baseUrl={props.baseUrl}
|
||||
getCustomEmoji={props.getCustomEmoji}
|
||||
username={props.user.username}
|
||||
isEdited={props.isEdited}
|
||||
mentions={props.mentions}
|
||||
channels={props.channels}
|
||||
numberOfLines={props.tmid ? 1 : 0}
|
||||
getCustomEmoji={props.getCustomEmoji}
|
||||
channels={props.channels}
|
||||
mentions={props.mentions}
|
||||
useMarkdown={props.useMarkdown}
|
||||
navToRoomInfo={props.navToRoomInfo}
|
||||
tmid={props.tmid}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -43,16 +44,16 @@ const Content = React.memo((props) => {
|
|||
Content.propTypes = {
|
||||
isTemp: PropTypes.bool,
|
||||
isInfo: PropTypes.bool,
|
||||
isEdited: PropTypes.bool,
|
||||
useMarkdown: PropTypes.bool,
|
||||
tmid: PropTypes.string,
|
||||
msg: PropTypes.string,
|
||||
isEdited: PropTypes.bool,
|
||||
useMarkdown: PropTypes.bool,
|
||||
baseUrl: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
getCustomEmoji: PropTypes.func,
|
||||
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
navToRoomInfo: PropTypes.func,
|
||||
getCustomEmoji: PropTypes.func
|
||||
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
navToRoomInfo: PropTypes.func
|
||||
};
|
||||
Content.displayName = 'MessageContent';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import FastImage from 'react-native-fast-image';
|
|||
import equal from 'deep-equal';
|
||||
import Touchable from 'react-native-platform-touchable';
|
||||
|
||||
import Markdown from './Markdown';
|
||||
import Markdown from '../markdown';
|
||||
import styles from './styles';
|
||||
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 isEqual from 'deep-equal';
|
||||
|
||||
import Markdown from './Markdown';
|
||||
import Markdown from '../markdown';
|
||||
import openLink from '../../utils/openLink';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
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 isEqual from 'deep-equal';
|
||||
|
||||
import Markdown from './Markdown';
|
||||
import Markdown from '../markdown';
|
||||
import openLink from '../../utils/openLink';
|
||||
import { isIOS } from '../../utils/deviceInfo';
|
||||
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 {
|
||||
COLOR_BORDER, COLOR_PRIMARY, COLOR_WHITE, COLOR_BACKGROUND_CONTAINER
|
||||
COLOR_BORDER, COLOR_PRIMARY, COLOR_WHITE
|
||||
} from '../../constants/colors';
|
||||
|
||||
const codeFontFamily = Platform.select({
|
||||
ios: { fontFamily: 'Courier New' },
|
||||
android: { fontFamily: 'monospace' }
|
||||
});
|
||||
|
||||
export default StyleSheet.create({
|
||||
root: {
|
||||
flexDirection: 'row'
|
||||
|
@ -34,30 +29,6 @@ export default StyleSheet.create({
|
|||
flexDirection: 'row'
|
||||
// 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 },
|
||||
marginTop: {
|
||||
marginTop: 6
|
||||
|
@ -143,28 +114,6 @@ export default StyleSheet.create({
|
|||
fontSize: 14,
|
||||
...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: {
|
||||
// flex: 1,
|
||||
flexDirection: 'column',
|
||||
|
@ -186,29 +135,15 @@ export default StyleSheet.create({
|
|||
height: 300,
|
||||
resizeMode: 'contain'
|
||||
},
|
||||
edited: {
|
||||
fontSize: 14,
|
||||
...sharedStyles.textColorDescription,
|
||||
text: {
|
||||
fontSize: 16,
|
||||
...sharedStyles.textColorNormal,
|
||||
...sharedStyles.textRegular
|
||||
},
|
||||
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: {
|
||||
color: COLOR_PRIMARY,
|
||||
textInfo: {
|
||||
fontStyle: 'italic',
|
||||
fontSize: 16,
|
||||
...sharedStyles.textColorDescription,
|
||||
...sharedStyles.textRegular
|
||||
},
|
||||
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: 'Forgot password',
|
||||
Forgot_Password: 'Forgot Password',
|
||||
Full_table: 'Click to see full table',
|
||||
Group_by_favorites: 'Group favorites',
|
||||
Group_by_type: 'Group by type',
|
||||
Hide: 'Hide',
|
||||
|
@ -360,6 +361,7 @@ export default {
|
|||
Start_of_conversation: 'Start of conversation',
|
||||
Started_discussion: 'Started a discussion:',
|
||||
Submit: 'Submit',
|
||||
Table: 'Table',
|
||||
Take_a_photo: 'Take a photo',
|
||||
Take_a_video: 'Take a video',
|
||||
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: 'Esqueci minha senha',
|
||||
Forgot_Password: 'Esqueci minha senha',
|
||||
Full_table: 'Clique para ver a tabela completa',
|
||||
Group_by_favorites: 'Agrupar favoritos',
|
||||
Group_by_type: 'Agrupar por tipo',
|
||||
Has_joined_the_channel: 'Entrou no canal',
|
||||
|
@ -326,6 +327,7 @@ export default {
|
|||
Start_of_conversation: 'Início da conversa',
|
||||
Started_discussion: 'Iniciou uma discussão:',
|
||||
Submit: 'Enviar',
|
||||
Table: 'Tabela',
|
||||
Take_a_photo: 'Tirar uma foto',
|
||||
Take_a_video: 'Gravar um vídeo',
|
||||
Terms_of_Service: ' Termos de Serviço ',
|
||||
|
|
|
@ -122,6 +122,9 @@ const ChatsStack = createStackNavigator({
|
|||
DirectoryView: {
|
||||
getScreen: () => require('./views/DirectoryView').default
|
||||
},
|
||||
TableView: {
|
||||
getScreen: () => require('./views/TableView').default
|
||||
},
|
||||
NotificationPrefView: {
|
||||
getScreen: () => require('./views/NotificationPreferencesView').default
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import equal from 'deep-equal';
|
|||
import RCTextInput from '../../containers/TextInput';
|
||||
import RCActivityIndicator from '../../containers/ActivityIndicator';
|
||||
import styles from './styles';
|
||||
import Markdown from '../../containers/message/Markdown';
|
||||
import Markdown from '../../containers/markdown';
|
||||
import debounce from '../../utils/debounce';
|
||||
import RocketChat from '../../lib/rocketchat';
|
||||
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": {
|
||||
"@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",
|
||||
"deep-equal": "^1.0.1",
|
||||
"ejson": "2.2.0",
|
||||
|
@ -34,7 +36,6 @@
|
|||
"js-base64": "^2.5.1",
|
||||
"js-sha256": "^0.9.0",
|
||||
"lodash": "4.17.15",
|
||||
"markdown-it-flowdock": "0.3.8",
|
||||
"moment": "^2.24.0",
|
||||
"prop-types": "15.7.2",
|
||||
"react": "16.8.6",
|
||||
|
@ -56,7 +57,6 @@
|
|||
"react-native-keyboard-input": "^5.3.1",
|
||||
"react-native-keyboard-tracking-view": "^5.5.0",
|
||||
"react-native-localize": "^1.1.4",
|
||||
"react-native-markdown-renderer": "^3.2.8",
|
||||
"react-native-mime-types": "^2.2.1",
|
||||
"react-native-modal": "^11.3.0",
|
||||
"react-native-notifications": "^2.0.6",
|
||||
|
@ -90,7 +90,8 @@
|
|||
"rn-user-defaults": "^1.3.5",
|
||||
"semver": "6.3.0",
|
||||
"snyk": "1.210.0",
|
||||
"strip-ansi": "5.2.0"
|
||||
"strip-ansi": "5.2.0",
|
||||
"url-parse": "^1.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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' />
|
||||
<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' />
|
||||
<Message
|
||||
msg='Message'
|
||||
|
@ -714,7 +728,7 @@ export default (
|
|||
<Message msg='Message' style={[styles.normalize, { backgroundColor: '#ddd' }]} />
|
||||
|
||||
<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' />
|
||||
<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"
|
||||
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@*":
|
||||
version "12.6.9"
|
||||
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"
|
||||
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":
|
||||
version "1.0.1"
|
||||
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"
|
||||
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:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26"
|
||||
|
@ -3473,11 +3466,6 @@ cssstyle@^1.0.0:
|
|||
dependencies:
|
||||
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:
|
||||
version "2.6.6"
|
||||
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:
|
||||
once "^1.4.0"
|
||||
|
||||
entities@~1.1.1:
|
||||
"entities@~ 1.1.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
|
||||
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"
|
||||
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:
|
||||
version "1.1.0"
|
||||
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"
|
||||
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:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
|
@ -7492,22 +7478,6 @@ map-visit@^1.0.0:
|
|||
dependencies:
|
||||
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:
|
||||
version "6.10.3"
|
||||
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"
|
||||
safe-buffer "^5.1.2"
|
||||
|
||||
mdurl@^1.0.1:
|
||||
"mdurl@~ 1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
||||
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
|
||||
|
@ -7962,7 +7932,7 @@ minimist@0.0.8:
|
|||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
@ -9391,6 +9361,11 @@ querystringify@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef"
|
||||
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:
|
||||
version "1.0.0"
|
||||
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"
|
||||
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:
|
||||
version "1.3.0"
|
||||
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"
|
||||
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:
|
||||
version "2.2.1"
|
||||
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"
|
||||
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:
|
||||
version "1.2.0"
|
||||
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"
|
||||
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:
|
||||
version "3.3.9"
|
||||
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"
|
||||
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:
|
||||
version "0.4.4"
|
||||
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"
|
||||
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:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
|
|
Loading…
Reference in New Issue