diff --git a/app/components/markdown/markdown.tsx b/app/components/markdown/markdown.tsx
index 69d93f046..9bcd2292a 100644
--- a/app/components/markdown/markdown.tsx
+++ b/app/components/markdown/markdown.tsx
@@ -6,10 +6,11 @@ import Renderer from 'commonmark-react-renderer';
import React, {ReactElement, useRef} from 'react';
import {Dimensions, GestureResponderEvent, Platform, StyleProp, Text, TextStyle, View} from 'react-native';
+import CompassIcon from '@components/compass_icon';
import Emoji from '@components/emoji';
import FormattedText from '@components/formatted_text';
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 AtMention from './at_mention';
@@ -26,11 +27,11 @@ import MarkdownTable from './markdown_table';
import MarkdownTableCell, {MarkdownTableCellProps} from './markdown_table_cell';
import MarkdownTableImage from './markdown_table_image';
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 {
MarkdownAtMentionRenderer, MarkdownBaseRenderer, MarkdownBlockStyles, MarkdownChannelMentionRenderer,
- MarkdownEmojiRenderer, MarkdownImageRenderer, MarkdownLatexRenderer, MarkdownTextStyles, UserMentionKey,
+ MarkdownEmojiRenderer, MarkdownImageRenderer, MarkdownLatexRenderer, MarkdownTextStyles, SearchPattern, UserMentionKey,
} from '@typings/global/markdown';
type MarkdownProps = {
@@ -55,6 +56,7 @@ type MarkdownProps = {
minimumHashtagLength?: number;
onPostPress?: (event: GestureResponderEvent) => void;
postId?: string;
+ searchPatterns?: SearchPattern[];
textStyles?: MarkdownTextStyles;
theme: Theme;
value?: string | number;
@@ -100,6 +102,10 @@ const getExtraPropsForNode = (node: any) => {
extraProps.size = node.size;
}
+ if (node.type === 'checkbox') {
+ extraProps.isChecked = node.isChecked;
+ }
+
return extraProps;
};
@@ -113,7 +119,7 @@ const Markdown = ({
disableAtChannelMentionHighlight = false, disableAtMentions = false, disableChannelLink = false,
disableGallery = false, disableHashtags = false, enableInlineLatex, enableLatex,
imagesMetadata, isEdited, isReplyPost, isSearchResult, layoutWidth,
- location, mentionKeys, minimumHashtagLength = 3, onPostPress, postId,
+ location, mentionKeys, minimumHashtagLength = 3, onPostPress, postId, searchPatterns,
textStyles = {}, theme, value = '',
}: MarkdownProps) => {
const style = getStyleSheet(theme);
@@ -171,6 +177,19 @@ const Markdown = ({
);
};
+ const renderCheckbox = ({isChecked}: {isChecked: boolean}) => {
+ return (
+
+
+ {' '}
+
+ );
+ };
+
const renderCodeBlock = (props: any) => {
// These sometimes include a trailing newline
const content = props.literal.replace(/\n$/, '');
@@ -463,6 +482,8 @@ const Markdown = ({
table_cell: renderTableCell,
mention_highlight: Renderer.forwardChildren,
+ search_highlight: Renderer.forwardChildren,
+ checkbox: renderCheckbox,
editedIndicator: renderEditedIndicator,
};
@@ -471,6 +492,7 @@ const Markdown = ({
renderers,
renderParagraphsInLists: true,
getExtraPropsForNode,
+ allowedTypes: Object.keys(renderers),
});
};
@@ -481,9 +503,13 @@ const Markdown = ({
ast = combineTextNodes(ast);
ast = addListItemIndices(ast);
ast = pullOutImages(ast);
+ ast = parseTaskLists(ast);
if (mentionKeys) {
ast = highlightMentions(ast, mentionKeys);
}
+ if (searchPatterns) {
+ ast = highlightSearchPatterns(ast, searchPatterns);
+ }
if (isEdited) {
const editIndicatorNode = new Node('edited_indicator');
diff --git a/app/components/markdown/transform.test.ts b/app/components/markdown/transform.test.ts
index ab487325a..0b5138584 100644
--- a/app/components/markdown/transform.test.ts
+++ b/app/components/markdown/transform.test.ts
@@ -8,12 +8,15 @@ import {Node, Parser} from 'commonmark';
import {
addListItemIndices,
combineTextNodes,
- getFirstMention,
+ getFirstMatch,
highlightMentions,
highlightTextNode,
+ mentionKeysToPatterns,
pullOutImages,
} from '@components/markdown/transform';
+import type {UserMentionKey} from '@typings/global/markdown';
+
/* eslint-disable max-lines, no-console, no-underscore-dangle */
describe('Components.Markdown.transform', () => {
@@ -2623,64 +2626,69 @@ describe('Components.Markdown.transform', () => {
name: 'no mention keys',
input: 'apple banana orange',
mentionKeys: [],
- expected: {index: -1, mention: null},
+ expected: {index: -1, length: -1},
}, {
name: 'single mention',
input: 'apple banana orange',
mentionKeys: [{key: 'banana'}],
- expected: {index: 6, mention: {key: 'banana'}},
+ expected: {index: 6, length: 6},
}, {
name: 'multiple mentions',
input: 'apple banana orange',
mentionKeys: [{key: 'apple'}, {key: 'orange'}],
- expected: {index: 0, mention: {key: 'apple'}},
+ expected: {index: 0, length: 5},
}, {
name: 'case sensitive',
input: 'apple APPLE Apple aPPle',
mentionKeys: [{key: 'Apple', caseSensitive: true}],
- expected: {index: 12, mention: {key: 'Apple', caseSensitive: true}},
+ expected: {index: 12, length: 5},
}, {
name: 'followed by period',
input: 'banana.',
mentionKeys: [{key: 'banana'}],
- expected: {index: 0, mention: {key: 'banana'}},
+ expected: {index: 0, length: 6},
}, {
name: 'followed by underscores',
input: 'banana__',
mentionKeys: [{key: 'banana'}],
- expected: {index: 0, mention: {key: 'banana'}},
+ expected: {index: 0, length: 6},
}, {
name: 'in brackets',
input: '(banana)',
mentionKeys: [{key: 'banana'}],
- expected: {index: 1, mention: {key: 'banana'}},
+ expected: {index: 1, length: 6},
}, {
name: 'following punctuation',
input: ':banana',
mentionKeys: [{key: 'banana'}],
- expected: {index: 1, mention: {key: 'banana'}},
+ expected: {index: 1, length: 6},
}, {
name: 'not part of another word',
input: 'pineapple',
mentionKeys: [{key: 'apple'}],
- expected: {index: -1, mention: null},
+ expected: {index: -1, length: -1},
}, {
name: 'no error from weird mention keys',
input: 'apple banana orange',
mentionKeys: [{key: '*\\3_.'}],
- expected: {index: -1, mention: null},
+ expected: {index: -1, length: -1},
}, {
name: 'no blank mention keys',
input: 'apple banana orange',
mentionKeys: [{key: ''}],
- expected: {index: -1, mention: null},
+ expected: {index: -1, length: -1},
}, {
name: 'multibyte key',
input: '좋은 하루 되세요.',
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) {
it(test.name, () => {
const actual = getFirstMention(test.input, test.mentionKeys);
diff --git a/app/components/markdown/transform.ts b/app/components/markdown/transform.ts
index 18aaa2096..d5ddf5e14 100644
--- a/app/components/markdown/transform.ts
+++ b/app/components/markdown/transform.ts
@@ -5,7 +5,7 @@ import {Node, NodeType} from 'commonmark';
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 */
@@ -114,6 +114,8 @@ function pullOutImage(image: any) {
export function highlightMentions(ast: Node, mentionKeys: UserMentionKey[]) {
const walker = ast.walker();
+ const patterns = mentionKeysToPatterns(mentionKeys);
+
let e;
while ((e = walker.next())) {
if (!e.entering) {
@@ -123,13 +125,13 @@ export function highlightMentions(ast: Node, mentionKeys: UserMentionKey[]) {
const node = e.node;
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;
}
- 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
// that was part of this one
@@ -158,38 +160,71 @@ export function highlightMentions(ast: Node, mentionKeys: UserMentionKey[]) {
return ast;
}
-// Given a string and an array of mention keys, returns the first mention that appears and its index.
-export function getFirstMention(str: string, mentionKeys: UserMentionKey[]) {
- let firstMention = null;
- let firstMentionIndex = -1;
-
- for (const mention of mentionKeys) {
- if (mention.key.trim() === '') {
- continue;
- }
-
+export function mentionKeysToPatterns(mentionKeys: UserMentionKey[]) {
+ return mentionKeys.filter((mention) => mention.key.trim() !== '').map((mention) => {
const flags = mention.caseSensitive ? '' : 'i';
let pattern;
if (cjkPattern.test(mention.key)) {
pattern = new RegExp(`${escapeRegex(mention.key)}`, flags);
} 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 regexes, 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);
if (!match || match[0] === '') {
continue;
}
- if (firstMentionIndex === -1 || match.index < firstMentionIndex) {
- firstMentionIndex = match.index;
- firstMention = mention;
+ if (firstMatchIndex === -1 || match.index < firstMatchIndex) {
+ firstMatchIndex = match.index;
+ firstMatchLength = match[0].length;
}
}
return {
- index: firstMentionIndex,
- mention: firstMention,
+ index: firstMatchIndex,
+ length: firstMatchLength,
};
}
@@ -252,3 +287,39 @@ function wrapNode(wrapper: any, node: any) {
wrapper._lastChild = node;
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;
+}
diff --git a/app/components/post_list/post/body/index.tsx b/app/components/post_list/post/body/index.tsx
index d440b50ca..c9450e77a 100644
--- a/app/components/post_list/post/body/index.tsx
+++ b/app/components/post_list/post/body/index.tsx
@@ -19,6 +19,7 @@ import Message from './message';
import Reactions from './reactions';
import type PostModel from '@typings/database/models/servers/post';
+import type {SearchPattern} from '@typings/global/markdown';
type BodyProps = {
appsEnabled: boolean;
@@ -34,6 +35,7 @@ type BodyProps = {
isPostAddChannelMember: boolean;
location: string;
post: PostModel;
+ searchPatterns?: SearchPattern[];
showAddReaction?: boolean;
theme: Theme;
};
@@ -74,7 +76,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
const Body = ({
appsEnabled, filesCount, hasReactions, highlight, highlightReplyBar,
isEphemeral, isFirstReply, isJumboEmoji, isLastReply, isPendingOrFailed, isPostAddChannelMember,
- location, post, showAddReaction, theme,
+ location, post, searchPatterns, showAddReaction, theme,
}: BodyProps) => {
const style = getStyleSheet(theme);
const isEdited = postEdited(post);
@@ -147,6 +149,7 @@ const Body = ({
layoutWidth={layoutWidth}
location={location}
post={post}
+ searchPatterns={searchPatterns}
theme={theme}
/>
);
diff --git a/app/components/post_list/post/body/message/message.tsx b/app/components/post_list/post/body/message/message.tsx
index 8a0bbb5be..350a16dc6 100644
--- a/app/components/post_list/post/body/message/message.tsx
+++ b/app/components/post_list/post/body/message/message.tsx
@@ -15,6 +15,7 @@ import ShowMoreButton from './show_more_button';
import type PostModel from '@typings/database/models/servers/post';
import type UserModel from '@typings/database/models/servers/user';
+import type {SearchPattern} from '@typings/global/markdown';
type MessageProps = {
currentUser: UserModel;
@@ -25,6 +26,7 @@ type MessageProps = {
layoutWidth?: number;
location: string;
post: PostModel;
+ searchPatterns?: SearchPattern[];
theme: Theme;
}
@@ -50,7 +52,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
};
});
-const Message = ({currentUser, highlight, isEdited, isPendingOrFailed, isReplyPost, layoutWidth, location, post, theme}: MessageProps) => {
+const Message = ({currentUser, highlight, isEdited, isPendingOrFailed, isReplyPost, layoutWidth, location, post, searchPatterns, theme}: MessageProps) => {
const [open, setOpen] = useState(false);
const [height, setHeight] = useState();
const dimensions = useWindowDimensions();
@@ -94,6 +96,7 @@ const Message = ({currentUser, highlight, isEdited, isPendingOrFailed, isReplyPo
textStyles={textStyles}
value={post.message}
mentionKeys={mentionKeys}
+ searchPatterns={searchPatterns}
theme={theme}
/>
diff --git a/app/components/post_list/post/post.tsx b/app/components/post_list/post/post.tsx
index 7d0b5bc72..9dae96f15 100644
--- a/app/components/post_list/post/post.tsx
+++ b/app/components/post_list/post/post.tsx
@@ -31,6 +31,7 @@ import UnreadDot from './unread_dot';
import type PostModel from '@typings/database/models/servers/post';
import type ThreadModel from '@typings/database/models/servers/thread';
import type UserModel from '@typings/database/models/servers/user';
+import type {SearchPattern} from '@typings/global/markdown';
type PostProps = {
appsEnabled: boolean;
@@ -54,6 +55,7 @@ type PostProps = {
post: PostModel;
previousPost?: PostModel;
reactionsCount: number;
+ searchPatterns?: SearchPattern[];
shouldRenderReplyButton?: boolean;
showAddReaction?: boolean;
skipSavedHeader?: boolean;
@@ -104,7 +106,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
const Post = ({
appsEnabled, canDelete, currentUser, differentThreadSequence, filesCount, hasReplies, highlight, highlightPinnedOrSaved = true, highlightReplyBar,
isCRTEnabled, isConsecutivePost, isEphemeral, isFirstReply, isSaved, isJumboEmoji, isLastReply, isPostAddChannelMember,
- location, post, reactionsCount, shouldRenderReplyButton, skipSavedHeader, skipPinnedHeader, showAddReaction = true, style,
+ location, post, reactionsCount, searchPatterns, shouldRenderReplyButton, skipSavedHeader, skipPinnedHeader, showAddReaction = true, style,
testID, thread, previousPost,
}: PostProps) => {
const pressDetected = useRef(false);
@@ -283,6 +285,7 @@ const Post = ({
isPostAddChannelMember={isPostAddChannelMember}
location={location}
post={post}
+ searchPatterns={searchPatterns}
showAddReaction={showAddReaction}
theme={theme}
/>
diff --git a/app/utils/markdown/index.ts b/app/utils/markdown/index.ts
index 1f5720747..865faae08 100644
--- a/app/utils/markdown/index.ts
+++ b/app/utils/markdown/index.ts
@@ -98,7 +98,10 @@ export const getMarkdownTextStyles = makeStyleSheetFromTheme((theme: Theme) => {
fontFamily: 'OpenSans-Bold',
},
mention_highlight: {
- fontFamily: 'OpenSans',
+ backgroundColor: theme.mentionHighlightBg,
+ color: theme.mentionHighlightLink,
+ },
+ search_highlight: {
backgroundColor: theme.mentionHighlightBg,
color: theme.mentionHighlightLink,
},
diff --git a/package-lock.json b/package-lock.json
index 42b031da2..ac5ed1288 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -34,8 +34,8 @@
"@sentry/react-native": "3.4.2",
"@stream-io/flat-list-mvcp": "0.10.2",
"base-64": "1.0.0",
- "commonmark": "github:mattermost/commonmark.js#d1003be97d15414af6c21894125623c45e3f5096",
- "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
+ "commonmark": "npm:@mattermost/commonmark@0.30.1-0",
+ "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#2c660491041f7595f6ce5a05f6dc2e30ca769d3a",
"deep-equal": "2.0.5",
"deepmerge": "4.2.2",
"emoji-regex": "10.1.0",
@@ -4021,6 +4021,37 @@
"@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": {
"version": "0.1.23",
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.23.tgz",
@@ -9441,9 +9472,10 @@
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
},
"node_modules/commonmark": {
- "version": "0.30.0",
- "resolved": "git+ssh://git@github.com/mattermost/commonmark.js.git#d1003be97d15414af6c21894125623c45e3f5096",
- "license": "BSD-2-Clause",
+ "name": "@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==",
"dependencies": {
"entities": "~3.0.1",
"mdurl": "~1.0.1",
@@ -9460,7 +9492,9 @@
},
"node_modules/commonmark-react-renderer": {
"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": {
"lodash.assign": "^4.2.0",
"lodash.isplainobject": "^4.0.6",
@@ -9468,7 +9502,7 @@
"xss-filters": "^1.2.6"
},
"peerDependencies": {
- "commonmark": "^0.30.0",
+ "@mattermost/commonmark": "*",
"react": ">=0.14.0"
}
},
@@ -28684,6 +28718,27 @@
"@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": {
"version": "0.1.23",
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.23.tgz",
@@ -32868,8 +32923,9 @@
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
},
"commonmark": {
- "version": "git+ssh://git@github.com/mattermost/commonmark.js.git#d1003be97d15414af6c21894125623c45e3f5096",
- "from": "commonmark@github:mattermost/commonmark.js#d1003be97d15414af6c21894125623c45e3f5096",
+ "version": "npm:@mattermost/commonmark@0.30.1-0",
+ "resolved": "https://registry.npmjs.org/@mattermost/commonmark/-/commonmark-0.30.1-0.tgz",
+ "integrity": "sha512-0+qW22COfd/BA81TQ05nQMfhmnuRAkv/vwCbs3iFVTEj7mTunYRwWUyb5M8K849V2VXdLdrS8htsBtIHDb2H7g==",
"requires": {
"entities": "~3.0.1",
"mdurl": "~1.0.1",
@@ -32886,8 +32942,9 @@
}
},
"commonmark-react-renderer": {
- "version": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
- "from": "commonmark-react-renderer@github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
+ "version": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#2c660491041f7595f6ce5a05f6dc2e30ca769d3a",
+ "integrity": "sha512-D++d6UFNLyu4fAAZg6blRb3rkiG+bFWKJ8fSLOJwzBit3Hm/sPZbx2QQeKfx+IHoMg7cCvHlesAT1+kB/+kBLQ==",
+ "from": "commonmark-react-renderer@github:mattermost/commonmark-react-renderer#2c660491041f7595f6ce5a05f6dc2e30ca769d3a",
"requires": {
"lodash.assign": "^4.2.0",
"lodash.isplainobject": "^4.0.6",
diff --git a/package.json b/package.json
index 266bb04ab..713ecec65 100644
--- a/package.json
+++ b/package.json
@@ -31,8 +31,8 @@
"@sentry/react-native": "3.4.2",
"@stream-io/flat-list-mvcp": "0.10.2",
"base-64": "1.0.0",
- "commonmark": "github:mattermost/commonmark.js#d1003be97d15414af6c21894125623c45e3f5096",
- "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d",
+ "commonmark": "npm:@mattermost/commonmark@0.30.1-0",
+ "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#2c660491041f7595f6ce5a05f6dc2e30ca769d3a",
"deep-equal": "2.0.5",
"deepmerge": "4.2.2",
"emoji-regex": "10.1.0",
diff --git a/patches/@types+commonmark+0.27.5.patch b/patches/@types+commonmark+0.27.5.patch
deleted file mode 100644
index 87b658f35..000000000
--- a/patches/@types+commonmark+0.27.5.patch
+++ /dev/null
@@ -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 {
diff --git a/types/global/markdown.ts b/types/global/markdown.ts
index f76b89d9f..a478b1128 100644
--- a/types/global/markdown.ts
+++ b/types/global/markdown.ts
@@ -3,7 +3,12 @@
import {TextStyle, ViewStyle} from 'react-native';
-export type UserMentionKey= {
+export type SearchPattern = {
+ pattern: RegExp;
+ term: string;
+};
+
+export type UserMentionKey = {
key: string;
caseSensitive?: boolean;
};