forked from Ivasoft/mattermost-mobile
Compare commits
5 Commits
migrate-to
...
hh_ship-co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a5da8d625 | ||
|
|
70d5cb068c | ||
|
|
c6af59b388 | ||
|
|
97cdac1d40 | ||
|
|
b9376ad429 |
@@ -6,10 +6,11 @@ import Renderer from 'commonmark-react-renderer';
|
|||||||
import React, {ReactElement, useRef} from 'react';
|
import React, {ReactElement, useRef} from 'react';
|
||||||
import {Dimensions, GestureResponderEvent, Platform, StyleProp, Text, TextStyle, View} from 'react-native';
|
import {Dimensions, GestureResponderEvent, Platform, StyleProp, Text, TextStyle, View} from 'react-native';
|
||||||
|
|
||||||
|
import CompassIcon from '@components/compass_icon';
|
||||||
import Emoji from '@components/emoji';
|
import Emoji from '@components/emoji';
|
||||||
import FormattedText from '@components/formatted_text';
|
import FormattedText from '@components/formatted_text';
|
||||||
import Hashtag from '@components/markdown/hashtag';
|
import Hashtag from '@components/markdown/hashtag';
|
||||||
import {blendColors, concatStyles, makeStyleSheetFromTheme} from '@utils/theme';
|
import {blendColors, changeOpacity, concatStyles, makeStyleSheetFromTheme} from '@utils/theme';
|
||||||
import {getScheme} from '@utils/url';
|
import {getScheme} from '@utils/url';
|
||||||
|
|
||||||
import AtMention from './at_mention';
|
import AtMention from './at_mention';
|
||||||
@@ -26,11 +27,11 @@ import MarkdownTable from './markdown_table';
|
|||||||
import MarkdownTableCell, {MarkdownTableCellProps} from './markdown_table_cell';
|
import MarkdownTableCell, {MarkdownTableCellProps} from './markdown_table_cell';
|
||||||
import MarkdownTableImage from './markdown_table_image';
|
import MarkdownTableImage from './markdown_table_image';
|
||||||
import MarkdownTableRow, {MarkdownTableRowProps} from './markdown_table_row';
|
import MarkdownTableRow, {MarkdownTableRowProps} from './markdown_table_row';
|
||||||
import {addListItemIndices, combineTextNodes, highlightMentions, pullOutImages} from './transform';
|
import {addListItemIndices, combineTextNodes, highlightMentions, highlightSearchPatterns, parseTaskLists, pullOutImages} from './transform';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
MarkdownAtMentionRenderer, MarkdownBaseRenderer, MarkdownBlockStyles, MarkdownChannelMentionRenderer,
|
MarkdownAtMentionRenderer, MarkdownBaseRenderer, MarkdownBlockStyles, MarkdownChannelMentionRenderer,
|
||||||
MarkdownEmojiRenderer, MarkdownImageRenderer, MarkdownLatexRenderer, MarkdownTextStyles, UserMentionKey,
|
MarkdownEmojiRenderer, MarkdownImageRenderer, MarkdownLatexRenderer, MarkdownTextStyles, SearchPattern, UserMentionKey,
|
||||||
} from '@typings/global/markdown';
|
} from '@typings/global/markdown';
|
||||||
|
|
||||||
type MarkdownProps = {
|
type MarkdownProps = {
|
||||||
@@ -55,6 +56,7 @@ type MarkdownProps = {
|
|||||||
minimumHashtagLength?: number;
|
minimumHashtagLength?: number;
|
||||||
onPostPress?: (event: GestureResponderEvent) => void;
|
onPostPress?: (event: GestureResponderEvent) => void;
|
||||||
postId?: string;
|
postId?: string;
|
||||||
|
searchPatterns?: SearchPattern[];
|
||||||
textStyles?: MarkdownTextStyles;
|
textStyles?: MarkdownTextStyles;
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
value?: string | number;
|
value?: string | number;
|
||||||
@@ -100,6 +102,10 @@ const getExtraPropsForNode = (node: any) => {
|
|||||||
extraProps.size = node.size;
|
extraProps.size = node.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node.type === 'checkbox') {
|
||||||
|
extraProps.isChecked = node.isChecked;
|
||||||
|
}
|
||||||
|
|
||||||
return extraProps;
|
return extraProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -114,7 +120,7 @@ const Markdown = ({
|
|||||||
disableAtChannelMentionHighlight = false, disableAtMentions = false, disableChannelLink = false,
|
disableAtChannelMentionHighlight = false, disableAtMentions = false, disableChannelLink = false,
|
||||||
disableGallery = false, disableHashtags = false, enableInlineLatex, enableLatex,
|
disableGallery = false, disableHashtags = false, enableInlineLatex, enableLatex,
|
||||||
imagesMetadata, isEdited, isReplyPost, isSearchResult, layoutWidth,
|
imagesMetadata, isEdited, isReplyPost, isSearchResult, layoutWidth,
|
||||||
location, mentionKeys, minimumHashtagLength = 3, onPostPress, postId,
|
location, mentionKeys, minimumHashtagLength = 3, onPostPress, postId, searchPatterns,
|
||||||
textStyles = {}, theme, value = '',
|
textStyles = {}, theme, value = '',
|
||||||
}: MarkdownProps) => {
|
}: MarkdownProps) => {
|
||||||
const style = getStyleSheet(theme);
|
const style = getStyleSheet(theme);
|
||||||
@@ -172,6 +178,19 @@ const Markdown = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderCheckbox = ({isChecked}: {isChecked: boolean}) => {
|
||||||
|
return (
|
||||||
|
<Text>
|
||||||
|
<CompassIcon
|
||||||
|
name={isChecked ? 'checkbox-marked' : 'checkbox-blank-outline'}
|
||||||
|
size={16}
|
||||||
|
color={changeOpacity(theme.centerChannelColor, 0.56)}
|
||||||
|
/>
|
||||||
|
{' '}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const renderCodeBlock = (props: any) => {
|
const renderCodeBlock = (props: any) => {
|
||||||
// These sometimes include a trailing newline
|
// These sometimes include a trailing newline
|
||||||
const content = props.literal.replace(/\n$/, '');
|
const content = props.literal.replace(/\n$/, '');
|
||||||
@@ -464,6 +483,8 @@ const Markdown = ({
|
|||||||
table_cell: renderTableCell,
|
table_cell: renderTableCell,
|
||||||
|
|
||||||
mention_highlight: Renderer.forwardChildren,
|
mention_highlight: Renderer.forwardChildren,
|
||||||
|
search_highlight: Renderer.forwardChildren,
|
||||||
|
checkbox: renderCheckbox,
|
||||||
|
|
||||||
editedIndicator: renderEditedIndicator,
|
editedIndicator: renderEditedIndicator,
|
||||||
};
|
};
|
||||||
@@ -472,6 +493,7 @@ const Markdown = ({
|
|||||||
renderers,
|
renderers,
|
||||||
renderParagraphsInLists: true,
|
renderParagraphsInLists: true,
|
||||||
getExtraPropsForNode,
|
getExtraPropsForNode,
|
||||||
|
allowedTypes: Object.keys(renderers),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -482,9 +504,13 @@ const Markdown = ({
|
|||||||
ast = combineTextNodes(ast);
|
ast = combineTextNodes(ast);
|
||||||
ast = addListItemIndices(ast);
|
ast = addListItemIndices(ast);
|
||||||
ast = pullOutImages(ast);
|
ast = pullOutImages(ast);
|
||||||
|
ast = parseTaskLists(ast);
|
||||||
if (mentionKeys) {
|
if (mentionKeys) {
|
||||||
ast = highlightMentions(ast, mentionKeys);
|
ast = highlightMentions(ast, mentionKeys);
|
||||||
}
|
}
|
||||||
|
if (searchPatterns) {
|
||||||
|
ast = highlightSearchPatterns(ast, searchPatterns);
|
||||||
|
}
|
||||||
|
|
||||||
if (isEdited) {
|
if (isEdited) {
|
||||||
const editIndicatorNode = new Node('edited_indicator');
|
const editIndicatorNode = new Node('edited_indicator');
|
||||||
|
|||||||
@@ -8,12 +8,15 @@ import {Node, Parser} from 'commonmark';
|
|||||||
import {
|
import {
|
||||||
addListItemIndices,
|
addListItemIndices,
|
||||||
combineTextNodes,
|
combineTextNodes,
|
||||||
getFirstMention,
|
getFirstMatch,
|
||||||
highlightMentions,
|
highlightMentions,
|
||||||
highlightTextNode,
|
highlightTextNode,
|
||||||
|
mentionKeysToPatterns,
|
||||||
pullOutImages,
|
pullOutImages,
|
||||||
} from '@components/markdown/transform';
|
} from '@components/markdown/transform';
|
||||||
|
|
||||||
|
import type {UserMentionKey} from '@typings/global/markdown';
|
||||||
|
|
||||||
/* eslint-disable max-lines, no-console, no-underscore-dangle */
|
/* eslint-disable max-lines, no-console, no-underscore-dangle */
|
||||||
|
|
||||||
describe('Components.Markdown.transform', () => {
|
describe('Components.Markdown.transform', () => {
|
||||||
@@ -2623,64 +2626,69 @@ describe('Components.Markdown.transform', () => {
|
|||||||
name: 'no mention keys',
|
name: 'no mention keys',
|
||||||
input: 'apple banana orange',
|
input: 'apple banana orange',
|
||||||
mentionKeys: [],
|
mentionKeys: [],
|
||||||
expected: {index: -1, mention: null},
|
expected: {index: -1, length: -1},
|
||||||
}, {
|
}, {
|
||||||
name: 'single mention',
|
name: 'single mention',
|
||||||
input: 'apple banana orange',
|
input: 'apple banana orange',
|
||||||
mentionKeys: [{key: 'banana'}],
|
mentionKeys: [{key: 'banana'}],
|
||||||
expected: {index: 6, mention: {key: 'banana'}},
|
expected: {index: 6, length: 6},
|
||||||
}, {
|
}, {
|
||||||
name: 'multiple mentions',
|
name: 'multiple mentions',
|
||||||
input: 'apple banana orange',
|
input: 'apple banana orange',
|
||||||
mentionKeys: [{key: 'apple'}, {key: 'orange'}],
|
mentionKeys: [{key: 'apple'}, {key: 'orange'}],
|
||||||
expected: {index: 0, mention: {key: 'apple'}},
|
expected: {index: 0, length: 5},
|
||||||
}, {
|
}, {
|
||||||
name: 'case sensitive',
|
name: 'case sensitive',
|
||||||
input: 'apple APPLE Apple aPPle',
|
input: 'apple APPLE Apple aPPle',
|
||||||
mentionKeys: [{key: 'Apple', caseSensitive: true}],
|
mentionKeys: [{key: 'Apple', caseSensitive: true}],
|
||||||
expected: {index: 12, mention: {key: 'Apple', caseSensitive: true}},
|
expected: {index: 12, length: 5},
|
||||||
}, {
|
}, {
|
||||||
name: 'followed by period',
|
name: 'followed by period',
|
||||||
input: 'banana.',
|
input: 'banana.',
|
||||||
mentionKeys: [{key: 'banana'}],
|
mentionKeys: [{key: 'banana'}],
|
||||||
expected: {index: 0, mention: {key: 'banana'}},
|
expected: {index: 0, length: 6},
|
||||||
}, {
|
}, {
|
||||||
name: 'followed by underscores',
|
name: 'followed by underscores',
|
||||||
input: 'banana__',
|
input: 'banana__',
|
||||||
mentionKeys: [{key: 'banana'}],
|
mentionKeys: [{key: 'banana'}],
|
||||||
expected: {index: 0, mention: {key: 'banana'}},
|
expected: {index: 0, length: 6},
|
||||||
}, {
|
}, {
|
||||||
name: 'in brackets',
|
name: 'in brackets',
|
||||||
input: '(banana)',
|
input: '(banana)',
|
||||||
mentionKeys: [{key: 'banana'}],
|
mentionKeys: [{key: 'banana'}],
|
||||||
expected: {index: 1, mention: {key: 'banana'}},
|
expected: {index: 1, length: 6},
|
||||||
}, {
|
}, {
|
||||||
name: 'following punctuation',
|
name: 'following punctuation',
|
||||||
input: ':banana',
|
input: ':banana',
|
||||||
mentionKeys: [{key: 'banana'}],
|
mentionKeys: [{key: 'banana'}],
|
||||||
expected: {index: 1, mention: {key: 'banana'}},
|
expected: {index: 1, length: 6},
|
||||||
}, {
|
}, {
|
||||||
name: 'not part of another word',
|
name: 'not part of another word',
|
||||||
input: 'pineapple',
|
input: 'pineapple',
|
||||||
mentionKeys: [{key: 'apple'}],
|
mentionKeys: [{key: 'apple'}],
|
||||||
expected: {index: -1, mention: null},
|
expected: {index: -1, length: -1},
|
||||||
}, {
|
}, {
|
||||||
name: 'no error from weird mention keys',
|
name: 'no error from weird mention keys',
|
||||||
input: 'apple banana orange',
|
input: 'apple banana orange',
|
||||||
mentionKeys: [{key: '*\\3_.'}],
|
mentionKeys: [{key: '*\\3_.'}],
|
||||||
expected: {index: -1, mention: null},
|
expected: {index: -1, length: -1},
|
||||||
}, {
|
}, {
|
||||||
name: 'no blank mention keys',
|
name: 'no blank mention keys',
|
||||||
input: 'apple banana orange',
|
input: 'apple banana orange',
|
||||||
mentionKeys: [{key: ''}],
|
mentionKeys: [{key: ''}],
|
||||||
expected: {index: -1, mention: null},
|
expected: {index: -1, length: -1},
|
||||||
}, {
|
}, {
|
||||||
name: 'multibyte key',
|
name: 'multibyte key',
|
||||||
input: '좋은 하루 되세요.',
|
input: '좋은 하루 되세요.',
|
||||||
mentionKeys: [{key: '하루'}],
|
mentionKeys: [{key: '하루'}],
|
||||||
expected: {index: 3, mention: {key: '하루'}},
|
expected: {index: 3, length: 2},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
function getFirstMention(str: string, mentionKeys: UserMentionKey[]) {
|
||||||
|
const patterns = mentionKeysToPatterns(mentionKeys);
|
||||||
|
return getFirstMatch(str, patterns);
|
||||||
|
}
|
||||||
|
|
||||||
for (const test of tests) {
|
for (const test of tests) {
|
||||||
it(test.name, () => {
|
it(test.name, () => {
|
||||||
const actual = getFirstMention(test.input, test.mentionKeys);
|
const actual = getFirstMention(test.input, test.mentionKeys);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {Node, NodeType} from 'commonmark';
|
|||||||
|
|
||||||
import {escapeRegex} from '@utils/markdown';
|
import {escapeRegex} from '@utils/markdown';
|
||||||
|
|
||||||
import type {UserMentionKey} from '@typings/global/markdown';
|
import type {SearchPattern, UserMentionKey} from '@typings/global/markdown';
|
||||||
|
|
||||||
/* eslint-disable no-underscore-dangle */
|
/* eslint-disable no-underscore-dangle */
|
||||||
|
|
||||||
@@ -114,6 +114,8 @@ function pullOutImage(image: any) {
|
|||||||
export function highlightMentions(ast: Node, mentionKeys: UserMentionKey[]) {
|
export function highlightMentions(ast: Node, mentionKeys: UserMentionKey[]) {
|
||||||
const walker = ast.walker();
|
const walker = ast.walker();
|
||||||
|
|
||||||
|
const patterns = mentionKeysToPatterns(mentionKeys);
|
||||||
|
|
||||||
let e;
|
let e;
|
||||||
while ((e = walker.next())) {
|
while ((e = walker.next())) {
|
||||||
if (!e.entering) {
|
if (!e.entering) {
|
||||||
@@ -123,13 +125,13 @@ export function highlightMentions(ast: Node, mentionKeys: UserMentionKey[]) {
|
|||||||
const node = e.node;
|
const node = e.node;
|
||||||
|
|
||||||
if (node.type === 'text' && node.literal) {
|
if (node.type === 'text' && node.literal) {
|
||||||
const {index, mention} = getFirstMention(node.literal, mentionKeys);
|
const {index, length} = getFirstMatch(node.literal, patterns);
|
||||||
|
|
||||||
if (index === -1 || !mention) {
|
if (index === -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mentionNode = highlightTextNode(node, index, index + mention.key.length, 'mention_highlight');
|
const mentionNode = highlightTextNode(node, index, index + length, 'mention_highlight');
|
||||||
|
|
||||||
// Resume processing on the next node after the mention node which may include any remaining text
|
// Resume processing on the next node after the mention node which may include any remaining text
|
||||||
// that was part of this one
|
// that was part of this one
|
||||||
@@ -158,38 +160,71 @@ export function highlightMentions(ast: Node, mentionKeys: UserMentionKey[]) {
|
|||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a string and an array of mention keys, returns the first mention that appears and its index.
|
export function mentionKeysToPatterns(mentionKeys: UserMentionKey[]) {
|
||||||
export function getFirstMention(str: string, mentionKeys: UserMentionKey[]) {
|
return mentionKeys.filter((mention) => mention.key.trim() !== '').map((mention) => {
|
||||||
let firstMention = null;
|
|
||||||
let firstMentionIndex = -1;
|
|
||||||
|
|
||||||
for (const mention of mentionKeys) {
|
|
||||||
if (mention.key.trim() === '') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const flags = mention.caseSensitive ? '' : 'i';
|
const flags = mention.caseSensitive ? '' : 'i';
|
||||||
let pattern;
|
let pattern;
|
||||||
if (cjkPattern.test(mention.key)) {
|
if (cjkPattern.test(mention.key)) {
|
||||||
pattern = new RegExp(`${escapeRegex(mention.key)}`, flags);
|
pattern = new RegExp(`${escapeRegex(mention.key)}`, flags);
|
||||||
} else {
|
} else {
|
||||||
pattern = new RegExp(`\\b${escapeRegex(mention.key)}_*\\b`, flags);
|
pattern = new RegExp(`\\b${escapeRegex(mention.key)}(?=_*\\b)`, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return pattern;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function highlightSearchPatterns(ast: Node, searchPatterns: SearchPattern[]) {
|
||||||
|
const walker = ast.walker();
|
||||||
|
|
||||||
|
let e;
|
||||||
|
while ((e = walker.next())) {
|
||||||
|
if (!e.entering) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const node = e.node;
|
||||||
|
|
||||||
|
if (node.type === 'text' && node.literal) {
|
||||||
|
const {index, length} = getFirstMatch(node.literal, searchPatterns.map((pattern) => pattern.pattern));
|
||||||
|
|
||||||
|
// TODO we might need special handling here for if the search term is part of a hashtag
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchNode = highlightTextNode(node, index, index + length, 'search_highlight');
|
||||||
|
|
||||||
|
// Resume processing on the next node after the match node which may include any remaining text
|
||||||
|
// that was part of this one
|
||||||
|
walker.resumeAt(matchNode, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a string and an array of regexess, returns the index and length of the first match.
|
||||||
|
export function getFirstMatch(str: string, patterns: RegExp[]) {
|
||||||
|
let firstMatchIndex = -1;
|
||||||
|
let firstMatchLength = -1;
|
||||||
|
|
||||||
|
for (const pattern of patterns) {
|
||||||
const match = pattern.exec(str);
|
const match = pattern.exec(str);
|
||||||
if (!match || match[0] === '') {
|
if (!match || match[0] === '') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstMentionIndex === -1 || match.index < firstMentionIndex) {
|
if (firstMatchIndex === -1 || match.index < firstMatchIndex) {
|
||||||
firstMentionIndex = match.index;
|
firstMatchIndex = match.index;
|
||||||
firstMention = mention;
|
firstMatchLength = match[0].length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
index: firstMentionIndex,
|
index: firstMatchIndex,
|
||||||
mention: firstMention,
|
length: firstMatchLength,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,3 +287,39 @@ function wrapNode(wrapper: any, node: any) {
|
|||||||
wrapper._lastChild = node;
|
wrapper._lastChild = node;
|
||||||
node._parent = wrapper;
|
node._parent = wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseTaskLists(ast: Node) {
|
||||||
|
const walker = ast.walker();
|
||||||
|
|
||||||
|
let e;
|
||||||
|
while ((e = walker.next())) {
|
||||||
|
if (!e.entering) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const node = e.node;
|
||||||
|
|
||||||
|
if (node.type !== 'item') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.firstChild?.type === 'paragraph' && node.firstChild?.firstChild?.type === 'text') {
|
||||||
|
const paragraphNode = node.firstChild;
|
||||||
|
const textNode = node.firstChild.firstChild;
|
||||||
|
|
||||||
|
const literal = textNode.literal ?? '';
|
||||||
|
|
||||||
|
const match = (/^ {0,3}\[( |x)\]\s/).exec(literal);
|
||||||
|
if (match) {
|
||||||
|
const checkbox = new Node('checkbox');
|
||||||
|
checkbox.isChecked = match[1] === 'x';
|
||||||
|
|
||||||
|
paragraphNode.prependChild(checkbox);
|
||||||
|
|
||||||
|
textNode.literal = literal.substring(match[0].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|||||||
@@ -50,6 +50,21 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const searchPatterns = [
|
||||||
|
{
|
||||||
|
pattern: /\bMattermost\b/,
|
||||||
|
term: 'Mattermost',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /\bbug\b/i,
|
||||||
|
term: 'bug',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /\bboat/,
|
||||||
|
term: 'boat',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const Message = ({currentUser, highlight, isEdited, isPendingOrFailed, isReplyPost, layoutWidth, location, post, theme}: MessageProps) => {
|
const Message = ({currentUser, highlight, isEdited, isPendingOrFailed, isReplyPost, layoutWidth, location, post, theme}: MessageProps) => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [height, setHeight] = useState<number|undefined>();
|
const [height, setHeight] = useState<number|undefined>();
|
||||||
@@ -94,6 +109,7 @@ const Message = ({currentUser, highlight, isEdited, isPendingOrFailed, isReplyPo
|
|||||||
textStyles={textStyles}
|
textStyles={textStyles}
|
||||||
value={post.message}
|
value={post.message}
|
||||||
mentionKeys={mentionKeys}
|
mentionKeys={mentionKeys}
|
||||||
|
searchPatterns={searchPatterns}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -104,7 +104,10 @@ export const getMarkdownTextStyles = makeStyleSheetFromTheme((theme: Theme) => {
|
|||||||
fontFamily: 'OpenSans-Bold',
|
fontFamily: 'OpenSans-Bold',
|
||||||
},
|
},
|
||||||
mention_highlight: {
|
mention_highlight: {
|
||||||
fontFamily: 'OpenSans',
|
backgroundColor: theme.mentionHighlightBg,
|
||||||
|
color: theme.mentionHighlightLink,
|
||||||
|
},
|
||||||
|
search_highlight: {
|
||||||
backgroundColor: theme.mentionHighlightBg,
|
backgroundColor: theme.mentionHighlightBg,
|
||||||
color: theme.mentionHighlightLink,
|
color: theme.mentionHighlightLink,
|
||||||
},
|
},
|
||||||
|
|||||||
79
package-lock.json
generated
79
package-lock.json
generated
@@ -33,8 +33,8 @@
|
|||||||
"@sentry/react-native": "3.4.0",
|
"@sentry/react-native": "3.4.0",
|
||||||
"@stream-io/flat-list-mvcp": "0.10.1",
|
"@stream-io/flat-list-mvcp": "0.10.1",
|
||||||
"base-64": "1.0.0",
|
"base-64": "1.0.0",
|
||||||
"commonmark": "github:mattermost/commonmark.js#d1003be97d15414af6c21894125623c45e3f5096",
|
"commonmark": "npm:@mattermost/commonmark@0.30.1-0",
|
||||||
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
|
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#2c660491041f7595f6ce5a05f6dc2e30ca769d3a",
|
||||||
"deep-equal": "2.0.5",
|
"deep-equal": "2.0.5",
|
||||||
"deepmerge": "4.2.2",
|
"deepmerge": "4.2.2",
|
||||||
"emoji-regex": "10.1.0",
|
"emoji-regex": "10.1.0",
|
||||||
@@ -3009,6 +3009,37 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mattermost/commonmark": {
|
||||||
|
"version": "0.30.1-0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mattermost/commonmark/-/commonmark-0.30.1-0.tgz",
|
||||||
|
"integrity": "sha512-0+qW22COfd/BA81TQ05nQMfhmnuRAkv/vwCbs3iFVTEj7mTunYRwWUyb5M8K849V2VXdLdrS8htsBtIHDb2H7g==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"entities": "~3.0.1",
|
||||||
|
"mdurl": "~1.0.1",
|
||||||
|
"minimist": "~1.2.5",
|
||||||
|
"string.prototype.repeat": "^1.0.0",
|
||||||
|
"xregexp": "5.1.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"commonmark": "bin/commonmark"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mattermost/commonmark/node_modules/entities": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@mattermost/compass-icons": {
|
"node_modules/@mattermost/compass-icons": {
|
||||||
"version": "0.1.22",
|
"version": "0.1.22",
|
||||||
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.22.tgz",
|
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.22.tgz",
|
||||||
@@ -8519,9 +8550,10 @@
|
|||||||
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
|
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
|
||||||
},
|
},
|
||||||
"node_modules/commonmark": {
|
"node_modules/commonmark": {
|
||||||
"version": "0.30.0",
|
"name": "@mattermost/commonmark",
|
||||||
"resolved": "git+ssh://git@github.com/mattermost/commonmark.js.git#d1003be97d15414af6c21894125623c45e3f5096",
|
"version": "0.30.1-0",
|
||||||
"license": "BSD-2-Clause",
|
"resolved": "https://registry.npmjs.org/@mattermost/commonmark/-/commonmark-0.30.1-0.tgz",
|
||||||
|
"integrity": "sha512-0+qW22COfd/BA81TQ05nQMfhmnuRAkv/vwCbs3iFVTEj7mTunYRwWUyb5M8K849V2VXdLdrS8htsBtIHDb2H7g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"entities": "~3.0.1",
|
"entities": "~3.0.1",
|
||||||
"mdurl": "~1.0.1",
|
"mdurl": "~1.0.1",
|
||||||
@@ -8538,7 +8570,9 @@
|
|||||||
},
|
},
|
||||||
"node_modules/commonmark-react-renderer": {
|
"node_modules/commonmark-react-renderer": {
|
||||||
"version": "4.3.5",
|
"version": "4.3.5",
|
||||||
"resolved": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
|
"resolved": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#2c660491041f7595f6ce5a05f6dc2e30ca769d3a",
|
||||||
|
"integrity": "sha512-D++d6UFNLyu4fAAZg6blRb3rkiG+bFWKJ8fSLOJwzBit3Hm/sPZbx2QQeKfx+IHoMg7cCvHlesAT1+kB/+kBLQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lodash.assign": "^4.2.0",
|
"lodash.assign": "^4.2.0",
|
||||||
"lodash.isplainobject": "^4.0.6",
|
"lodash.isplainobject": "^4.0.6",
|
||||||
@@ -8546,7 +8580,7 @@
|
|||||||
"xss-filters": "^1.2.6"
|
"xss-filters": "^1.2.6"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"commonmark": "^0.30.0",
|
"@mattermost/commonmark": "*",
|
||||||
"react": ">=0.14.0"
|
"react": ">=0.14.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -25685,6 +25719,27 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@mattermost/commonmark": {
|
||||||
|
"version": "0.30.1-0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mattermost/commonmark/-/commonmark-0.30.1-0.tgz",
|
||||||
|
"integrity": "sha512-0+qW22COfd/BA81TQ05nQMfhmnuRAkv/vwCbs3iFVTEj7mTunYRwWUyb5M8K849V2VXdLdrS8htsBtIHDb2H7g==",
|
||||||
|
"peer": true,
|
||||||
|
"requires": {
|
||||||
|
"entities": "~3.0.1",
|
||||||
|
"mdurl": "~1.0.1",
|
||||||
|
"minimist": "~1.2.5",
|
||||||
|
"string.prototype.repeat": "^1.0.0",
|
||||||
|
"xregexp": "5.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"entities": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
|
||||||
|
"peer": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@mattermost/compass-icons": {
|
"@mattermost/compass-icons": {
|
||||||
"version": "0.1.22",
|
"version": "0.1.22",
|
||||||
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.22.tgz",
|
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.22.tgz",
|
||||||
@@ -29934,8 +29989,9 @@
|
|||||||
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
|
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
|
||||||
},
|
},
|
||||||
"commonmark": {
|
"commonmark": {
|
||||||
"version": "git+ssh://git@github.com/mattermost/commonmark.js.git#d1003be97d15414af6c21894125623c45e3f5096",
|
"version": "npm:@mattermost/commonmark@0.30.1-0",
|
||||||
"from": "commonmark@github:mattermost/commonmark.js#d1003be97d15414af6c21894125623c45e3f5096",
|
"resolved": "https://registry.npmjs.org/@mattermost/commonmark/-/commonmark-0.30.1-0.tgz",
|
||||||
|
"integrity": "sha512-0+qW22COfd/BA81TQ05nQMfhmnuRAkv/vwCbs3iFVTEj7mTunYRwWUyb5M8K849V2VXdLdrS8htsBtIHDb2H7g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"entities": "~3.0.1",
|
"entities": "~3.0.1",
|
||||||
"mdurl": "~1.0.1",
|
"mdurl": "~1.0.1",
|
||||||
@@ -29952,8 +30008,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commonmark-react-renderer": {
|
"commonmark-react-renderer": {
|
||||||
"version": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
|
"version": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#2c660491041f7595f6ce5a05f6dc2e30ca769d3a",
|
||||||
"from": "commonmark-react-renderer@github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
|
"integrity": "sha512-D++d6UFNLyu4fAAZg6blRb3rkiG+bFWKJ8fSLOJwzBit3Hm/sPZbx2QQeKfx+IHoMg7cCvHlesAT1+kB/+kBLQ==",
|
||||||
|
"from": "commonmark-react-renderer@github:mattermost/commonmark-react-renderer#2c660491041f7595f6ce5a05f6dc2e30ca769d3a",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lodash.assign": "^4.2.0",
|
"lodash.assign": "^4.2.0",
|
||||||
"lodash.isplainobject": "^4.0.6",
|
"lodash.isplainobject": "^4.0.6",
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
"@sentry/react-native": "3.4.0",
|
"@sentry/react-native": "3.4.0",
|
||||||
"@stream-io/flat-list-mvcp": "0.10.1",
|
"@stream-io/flat-list-mvcp": "0.10.1",
|
||||||
"base-64": "1.0.0",
|
"base-64": "1.0.0",
|
||||||
"commonmark": "github:mattermost/commonmark.js#d1003be97d15414af6c21894125623c45e3f5096",
|
"commonmark": "npm:@mattermost/commonmark@0.30.1-0",
|
||||||
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
|
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#2c660491041f7595f6ce5a05f6dc2e30ca769d3a",
|
||||||
"deep-equal": "2.0.5",
|
"deep-equal": "2.0.5",
|
||||||
"deepmerge": "4.2.2",
|
"deepmerge": "4.2.2",
|
||||||
"emoji-regex": "10.1.0",
|
"emoji-regex": "10.1.0",
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
diff --git a/node_modules/@types/commonmark/index.d.ts b/node_modules/@types/commonmark/index.d.ts
|
|
||||||
index 35e9ed6..382cf98 100755
|
|
||||||
--- a/node_modules/@types/commonmark/index.d.ts
|
|
||||||
+++ b/node_modules/@types/commonmark/index.d.ts
|
|
||||||
@@ -5,8 +5,8 @@
|
|
||||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
||||||
|
|
||||||
export type NodeType =
|
|
||||||
- 'text' |'softbreak' | 'linebreak' | 'emph' | 'strong' | 'html_inline' | 'link' | 'image' | 'code' | 'document' | 'paragraph' |
|
|
||||||
- 'block_quote' | 'item' | 'list' | 'heading' | 'code_block' | 'html_block' | 'thematic_break' | 'custom_inline' | 'custom_block';
|
|
||||||
+ 'text' |'softbreak' | 'linebreak' | 'emph' | 'strong' | 'html_inline' | 'link' | 'image' | 'code' | 'document' | 'paragraph' | 'mention_highlight' | 'at_mention' |
|
|
||||||
+ 'block_quote' | 'item' | 'list' | 'heading' | 'code_block' | 'html_block' | 'thematic_break' | 'custom_inline' | 'custom_block' | 'table' | 'edited_indicator';
|
|
||||||
|
|
||||||
export class Node {
|
|
||||||
constructor(nodeType: NodeType, sourcepos?: Position);
|
|
||||||
@@ -125,6 +125,8 @@ export class Node {
|
|
||||||
* https://github.com/jgm/commonmark.js/issues/74
|
|
||||||
*/
|
|
||||||
_listData: ListData;
|
|
||||||
+
|
|
||||||
+ mentionName?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@@ -200,6 +202,8 @@ export interface ParserOptions {
|
|
||||||
*/
|
|
||||||
smart?: boolean | undefined;
|
|
||||||
time?: boolean | undefined;
|
|
||||||
+ urlFilter?: (url: string) => boolean;
|
|
||||||
+ minimumHashtagLength?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HtmlRenderingOptions extends XmlRenderingOptions {
|
|
||||||
@@ -3,7 +3,12 @@
|
|||||||
|
|
||||||
import {TextStyle, ViewStyle} from 'react-native';
|
import {TextStyle, ViewStyle} from 'react-native';
|
||||||
|
|
||||||
export type UserMentionKey= {
|
export type SearchPattern = {
|
||||||
|
pattern: RegExp;
|
||||||
|
term: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UserMentionKey = {
|
||||||
key: string;
|
key: string;
|
||||||
caseSensitive?: boolean;
|
caseSensitive?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user