update components and add storybooks

This commit is contained in:
Gerzon Z 2021-08-20 12:25:30 -04:00
parent 71aed0cde8
commit c2dd2dbc48
19 changed files with 642 additions and 49 deletions

View File

@ -3,12 +3,14 @@ import React from 'react';
import { Text } from 'react-native';
import { themes } from '../../constants/colors';
import { useTheme } from '../../theme';
import styles from './styles';
const Hashtag = React.memo(({
hashtag, channels, navToRoomInfo, style = [], theme
hashtag, channels, navToRoomInfo, style = []
}) => {
const { theme } = useTheme();
const handlePress = () => {
const index = channels.findIndex(channel => channel.name === hashtag);
const navParam = {
@ -44,7 +46,6 @@ Hashtag.propTypes = {
hashtag: PropTypes.string,
navToRoomInfo: PropTypes.func,
style: PropTypes.array,
theme: PropTypes.string,
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
};

View File

@ -1,14 +1,15 @@
/* eslint-disable react/no-array-index-key */
import React from 'react';
import { View } from 'react-native';
import PropTypes from 'prop-types';
import Emoji from './Emoji';
const BigEmoji = ({ value }) => (
<>
<View style={{ flexDirection: 'row' }}>
{value.map((block, index) => <Emoji key={index} emojiHandle={`:${ block.value.value }:`} isBigEmoji />)}
</>
</View>
);
BigEmoji.propTypes = {

View File

@ -2,9 +2,10 @@
import React from 'react';
import { StyleSheet, Text } from 'react-native';
import PropTypes from 'prop-types';
import Plain from './Plain';
import Strike from './Strike';
import Italic from './Italic';
import Plain from './Plain';
const styles = StyleSheet.create({
text: {
@ -17,7 +18,7 @@ const Bold = ({ value }) => (
{value.map((block, index) => {
switch (block.type) {
case 'PLAIN_TEXT':
return <Plain key={index} value={block.value} />;
return <Plain value={block.value} />;
case 'STRIKE':
return <Strike key={index} value={block.value} />;
case 'ITALIC':

View File

@ -21,7 +21,7 @@ const Code = ({
...styles.codeBlock,
color: themes[theme].bodyText,
backgroundColor: themes[theme].bannerBackground,
borderColor: themes[theme].bannerBackground
borderColor: themes[theme].borderColor
},
...style
]}

View File

@ -10,9 +10,11 @@ import Italic from './Italic';
import Emoji from './Emoji';
import Mention from './Mention';
import InlineCode from './InlineCode';
import Hashtag from '../Hashtag';
const Inline = ({
value, mentions, navToRoomInfo, style
value, mentions, channels, navToRoomInfo, style
}) => (
<Text>
{value.map((block) => {
@ -33,8 +35,7 @@ const Inline = ({
case 'EMOJI':
return <Emoji emojiHandle={`:${ block.value.value }:`} />;
case 'MENTION_CHANNEL':
// case 'COLOR':
return <Plain value={`${ block.value.value }`} />;
return <Hashtag hashtag={block.value.value} navToRoomInfo={navToRoomInfo} channels={channels} style={style} />;
case 'INLINE_CODE':
return <InlineCode value={block.value} style={style} />;
default:
@ -47,6 +48,7 @@ const Inline = ({
Inline.propTypes = {
value: PropTypes.object,
mentions: PropTypes.array,
channels: PropTypes.array,
navToRoomInfo: PropTypes.func,
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
};

View File

@ -1,33 +1,26 @@
import React from 'react';
import { Text } from 'react-native';
import PropTypes from 'prop-types';
import { useTheme } from '@react-navigation/native';
import styles from '../styles';
import { themes } from '../../../constants/colors';
import { useTheme } from '../../../theme';
const InlineCode = ({ value, style }) => {
const { theme } = useTheme();
console.log({ value: value.value });
return (
<Text style={[
{
...styles.codeInline,
color: themes[theme].bodyText,
backgroundColor: themes[theme].bannerBackground,
borderColor: themes[theme].bannerBackground
borderColor: themes[theme].borderColor
},
...style
]}
>
{((block) => {
switch (block.type) {
case 'PLAIN_TEXT':
return block.value;
default:
return null;
}
})(value)}
{value.type === 'PLAIN_TEXT' && value.value}
</Text>
);
};

View File

@ -3,9 +3,9 @@ import React from 'react';
import { StyleSheet, Text } from 'react-native';
import PropTypes from 'prop-types';
import Plain from './Plain';
import Strike from './Strike';
import Bold from './Bold';
import Plain from './Plain';
const styles = StyleSheet.create({
text: {

View File

@ -0,0 +1,23 @@
/* eslint-disable react/no-array-index-key */
import React from 'react';
import { View, Text } from 'react-native';
import PropTypes from 'prop-types';
import Inline from './Inline';
const OrderedList = React.memo(({ value }) => (
<>
{value.map((item, index) => (
<View style={{ flexDirection: 'row' }}>
<Text>{index + 1}. </Text>
<Inline key={index} value={item.value} />
</View>
))}
</>
));
OrderedList.propTypes = {
value: PropTypes.array
};
export default OrderedList;

View File

@ -4,12 +4,13 @@ import PropTypes from 'prop-types';
import Inline from './Inline';
const Paragraph = ({
value, mentions, navToRoomInfo, style
}) => <Inline value={value} mentions={mentions} navToRoomInfo={navToRoomInfo} style={style} />;
value, mentions, channels, navToRoomInfo, style
}) => <Inline value={value} mentions={mentions} channels={channels} navToRoomInfo={navToRoomInfo} style={style} />;
Paragraph.propTypes = {
value: PropTypes.string,
mentions: PropTypes.string,
mentions: PropTypes.array,
channels: PropTypes.array,
navToRoomInfo: PropTypes.func,
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
};

View File

@ -1,9 +1,11 @@
/* eslint-disable react/no-array-index-key */
import React from 'react';
import { View } from 'react-native';
import PropTypes from 'prop-types';
import { themes } from '../../../constants/colors';
import { useTheme } from '../../../theme';
import styles from '../styles';
import Paragraph from './Paragraph';
const Quote = ({ value }) => {
const { theme } = useTheme();
@ -12,7 +14,9 @@ const Quote = ({ value }) => {
<View style={styles.container}>
<View style={[styles.quote, { backgroundColor: themes[theme].borderColor }]} />
<View style={styles.childContainer}>
{value}
{value.map((item, index) => (
<Paragraph key={index} value={item.value} mentions={[]} />
))}
</View>
</View>
</>

View File

@ -3,9 +3,9 @@ import React from 'react';
import { StyleSheet, Text } from 'react-native';
import PropTypes from 'prop-types';
import Plain from './Plain';
import Bold from './Bold';
import Italic from './Italic';
import Plain from './Plain';
const styles = StyleSheet.create({
text: {

View File

@ -0,0 +1,18 @@
/* eslint-disable react/no-array-index-key */
import React from 'react';
import PropTypes from 'prop-types';
import Inline from './Inline';
const UnorderedList = React.memo(({ value }) => (
<>
{value.map((item, index) => (
<Inline key={index} value={item.value} />
))}
</>
));
UnorderedList.propTypes = {
value: PropTypes.array
};
export default UnorderedList;

View File

@ -2,18 +2,19 @@
import React from 'react';
import PropTypes from 'prop-types';
import List from './List';
import Quote from './Quote';
import Paragraph from './Paragraph';
import Heading from './Heading';
import Code from './Code';
import Link from './Link';
import BigEmoji from './BigEmoji';
import OrderedList from './OrderedList';
import UnorderedList from './UnorderedList';
const isBigEmoji = tokens => tokens.length === 1 && tokens[0].type === 'BIG_EMOJI';
const Body = ({
tokens, mentions, navToRoomInfo, style
tokens, mentions, channels, navToRoomInfo, style
}) => {
if (isBigEmoji(tokens)) {
return <BigEmoji value={tokens[0].value} />;
@ -24,15 +25,25 @@ const Body = ({
{tokens.map((block, index) => {
switch (block.type) {
case 'UNORDERED_LIST':
return <List type={block.type} value={block.value} key={index} />;
return <UnorderedList key={index} value={block.value} />;
case 'ORDERED_LIST':
return <List type={block.type} value={block.value} key={index} />;
return <OrderedList key={index} value={block.value} />;
case 'TASK':
return <List type={block.type} value={block.value} key={index} />;
return <OrderedList key={index} value={block.value} />;
case 'QUOTE':
console.log({ block });
return <Quote key={index} value={block.value} />;
case 'PARAGRAPH':
return <Paragraph key={index} value={block.value} navToRoomInfo={navToRoomInfo} mentions={mentions} style={style} />;
return (
<Paragraph
key={index}
value={block.value}
navToRoomInfo={navToRoomInfo}
channels={channels}
mentions={mentions}
style={style}
/>
);
case 'CODE':
return <Code key={index} value={block.value} style={style} />;
case 'LINK':
@ -51,6 +62,7 @@ const Body = ({
Body.propTypes = {
tokens: PropTypes.array,
mentions: PropTypes.array,
channels: PropTypes.array,
navToRoomInfo: PropTypes.func,
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
};

View File

@ -238,14 +238,13 @@ class Markdown extends PureComponent {
renderHashtag = ({ hashtag }) => {
const {
channels, navToRoomInfo, style, theme
channels, navToRoomInfo, style
} = this.props;
return (
<MarkdownHashtag
hashtag={hashtag}
channels={channels}
navToRoomInfo={navToRoomInfo}
theme={theme}
style={style}
/>
);
@ -376,7 +375,7 @@ class Markdown extends PureComponent {
render() {
const {
msg, md, numberOfLines, preview = false, theme, style = [], testID, user, mentions, navToRoomInfo
msg, md, numberOfLines, preview = false, theme, style = [], testID, user, mentions, channels, navToRoomInfo
} = this.props;
if (!msg) {
@ -384,7 +383,7 @@ class Markdown extends PureComponent {
}
if (user.enableMessageParserEarlyAdoption && md) {
return <MessageBody tokens={md} theme={theme} style={style} mentions={mentions} navToRoomInfo={navToRoomInfo} />;
return <MessageBody tokens={md} style={style} mentions={mentions} channels={channels} navToRoomInfo={navToRoomInfo} />;
}
let m = formatText(msg);

View File

@ -73,7 +73,9 @@ export default StyleSheet.create({
...sharedStyles.textRegular,
...codeFontFamily,
borderWidth: 1,
borderRadius: 4
borderRadius: 4,
paddingLeft: 2,
paddingTop: 2
},
codeBlock: {
...sharedStyles.textRegular,

View File

@ -1,7 +1,13 @@
import 'react-native-gesture-handler';
import 'react-native-console-time-polyfill';
import { AppRegistry } from 'react-native';
import { name as appName, share as shareName } from './app.json';
// import 'react-native-gesture-handler';
// import 'react-native-console-time-polyfill';
// import { AppRegistry } from 'react-native';
// import { name as appName, share as shareName } from './app.json';
// AppRegistry.registerComponent(appName, () => require('./app/index').default);
// AppRegistry.registerComponent(shareName, () => require('./app/share').default);
// For storybook, comment everything above and uncomment below
import './storybook';
if (__DEV__) {
require('./app/ReactotronConfig');
@ -16,9 +22,3 @@ if (__DEV__) {
console.error = () => {};
console.info = () => {};
}
AppRegistry.registerComponent(appName, () => require('./app/index').default);
AppRegistry.registerComponent(shareName, () => require('./app/share').default);
// For storybook, comment everything above and uncomment below
// import './storybook';

View File

@ -152,7 +152,6 @@ stories.add('Hashtag', () => (
<View style={styles.container}>
<Markdown
msg='#test-channel #unknown'
theme={theme}
channels={[{ _id: '123', name: 'test-channel' }]}
/>
</View>

View File

@ -0,0 +1,536 @@
/* eslint-disable import/no-extraneous-dependencies */
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { storiesOf } from '@storybook/react-native';
import MessageBody from '../../app/containers/markdown/MessageBody';
import { themes } from '../../app/constants/colors';
const stories = storiesOf('MessageBody', module);
const theme = 'light';
const styles = StyleSheet.create({
container: {
marginHorizontal: 15,
backgroundColor: themes[theme].backgroundColor,
marginVertical: 50
},
separator: {
marginHorizontal: 10,
marginVertical: 10
}
});
const simpleTextMsg = [{
type: 'PARAGRAPH',
value: [{
type: 'PLAIN_TEXT',
value: 'This is Rocket.Chat'
}]
}];
const longTextMsg = [{
type: 'PARAGRAPH',
value: [{
type: 'PLAIN_TEXT',
value: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
}]
}];
const lineBreakMsg = [
{
type: 'PARAGRAPH',
value: [
{
type: 'PLAIN_TEXT',
value: 'a'
},
{
type: 'PLAIN_TEXT',
value: 'b'
},
{
type: 'PLAIN_TEXT',
value: 'c'
},
{
type: 'PLAIN_TEXT',
value: ''
},
{
type: 'PLAIN_TEXT',
value: 'd'
},
{
type: 'PLAIN_TEXT',
value: ''
},
{
type: 'PLAIN_TEXT',
value: ''
},
{
type: 'PLAIN_TEXT',
value: 'e'
}
]
}
];
const sequentialEmptySpacesMsg = [
{
type: 'PARAGRAPH',
value: [
{
type: 'PLAIN_TEXT',
value: 'a b c'
}
]
}
];
const boldOrUnderscoreMsg = [
{
type: 'PARAGRAPH',
value: [
{
type: 'PLAIN_TEXT',
value: 'Strong emphasis, aka bold, with '
},
{
type: 'BOLD',
value: [{
type: 'PLAIN_TEXT',
value: 'asterisks'
}]
},
{
type: 'PLAIN_TEXT',
value: ' or '
},
{
type: 'ITALIC',
value: [{
type: 'PLAIN_TEXT',
value: 'underscore'
}]
}
]
}
];
stories.add('Text', () => (
<View style={styles.container}>
<MessageBody tokens={simpleTextMsg} />
<MessageBody tokens={longTextMsg} />
<MessageBody tokens={lineBreakMsg} />
<MessageBody tokens={sequentialEmptySpacesMsg} />
<MessageBody tokens={boldOrUnderscoreMsg} />
</View>
));
const allMentionTokens = [
{
type: 'PARAGRAPH',
value: [
{
type: 'MENTION_USER',
value: {
type: 'PLAIN_TEXT',
value: 'rocket.cat'
}
}
]
}
];
const multipleMentionTokens = [
{
type: 'PARAGRAPH',
value: [
{
type: 'MENTION_USER',
value: {
type: 'PLAIN_TEXT',
value: 'name'
}
},
{
type: 'PLAIN_TEXT',
value: ' '
},
{
type: 'MENTION_USER',
value: {
type: 'PLAIN_TEXT',
value: 'rocket.cat'
}
},
{
type: 'PLAIN_TEXT',
value: ' '
},
{
type: 'MENTION_USER',
value: {
type: 'PLAIN_TEXT',
value: 'here'
}
},
{
type: 'PLAIN_TEXT',
value: ' '
},
{
type: 'MENTION_USER',
value: {
type: 'PLAIN_TEXT',
value: 'all'
}
}
]
}
];
const allMentions = [
{
_id: 'rocket.cat',
username: 'rocket.cat'
}
];
const multipleMentions = [
{
_id: 'name',
username: 'name'
},
{
_id: 'rocket.cat',
username: 'rocket.cat'
},
{
_id: 'here',
username: 'here'
},
{
_id: 'all',
username: 'all'
}
];
stories.add('Mentions', () => (
<View style={styles.container}>
<MessageBody tokens={allMentionTokens} mentions={allMentions} navToRoomInfo={() => {}} style={[]} />
<MessageBody tokens={multipleMentionTokens} mentions={multipleMentions} navToRoomInfo={() => {}} style={[]} />
</View>
));
const channelTokens = [
{
type: 'PARAGRAPH',
value: [{
type: 'MENTION_CHANNEL',
value: {
type: 'PLAIN_TEXT',
value: 'text_channel'
}
}]
}
];
const channelMention = [
{
_id: 'text_channel',
name: 'text_channel'
}
];
stories.add('Hashtag', () => (
<View style={styles.container}>
<MessageBody tokens={channelTokens} channels={channelMention} navToRoomInfo={() => {}} />
</View>
));
const bigEmojiTokens = [{
type: 'BIG_EMOJI',
value: [
{
type: 'EMOJI',
value: {
type: 'PLAIN_TEXT',
value: 'green_heart'
}
}
]
}];
const multipleBigEmojiTokens = [{
type: 'BIG_EMOJI',
value: [
{
type: 'EMOJI',
value: {
type: 'PLAIN_TEXT',
value: 'green_heart'
}
},
{
type: 'EMOJI',
value: {
type: 'PLAIN_TEXT',
value: 'joy'
}
},
{
type: 'EMOJI',
value: {
type: 'PLAIN_TEXT',
value: 'grin'
}
}
]
}];
const emojiTokens = [{
type: 'PARAGRAPH',
value: [
{
type: 'EMOJI',
value: {
type: 'PLAIN_TEXT',
value: 'rocket'
}
},
{
type: 'EMOJI',
value: {
type: 'PLAIN_TEXT',
value: 'facepalm'
}
}
]
}];
stories.add('Emoji', () => (
<View style={styles.container}>
<MessageBody tokens={bigEmojiTokens} />
<MessageBody tokens={multipleBigEmojiTokens} />
<MessageBody tokens={emojiTokens} />
</View>
));
const blockQuoteTokens = [{
type: 'QUOTE',
value: [{
type: 'PARAGRAPH',
value: [{
type: 'PLAIN_TEXT',
value: 'Rocket.Chat to the moon'
}]
}]
}];
stories.add('Block quote', () => (
<View style={styles.container}>
<MessageBody tokens={blockQuoteTokens} />
</View>
));
const rocketChatLink = [
{
type: 'PARAGRAPH',
value: [
{
type: 'LINK',
value: {
src: {
type: 'PLAIN_TEXT',
value: 'https://rocket.chat'
},
label: {
type: 'PLAIN_TEXT',
value: 'https://rocket.chat'
}
}
}
]
}
];
const markdownLink = [
{
type: 'PARAGRAPH',
value: [
{
type: 'LINK',
value: {
src: {
type: 'PLAIN_TEXT',
value: 'https://rocket.chat'
},
label: {
type: 'PLAIN_TEXT',
value: 'Markdown link'
}
}
}
]
}
];
stories.add('Links', () => (
<View style={styles.container}>
<MessageBody tokens={rocketChatLink} />
<MessageBody tokens={markdownLink} />
</View>
));
stories.add('Headers', () => (
<View style={styles.container}>
<MessageBody
tokens={
[
{
type: 'HEADING',
value: [{
type: 'PLAIN_TEXT',
value: '# Header 1'
}],
level: 1
}
]
}
/>
<MessageBody
tokens={
[
{
type: 'HEADING',
value: [{
type: 'PLAIN_TEXT',
value: '## Header 2'
}],
level: 2
}
]
}
/>
<MessageBody
tokens={
[
{
type: 'HEADING',
value: [{
type: 'PLAIN_TEXT',
value: '### Header 3'
}],
level: 3
}
]
}
/>
<MessageBody
tokens={
[
{
type: 'HEADING',
value: [{
type: 'PLAIN_TEXT',
value: '#### Header 4'
}],
level: 4
}
]
}
/>
<MessageBody
tokens={
[
{
type: 'HEADING',
value: [{
type: 'PLAIN_TEXT',
value: '##### Header 5'
}],
level: 5
}
]
}
/>
<MessageBody
tokens={
[
{
type: 'HEADING',
value: [{
type: 'PLAIN_TEXT',
value: '###### Header 6'
}],
level: 6
}
]
}
/>
</View>
));
const unorederedListToken = [
{
type: 'UNORDERED_LIST',
value: [
{
type: 'LIST_ITEM',
value: [
{
type: 'PLAIN_TEXT',
value: 'Open Source'
}
]
},
{
type: 'LIST_ITEM',
value: [
{
type: 'PLAIN_TEXT',
value: 'Rocket.Chat'
}
]
}
]
}
];
const orderedListToken = [
{
type: 'ORDERED_LIST',
value: [
{
type: 'LIST_ITEM',
value: [
{
type: 'PLAIN_TEXT',
value: 'Open Source'
}
]
},
{
type: 'LIST_ITEM',
value: [
{
type: 'PLAIN_TEXT',
value: 'Rocket.Chat'
}
]
}
]
}
];
stories.add('Lists', () => (
<View style={styles.container}>
<MessageBody tokens={unorederedListToken} />
<MessageBody tokens={orderedListToken} />
</View>
));

View File

@ -12,6 +12,7 @@ import './HeaderButtons';
import './UnreadBadge';
import '../../app/views/ThreadMessagesView/Item.stories.js';
import './Avatar';
import './MessageBody';
import '../../app/containers/BackgroundContainer/index.stories.js';
import '../../app/containers/RoomHeader/RoomHeader.stories.js';
import '../../app/views/RoomView/LoadMore/LoadMore.stories';