Skip to content

Commit e69dad3

Browse files
ggazzodougfabris
andauthored
feat: Message Preview (#587)
Co-authored-by: Douglas Fabris <devfabris@gmail.com>
1 parent 4662cf0 commit e69dad3

File tree

188 files changed

+1957
-1000
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

188 files changed

+1957
-1000
lines changed
Loading
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import {
2+
MessageGenericPreview,
3+
MessageGenericPreviewContent,
4+
MessageGenericPreviewDescription,
5+
MessageGenericPreviewImage,
6+
MessageGenericPreviewTitle,
7+
MessageGenericPreviewFooter,
8+
MessageGenericPreviewThumb,
9+
Box,
10+
} from '@rocket.chat/fuselage';
11+
import * as UiKit from '@rocket.chat/ui-kit';
12+
import {
13+
isPreviewBlockWithThumb,
14+
isPreviewBlockWithPreview,
15+
} from '@rocket.chat/ui-kit';
16+
import React, { memo, ReactElement } from 'react';
17+
18+
import { BlockProps } from '../utils/BlockProps';
19+
import ContextBlock from './ContextBlock';
20+
21+
type PreviewBlockProps = BlockProps<UiKit.PreviewBlock>;
22+
23+
const PreviewBlock = ({
24+
block,
25+
surfaceRenderer,
26+
}: PreviewBlockProps): ReactElement => (
27+
<Box>
28+
<MessageGenericPreview>
29+
{isPreviewBlockWithPreview(block) && block.preview?.dimensions && (
30+
<MessageGenericPreviewImage
31+
width={block.preview.dimensions.width}
32+
height={block.preview.dimensions.height}
33+
url={block.preview.url}
34+
/>
35+
)}
36+
<MessageGenericPreviewContent
37+
thumb={
38+
isPreviewBlockWithThumb(block) ? (
39+
<MessageGenericPreviewThumb>
40+
<MessageGenericPreviewImage
41+
height={192}
42+
width={368}
43+
url={block.thumb.url}
44+
/>
45+
</MessageGenericPreviewThumb>
46+
) : undefined
47+
}
48+
>
49+
{Array.isArray(block.title) ? (
50+
<MessageGenericPreviewTitle
51+
externalUrl={
52+
isPreviewBlockWithPreview(block) ? block.externalUrl : undefined
53+
}
54+
>
55+
{block.title.map((title) =>
56+
surfaceRenderer.renderTextObject(
57+
title,
58+
0,
59+
UiKit.BlockContext.NONE
60+
)
61+
)}
62+
</MessageGenericPreviewTitle>
63+
) : null}
64+
{Array.isArray(block.description) ? (
65+
<MessageGenericPreviewDescription clamp>
66+
{block.description.map((description) =>
67+
surfaceRenderer.renderTextObject(
68+
description,
69+
0,
70+
UiKit.BlockContext.NONE
71+
)
72+
)}
73+
</MessageGenericPreviewDescription>
74+
) : null}
75+
{block.footer && (
76+
<MessageGenericPreviewFooter>
77+
<ContextBlock
78+
block={block.footer}
79+
surfaceRenderer={surfaceRenderer}
80+
context={UiKit.BlockContext.BLOCK}
81+
index={0}
82+
/>
83+
</MessageGenericPreviewFooter>
84+
)}
85+
</MessageGenericPreviewContent>
86+
</MessageGenericPreview>
87+
</Box>
88+
);
89+
90+
export default memo(PreviewBlock);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Box } from '@rocket.chat/fuselage';
2+
import * as UiKit from '@rocket.chat/ui-kit';
3+
import React, { FC } from 'react';
4+
5+
import { BlockProps } from '../../utils/BlockProps';
6+
import { ContextElementItem } from './ContextElementItem';
7+
8+
type ContextElementProps = BlockProps<UiKit.ContextBlock>;
9+
10+
export const ContextElement: FC<ContextElementProps> = ({
11+
block,
12+
surfaceRenderer,
13+
className,
14+
}) => (
15+
<Box
16+
className={className}
17+
display='flex'
18+
alignItems='center'
19+
margin={-4}
20+
withTruncatedText
21+
>
22+
{block.elements.map((element, i) => (
23+
<ContextElementItem
24+
index={i}
25+
key={i}
26+
element={element}
27+
surfaceRenderer={surfaceRenderer}
28+
/>
29+
))}
30+
</Box>
31+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Box } from '@rocket.chat/fuselage';
2+
import * as UiKit from '@rocket.chat/ui-kit';
3+
import { BlockContext, ElementType } from '@rocket.chat/ui-kit';
4+
import React, { FC } from 'react';
5+
6+
import { BlockProps } from '../../utils/BlockProps';
7+
8+
type ContextElementProps = BlockProps<UiKit.ContextBlock>;
9+
10+
export const ContextElementItem: FC<{
11+
element: ContextElementProps['block']['elements'][number];
12+
surfaceRenderer: ContextElementProps['surfaceRenderer'];
13+
index: number;
14+
}> = ({ element, surfaceRenderer, index }) => {
15+
const renderedElement = surfaceRenderer.renderContext(
16+
element,
17+
BlockContext.CONTEXT,
18+
undefined,
19+
index
20+
);
21+
22+
if (!renderedElement) {
23+
return null;
24+
}
25+
26+
switch (element.type) {
27+
case ElementType.PLAIN_TEXT:
28+
case ElementType.MARKDOWN:
29+
return (
30+
<Box is='span' withTruncatedText fontScale='c1' color='info' margin={4}>
31+
{renderedElement}
32+
</Box>
33+
);
34+
35+
default:
36+
return <>{renderedElement}</>;
37+
}
38+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './ContextElement';

packages/fuselage-ui-kit/src/stories/Message.stories.tsx

+27-34
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
/* eslint-disable new-cap */
2-
import {
3-
Message,
4-
Avatar,
5-
MessageLeftContainer,
6-
MessageHeader,
7-
MessageContainer,
8-
MessageName,
9-
MessageUsername,
10-
MessageRole,
11-
MessageTimestamp,
12-
MessageToolbox,
13-
MessageBody,
14-
} from '@rocket.chat/fuselage';
2+
import { Message, Avatar } from '@rocket.chat/fuselage';
153
import * as UiKit from '@rocket.chat/ui-kit';
164
import { action } from '@storybook/addon-actions';
175
import React from 'react';
@@ -35,7 +23,7 @@ const createStory = (blocks: readonly UiKit.LayoutBlock[]) => {
3523
errors: Record<string, string>;
3624
}) => (
3725
<Message clickable>
38-
<MessageLeftContainer>
26+
<Message.LeftContainer>
3927
<Avatar
4028
url='data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC
4129
4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj
@@ -50,17 +38,17 @@ const createStory = (blocks: readonly UiKit.LayoutBlock[]) => {
5038
UH2oorkV10pRc7b1zXb/hZOzuJvM86QWEXeELxOzHSIPcmiiiunVlF2RNTpRkrs//Z'
5139
size={'x36'}
5240
/>
53-
</MessageLeftContainer>
54-
<MessageContainer>
55-
<MessageHeader>
56-
<MessageName>Haylie George</MessageName>
57-
<MessageUsername>@haylie.george</MessageUsername>
58-
<MessageRole>Admin</MessageRole>
59-
<MessageRole>User</MessageRole>
60-
<MessageRole>Owner</MessageRole>
61-
<MessageTimestamp>12:00 PM</MessageTimestamp>
62-
</MessageHeader>
63-
<MessageBody>
41+
</Message.LeftContainer>
42+
<Message.Container>
43+
<Message.Header>
44+
<Message.Name>Haylie George</Message.Name>
45+
<Message.Username>@haylie.george</Message.Username>
46+
<Message.Role>Admin</Message.Role>
47+
<Message.Role>User</Message.Role>
48+
<Message.Role>Owner</Message.Role>
49+
<Message.Timestamp>12:00 PM</Message.Timestamp>
50+
</Message.Header>
51+
<Message.Body>
6452
<kitContext.Provider
6553
value={{
6654
action: action('action'),
@@ -72,15 +60,15 @@ const createStory = (blocks: readonly UiKit.LayoutBlock[]) => {
7260
>
7361
{UiKitMessage(blocks)}
7462
</kitContext.Provider>
75-
</MessageBody>
76-
</MessageContainer>
77-
<MessageToolbox.Wrapper>
78-
<MessageToolbox>
79-
<MessageToolbox.Item icon='quote' />
80-
<MessageToolbox.Item icon='clock' />
81-
<MessageToolbox.Item icon='thread' />
82-
</MessageToolbox>
83-
</MessageToolbox.Wrapper>
63+
</Message.Body>
64+
</Message.Container>
65+
<Message.Toolbox.Wrapper>
66+
<Message.Toolbox>
67+
<Message.Toolbox.Item icon='quote' />
68+
<Message.Toolbox.Item icon='clock' />
69+
<Message.Toolbox.Item icon='thread' />
70+
</Message.Toolbox>
71+
</Message.Toolbox.Wrapper>
8472
</Message>
8573
);
8674
story.args = {
@@ -151,3 +139,8 @@ export const ContextWithTextAndImages = createStory(
151139
);
152140

153141
export const Conditional = createStory(payloads.conditional);
142+
143+
export const Preview = createStory(payloads.preview);
144+
export const PreviewWithExternalUrl = createStory(
145+
payloads.previewWithExternalUrl
146+
);

packages/fuselage-ui-kit/src/stories/payloads/img.ts

+3
Large diffs are not rendered by default.

packages/fuselage-ui-kit/src/stories/payloads/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export * from './divider';
55
export * from './image';
66
export * from './input';
77
export * from './section';
8+
export * from './preview';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// import * as UiKit from '@rocket.chat/ui-kit';
2+
import { PreviewBlock } from '@rocket.chat/ui-kit';
3+
4+
import img from './img';
5+
6+
export const preview: PreviewBlock[] = [
7+
{
8+
type: 'preview',
9+
title: [
10+
{
11+
type: 'plain_text',
12+
text: 'I Need a Marg',
13+
emoji: true,
14+
},
15+
],
16+
description: [
17+
{
18+
type: 'plain_text',
19+
text: 'I Need a Description',
20+
emoji: true,
21+
},
22+
],
23+
thumb: { url: img },
24+
footer: {
25+
type: 'context',
26+
elements: [
27+
{
28+
type: 'plain_text',
29+
text: 'google.com',
30+
},
31+
],
32+
},
33+
},
34+
];
35+
36+
export const previewWithExternalUrl: PreviewBlock[] = [
37+
{
38+
type: 'preview',
39+
title: [
40+
{
41+
type: 'plain_text',
42+
text: 'I Need a Marg',
43+
emoji: true,
44+
},
45+
],
46+
description: [
47+
{
48+
type: 'plain_text',
49+
text: 'I Need a Description',
50+
emoji: true,
51+
},
52+
],
53+
// thumb: { url: img },
54+
footer: {
55+
type: 'context',
56+
elements: [
57+
{
58+
type: 'plain_text',
59+
text: 'google.com',
60+
},
61+
],
62+
},
63+
externalUrl:
64+
'https://rocketchat.github.io/Rocket.Chat.Fuselage/?path=/story/*',
65+
},
66+
];

packages/fuselage-ui-kit/src/surfaces/FuselageSurfaceRenderer.tsx

+29-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import ContextBlock from '../blocks/ContextBlock';
66
import DividerBlock from '../blocks/DividerBlock';
77
import ImageBlock from '../blocks/ImageBlock';
88
import InputBlock from '../blocks/InputBlock';
9+
import PreviewBlock from '../blocks/PreviewBlock';
910
import SectionBlock from '../blocks/SectionBlock';
1011
import ButtonElement from '../elements/ButtonElement';
1112
import DatePickerElement from '../elements/DatePickerElement';
@@ -18,7 +19,15 @@ import StaticSelectElement from '../elements/StaticSelectElement';
1819

1920
export class FuselageSurfaceRenderer extends UiKit.SurfaceRenderer<ReactElement> {
2021
public constructor() {
21-
super(['actions', 'context', 'divider', 'image', 'input', 'section']);
22+
super([
23+
'actions',
24+
'context',
25+
'divider',
26+
'image',
27+
'input',
28+
'section',
29+
'preview',
30+
]);
2231
}
2332

2433
public plain_text(
@@ -65,6 +74,25 @@ export class FuselageSurfaceRenderer extends UiKit.SurfaceRenderer<ReactElement>
6574
return null;
6675
}
6776

77+
preview(
78+
block: UiKit.PreviewBlock,
79+
context: UiKit.BlockContext,
80+
index: number
81+
): ReactElement | null {
82+
if (context !== UiKit.BlockContext.BLOCK) {
83+
return null;
84+
}
85+
return (
86+
<PreviewBlock
87+
key={index}
88+
block={block}
89+
context={context}
90+
index={index}
91+
surfaceRenderer={this}
92+
/>
93+
);
94+
}
95+
6896
context(
6997
block: UiKit.ContextBlock,
7098
context: UiKit.BlockContext,

0 commit comments

Comments
 (0)