stream-chat-react-native-core
Version:
The official React Native and Expo components for Stream Chat, a service for building chat applications
632 lines • 21.4 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.renderText = exports.MarkdownReactiveScrollView = exports.ListOutput = void 0;
var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _reactNativeGestureHandler = require("react-native-gesture-handler");
var _reactNativeMarkdownPackage = _interopRequireDefault(require("react-native-markdown-package"));
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
var _simpleMarkdown = require("simple-markdown");
var _generateMarkdownText = require("./generateMarkdownText");
var _theme = require("../../../../theme");
var _utils = require("../../../../utils/utils");
var _jsxRuntime = require("react/jsx-runtime");
var _jsxFileName = "/home/runner/work/stream-chat-react-native/stream-chat-react-native/package/src/components/Message/MessageItemView/utils/renderText.tsx";
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
var MarkdownReactiveScrollView = ({
children
}) => {
var scrollViewRef = (0, _reactNativeReanimated.useAnimatedRef)();
var contentWidth = (0, _reactNativeReanimated.useSharedValue)(0);
var visibleContentWidth = (0, _reactNativeReanimated.useSharedValue)(0);
var offsetBeforeScroll = (0, _reactNativeReanimated.useSharedValue)(0);
var panGesture = _reactNativeGestureHandler.Gesture.Pan().activeOffsetX([-5, 5]).onUpdate(event => {
var translationX = event.translationX;
(0, _reactNativeReanimated.scrollTo)(scrollViewRef, offsetBeforeScroll.value - translationX, 0, false);
}).onEnd(event => {
var translationX = event.translationX;
var velocityEffect = event.velocityX * 0.3;
var finalPosition = (0, _reactNativeReanimated.clamp)(offsetBeforeScroll.value - translationX - velocityEffect, 0, contentWidth.value - visibleContentWidth.value);
offsetBeforeScroll.value = finalPosition;
(0, _reactNativeReanimated.scrollTo)(scrollViewRef, finalPosition, 0, true);
});
return (0, _jsxRuntime.jsx)(_reactNative.View, {
style: {
width: '100%'
},
children: (0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, {
gesture: panGesture,
children: (0, _jsxRuntime.jsx)(_reactNativeReanimated.default.ScrollView, {
contentContainerStyle: {
flexGrow: 1
},
horizontal: true,
nestedScrollEnabled: true,
onContentSizeChange: width => {
contentWidth.value = width;
},
onLayout: e => {
visibleContentWidth.value = e.nativeEvent.layout.width;
},
ref: scrollViewRef,
scrollEnabled: false,
children: children
})
})
});
};
exports.MarkdownReactiveScrollView = MarkdownReactiveScrollView;
var defaultMarkdownStyles = {
codeBlock: {
fontFamily: _reactNative.Platform.OS === 'ios' ? 'Courier' : 'Monospace',
fontWeight: '500',
marginVertical: _theme.primitives.spacingXs,
fontSize: _theme.primitives.typographyFontSizeMd,
lineHeight: _theme.primitives.typographyLineHeightNormal
},
heading1: {
fontSize: _theme.primitives.typographyFontSizeMd * 2,
lineHeight: _theme.primitives.typographyFontSizeMd * 2 * 1.25
},
heading2: {
fontSize: _theme.primitives.typographyFontSizeMd * 1.5,
lineHeight: _theme.primitives.typographyFontSizeMd * 1.5 * 1.25
},
heading3: {
fontSize: _theme.primitives.typographyFontSizeMd * 1.25,
lineHeight: _theme.primitives.typographyFontSizeMd * 1.25 * 1.25
},
heading4: {
fontSize: _theme.primitives.typographyFontSizeMd,
lineHeight: _theme.primitives.typographyFontSizeMd * 1.25
},
heading5: {
fontSize: _theme.primitives.typographyFontSizeMd * 0.875,
lineHeight: _theme.primitives.typographyFontSizeMd * 0.875 * 1.25
},
heading6: {
fontSize: _theme.primitives.typographyFontSizeMd * 0.75,
lineHeight: _theme.primitives.typographyFontSizeMd * 0.75 * 1.25
},
inlineCode: {
padding: _theme.primitives.spacingXxs,
paddingHorizontal: _theme.primitives.spacingXxs,
fontSize: _theme.primitives.typographyFontSizeMd,
lineHeight: _theme.primitives.typographyLineHeightNormal
},
list: {
marginBottom: _theme.primitives.spacingXs,
marginTop: _theme.primitives.spacingXs
},
listItemNumber: {
fontWeight: 'bold'
},
listItemText: {
flex: 0
},
listRow: {
flexDirection: 'row'
},
mentions: {
fontWeight: _theme.primitives.typographyFontWeightRegular,
fontSize: _theme.primitives.typographyFontSizeMd,
lineHeight: _theme.primitives.typographyLineHeightNormal
},
paragraph: {
marginBottom: _theme.primitives.spacingXs,
fontSize: _theme.primitives.typographyFontSizeMd,
marginTop: _theme.primitives.spacingXs
},
paragraphCenter: {
marginBottom: _theme.primitives.spacingXs,
fontSize: _theme.primitives.typographyFontSizeMd,
marginTop: _theme.primitives.spacingXs
},
paragraphWithImage: {
marginBottom: _theme.primitives.spacingXs,
marginTop: _theme.primitives.spacingXs
},
table: {
borderRadius: _theme.primitives.radiusXxs,
borderWidth: 1,
flex: 1,
flexDirection: 'row'
},
tableHeader: {
flexDirection: 'row',
justifyContent: 'space-around'
},
tableHeaderCell: {
fontWeight: '500'
},
tableRow: {
alignItems: 'center',
justifyContent: 'space-around'
},
tableRowCell: {
flex: 1
}
};
var mentionsParseFunction = (capture, parse, state) => ({
content: (0, _simpleMarkdown.parseInline)(parse, capture[0], state)
});
var renderText = params => {
var semantics = params.semantics,
markdownRules = params.markdownRules,
markdownStyles = params.markdownStyles,
message = params.message,
messageOverlay = params.messageOverlay,
messageTextNumberOfLines = params.messageTextNumberOfLines,
onLinkParams = params.onLink,
onLongPressParam = params.onLongPress,
onlyEmojis = params.onlyEmojis,
onPressParam = params.onPress,
preventPress = params.preventPress,
isMyMessage = params.isMyMessage;
var text = message.text;
var markdownText = (0, _generateMarkdownText.generateMarkdownText)(text);
var styles = {
...defaultMarkdownStyles,
...markdownStyles,
paragraph: {
...(onlyEmojis ? {} : {
lineHeight: _theme.primitives.typographyLineHeightNormal
}),
...defaultMarkdownStyles.paragraph,
...markdownStyles?.paragraph
},
paragraphCenter: {
...(onlyEmojis ? {} : {
lineHeight: _theme.primitives.typographyLineHeightNormal
}),
...defaultMarkdownStyles.paragraphCenter,
...markdownStyles?.paragraphCenter
},
autolink: {
fontSize: _theme.primitives.typographyFontSizeMd,
lineHeight: _theme.primitives.typographyLineHeightNormal,
...defaultMarkdownStyles.autolink,
color: semantics.textLink,
...markdownStyles?.autolink
},
blockQuoteSection: {
...defaultMarkdownStyles.blockQuoteSection,
flexDirection: 'row',
padding: _theme.primitives.spacingXs,
...markdownStyles?.blockQuoteSection
},
blockQuoteSectionBar: {
...defaultMarkdownStyles.blockQuoteSectionBar,
backgroundColor: semantics.borderCoreStrong,
marginRight: _theme.primitives.spacingXs,
width: 2,
...markdownStyles?.blockQuoteSectionBar
},
blockQuoteText: {
fontSize: _theme.primitives.typographyFontSizeMd,
lineHeight: _theme.primitives.typographyLineHeightNormal,
...defaultMarkdownStyles.blockQuoteText,
...markdownStyles?.blockQuoteText
},
codeBlock: {
...defaultMarkdownStyles.codeBlock,
backgroundColor: semantics.backgroundCoreSurfaceSubtle,
color: semantics.textPrimary,
padding: _theme.primitives.spacingXs,
...markdownStyles?.codeBlock
},
inlineCode: {
...defaultMarkdownStyles.inlineCode,
backgroundColor: semantics.backgroundCoreSurfaceSubtle,
borderColor: semantics.borderCoreSubtle,
color: semantics.accentError,
...markdownStyles?.inlineCode
},
mentions: {
...defaultMarkdownStyles.mentions,
color: semantics.chatTextMention,
...markdownStyles?.mentions
},
table: {
...defaultMarkdownStyles.table,
borderColor: semantics.borderCoreStrong,
marginVertical: _theme.primitives.spacingXs,
...markdownStyles?.table
},
tableHeader: {
...defaultMarkdownStyles.tableHeader,
backgroundColor: semantics.backgroundCoreSurfaceSubtle,
...markdownStyles?.tableHeader
},
tableHeaderCell: {
fontSize: _theme.primitives.typographyFontSizeMd,
lineHeight: _theme.primitives.typographyLineHeightNormal,
...defaultMarkdownStyles.tableHeaderCell,
padding: _theme.primitives.spacingXxs,
...markdownStyles?.tableHeaderCell
},
tableRow: {
...defaultMarkdownStyles.tableRow,
...markdownStyles?.tableRow
},
tableRowCell: {
...defaultMarkdownStyles.tableRowCell,
borderColor: semantics.borderCoreStrong,
padding: _theme.primitives.spacingXxs,
...markdownStyles?.tableRowCell
},
tableRowLast: {
...markdownStyles?.tableRowLast
},
text: {
fontSize: _theme.primitives.typographyFontSizeMd,
...(onlyEmojis ? {} : {
lineHeight: _theme.primitives.typographyLineHeightNormal
}),
...defaultMarkdownStyles.text,
color: isMyMessage ? semantics.chatTextOutgoing : semantics.chatTextIncoming,
...markdownStyles?.text,
writingDirection: _reactNative.I18nManager.isRTL ? 'rtl' : 'ltr'
}
};
var onLink = url => onLinkParams ? onLinkParams(url) : _reactNative.Linking.canOpenURL(url).then(canOpenUrl => canOpenUrl && _reactNative.Linking.openURL(url));
var previousLink;
var linkReact = (node, output, {
...state
}) => {
var url;
if (state?.withinLink && previousLink) {
url = previousLink;
} else {
url = node.target;
previousLink = node.target;
}
var onPress = event => {
if (!preventPress && onPressParam) {
onPressParam({
additionalInfo: {
url
},
defaultHandler: () => {
onLink(url);
},
emitter: 'textLink',
event
});
}
};
var onLongPress = event => {
if (!preventPress && onLongPressParam) {
onLongPressParam({
additionalInfo: {
url
},
emitter: 'textLink',
event
});
}
};
return (0, _jsxRuntime.jsx)(_reactNative.Text, {
onLongPress: onLongPress,
onPress: onPress,
style: styles.autolink,
suppressHighlighting: true,
children: output(node.content, {
...state,
withinLink: true
})
}, state.key);
};
var paragraphTextReact = (node, output, {
...state
}) => {
if (messageTextNumberOfLines !== undefined) {
if (state.key === '0' || state.key === 0) {
return (0, _jsxRuntime.jsx)(_reactNative.Text, {
numberOfLines: messageTextNumberOfLines,
style: styles.paragraph,
children: output(node.content, state)
}, state.key);
} else {
return null;
}
}
return (0, _jsxRuntime.jsx)(_reactNative.Text, {
style: styles.paragraph,
children: output(node.content, state)
}, state.key);
};
var mentioned_channel = message.mentioned_channel,
mentioned_group_ids = message.mentioned_group_ids,
mentioned_groups = message.mentioned_groups,
mentioned_here = message.mentioned_here,
mentioned_roles = message.mentioned_roles,
mentioned_users = message.mentioned_users;
var mentionEntities = [...(mentioned_users ?? []).map(user => ({
...user,
mentionType: 'user'
})), ...(mentioned_channel ? [{
id: 'channel',
mentionType: 'channel',
name: 'channel'
}] : []), ...(mentioned_here ? [{
id: 'here',
mentionType: 'here',
name: 'here'
}] : []), ...(mentioned_roles ?? []).map(role => ({
id: role,
mentionType: 'role',
name: role
})), ...(mentioned_groups ?? (mentioned_group_ids ?? []).map(id => ({
id,
name: id
}))).map(group => ({
id: group.id,
mentionType: 'user_group',
name: group.name ?? group.id
}))];
var mentionLookup = new Map();
for (var entity of mentionEntities) {
var key = (entity.name ?? entity.id).toLowerCase();
if (!mentionLookup.has(key)) mentionLookup.set(key, entity);
}
var mentionTokens = mentionEntities.map(entity => entity.name ?? entity.id).filter(value => Boolean(value)).sort((a, b) => b.length - a.length).map(value => `@${(0, _utils.escapeRegExp)(value)}`).join('|');
var regEx = new RegExp(`^\\B(${mentionTokens})`, 'g');
var mentionsMatchFunction = source => regEx.exec(source);
var colorForMentionType = mentionType => {
switch (mentionType) {
case 'user':
return semantics.chatTextMentionUser;
case 'channel':
case 'here':
return semantics.chatTextMentionBroadcast;
case 'role':
return semantics.chatTextMentionRole;
case 'user_group':
return semantics.chatTextMentionGroup;
default:
return semantics.chatTextMention;
}
};
var mentionsReact = (node, output, {
...state
}) => {
var matchedText = node.content[0]?.content;
var matchedName = matchedText?.substring(1) ?? '';
var matchedEntity = mentionLookup.get(matchedName.toLowerCase());
var mentionedUser = matchedEntity?.mentionType === 'user' ? matchedEntity : undefined;
var mentionColor = matchedEntity ? colorForMentionType(matchedEntity.mentionType) : semantics.chatTextMention;
var onPress = event => {
if (!preventPress && onPressParam) {
onPressParam({
additionalInfo: {
mentionedEntity: matchedEntity,
user: mentionedUser
},
emitter: 'textMention',
event
});
}
};
var onLongPress = event => {
if (!preventPress && onLongPressParam) {
onLongPressParam({
additionalInfo: {
mentionedEntity: matchedEntity,
user: mentionedUser
},
emitter: 'textMention',
event
});
}
};
return (0, _jsxRuntime.jsx)(_reactNative.Text, {
onLongPress: onLongPress,
onPress: onPress,
style: [styles.mentions, {
color: mentionColor
}],
children: Array.isArray(node.content) ? node.content.reduce((acc, current) => acc + current.content, '') || '' : output(node.content, state)
}, state.key);
};
var listReact = (node, output, state) => (0, _jsxRuntime.jsx)(ListOutput, {
node: node,
output: output,
state: state,
styles: styles
}, `list-${state.key}`);
var codeBlockReact = (node, _, state) => (0, _jsxRuntime.jsx)(MarkdownReactiveScrollView, {
children: (0, _jsxRuntime.jsx)(_reactNative.Text, {
style: styles.codeBlock,
children: node?.content?.trim()
})
}, state.key);
var tableReact = (node, output, state) => (0, _jsxRuntime.jsx)(MarkdownReactiveScrollView, {
children: (0, _jsxRuntime.jsx)(MarkdownTable, {
node: node,
output: output,
state: state,
styles: styles
})
}, state.key);
var blockQuoteReact = (node, output, state) => (0, _jsxRuntime.jsxs)(_reactNative.View, {
style: styles.blockQuoteSection,
children: [(0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.blockQuoteSectionBar
}), (0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.blockQuoteText,
children: output(node.content, state)
})]
}, state.key);
var customRules = {
blockQuote: {
react: blockQuoteReact
},
codeBlock: {
react: codeBlockReact
},
image: {
match: () => null
},
link: {
react: linkReact
},
list: {
react: listReact
},
paragraph: messageTextNumberOfLines ? {
react: paragraphTextReact
} : {},
reflink: {
match: () => null
},
sublist: {
react: listReact
},
...(mentionTokens ? {
mentions: {
match: mentionsMatchFunction,
order: _simpleMarkdown.defaultRules.text.order - 0.5,
parse: mentionsParseFunction,
react: mentionsReact
}
} : {}),
table: {
react: tableReact
}
};
return (0, _jsxRuntime.jsx)(_reactNativeMarkdownPackage.default, {
onLink: onLink,
rules: {
...customRules,
...markdownRules
},
styles: styles,
children: markdownText
}, `${JSON.stringify(mentionEntities)}-${onlyEmojis}-${messageOverlay ? JSON.stringify(markdownStyles) : undefined}-${JSON.stringify(semantics)}`);
};
exports.renderText = renderText;
var ListOutput = ({
node,
output,
state,
styles
}) => {
var isSublist = state.withinList;
var parentTypes = ['text', 'paragraph', 'strong'];
return (0, _jsxRuntime.jsx)(_reactNative.View, {
style: isSublist ? styles?.sublist : styles?.list,
children: node.items.map((item, index) => {
var indexAfterStart = node.start + index;
if (item === null) {
return (0, _jsxRuntime.jsx)(ListRow, {
style: styles?.listRow,
testID: "list-item",
children: (0, _jsxRuntime.jsx)(Bullet, {
index: node.ordered && indexAfterStart,
style: node.ordered ? styles?.listItemNumber : styles?.listItemBullet
})
}, index);
}
isSublist = item.length > 1 && item[1].type === 'list';
var isSublistWithinText = parentTypes.includes((item[0] ?? {}).type) && isSublist;
var style = isSublistWithinText ? {
marginBottom: 0
} : {};
return (0, _jsxRuntime.jsxs)(ListRow, {
style: styles?.listRow,
testID: "list-item",
children: [(0, _jsxRuntime.jsx)(Bullet, {
index: node.ordered && indexAfterStart,
style: node.ordered ? styles?.listItemNumber : styles?.listItemBullet
}), (0, _jsxRuntime.jsx)(ListItem, {
style: [styles?.listItemText, style],
children: output(item, state)
}, 1)]
}, index);
})
}, state.key);
};
exports.ListOutput = ListOutput;
var Bullet = ({
index,
style
}) => (0, _jsxRuntime.jsx)(_reactNative.Text, {
style: style,
children: index ? `${index}. ` : '\u2022 '
}, 0);
var ListRow = ({
children,
style
}) => (0, _jsxRuntime.jsx)(_reactNative.View, {
style: style,
children: children
});
var ListItem = ({
children,
style
}) => (0, _jsxRuntime.jsx)(_reactNative.Text, {
style: style,
children: children
});
var transpose = matrix => matrix[0].map((_, colIndex) => matrix.map(row => row[colIndex]));
var MarkdownTable = ({
node,
output,
state,
styles
}) => {
var content = (0, _react.useMemo)(() => {
var nodeContent = [node?.header, ...(node?.cells ?? null)];
return transpose(nodeContent);
}, [node?.cells, node?.header]);
var columns = content?.map((column, idx) => (0, _jsxRuntime.jsx)(MarkdownTableColumn, {
items: column,
output: output,
state: state,
styles: styles
}, `column-${idx}`));
return (0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.table,
children: columns
}, state.key);
};
var MarkdownTableColumn = ({
items,
output,
state,
styles
}) => {
var _items = (0, _toArray2.default)(items),
headerCellContent = _items[0],
columnCellContents = _arrayLikeToArray(_items).slice(1);
var ColumnCell = (0, _react.useCallback)(({
content
}) => content ? (0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.tableRow,
children: (0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.tableRowCell,
children: output(content, state)
})
}) : null, [output, state, styles]);
return (0, _jsxRuntime.jsxs)(_reactNative.View, {
style: {
flex: 1,
flexDirection: 'column'
},
children: [headerCellContent ? (0, _jsxRuntime.jsx)(_reactNative.View, {
style: styles.tableHeader,
children: (0, _jsxRuntime.jsx)(_reactNative.Text, {
style: styles.tableHeaderCell,
children: output(headerCellContent, state)
})
}, -1) : null, columnCellContents && columnCellContents.map((content, idx) => (0, _jsxRuntime.jsx)(ColumnCell, {
content: content
}, `cell-${idx}`))]
});
};
//# sourceMappingURL=renderText.js.map