Skip to content

Commit

Permalink
feat: add chatLog component
Browse files Browse the repository at this point in the history
  • Loading branch information
shleewhite committed Jun 22, 2022
1 parent 7e3fda8 commit c9ee672
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import * as React from 'react';
import {screen, render} from '@testing-library/react';
import {CustomizationProvider} from '@twilio-paste/customization';
import type {PasteCustomCSS} from '@twilio-paste/customization';
import {ChatMessage, ChatBubble, ChatMessageMeta, ChatMessageMetaItem} from '../src';
import {ChatMessage, ChatBubble, ChatMessageMeta, ChatMessageMetaItem, ChatLog} from '../src';

const customizedElements: {[key: string]: PasteCustomCSS} = {
CHAT_LOG: {
padding: 'space100',
},
CHAT_MESSAGE: {
marginBottom: 'space100',
variants: {
Expand Down Expand Up @@ -33,6 +36,7 @@ const customizedElements: {[key: string]: PasteCustomCSS} = {
};

const customizedFooElements: {[key: string]: PasteCustomCSS} = {
foo_log: customizedElements.CHAT_LOG,
foo_message: customizedElements.CHAT_MESSAGE,
foo_bubble: customizedElements.CHAT_BUBBLE,
foo_meta: customizedElements.CHAT_MESSAGE_META,
Expand Down Expand Up @@ -87,6 +91,7 @@ describe('Customization', () => {
);

const inboundMessage = screen.getByTestId('inbound-message');

expect(inboundMessage.getAttribute('data-paste-element')).toEqual('CHAT_MESSAGE');

const outboundMessage = screen.getByTestId('outbound-message');
Expand Down Expand Up @@ -395,3 +400,33 @@ describe('Customization', () => {
});
});
});

describe('ChatLog', () => {
it('should add custom styles', () => {
render(<ChatLog />, {wrapper: CustomizationWrapper});

const chatLog = screen.getByRole('log');
expect(chatLog).toHaveStyleRule('padding', '2.25rem');
});

it('should set element data attribute', () => {
render(<ChatLog />, {wrapper: CustomizationWrapper});

const chatLog = screen.getByRole('log');
expect(chatLog.getAttribute('data-paste-element')).toEqual('CHAT_LOG');
});

it('should add custom styles with a custom element data attribute', () => {
render(<ChatLog element="foo_log" />, {wrapper: CustomizationFooWrapper});

const chatLog = screen.getByRole('log');
expect(chatLog).toHaveStyleRule('padding', '2.25rem');
});

it('should set custom element data attribute', () => {
render(<ChatLog element="foo_log" />, {wrapper: CustomizationFooWrapper});

const chatLog = screen.getByRole('log');
expect(chatLog.getAttribute('data-paste-element')).toEqual('foo_log');
});
});
15 changes: 11 additions & 4 deletions packages/paste-core/components/chat-log/__tests__/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import {screen, render} from '@testing-library/react';
// @ts-ignore typescript doesn't like js imports
import axe from '../../../../../.jest/axe-helper';
import {ChatMessage, ChatBubble, ChatMessageMeta, ChatMessageMetaItem} from '../src';
import {ChatMessage, ChatBubble, ChatMessageMeta, ChatMessageMetaItem, ChatLog} from '../src';

describe('ChatMessage', () => {
it('should render a list element', () => {
Expand Down Expand Up @@ -93,11 +93,18 @@ describe('ChatMessageMeta', () => {
});
});

describe('ChatLog', () => {
it('should render', () => {
render(<ChatLog></ChatLog>);
expect(screen.getByRole('log')).toBeDefined();
expect(screen.getByRole('list')).toBeDefined();
});
});

describe('Accessibility', () => {
it('Should have no accessibility violations', async () => {
const {container} = render(
// todo: replace with ChatLog component
<ul>
<ChatLog>
<ChatMessage variant="inbound">
<ChatBubble>test</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 5:04pm">
Expand All @@ -111,7 +118,7 @@ describe('Accessibility', () => {
<ChatMessageMetaItem>2 minutes ago</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
</ul>
</ChatLog>
);
const results = await axe(container);
expect(results).toHaveNoViolations();
Expand Down
24 changes: 24 additions & 0 deletions packages/paste-core/components/chat-log/src/ChatLog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import {Box, safelySpreadBoxProps} from '@twilio-paste/box';

import type {ChatLogProps} from './types';

const ChatLog = React.forwardRef<HTMLDivElement, ChatLogProps>(({children, element = 'CHAT_LOG', ...props}, ref) => {
return (
<Box role="log" padding="space70" element={element} ref={ref} {...safelySpreadBoxProps(props)}>
<Box as="ul" margin="space0" padding="space0">
{children}
</Box>
</Box>
);
});

ChatLog.displayName = 'ChatLog';

ChatLog.propTypes = {
children: PropTypes.node,
element: PropTypes.string,
};

export {ChatLog};
1 change: 1 addition & 0 deletions packages/paste-core/components/chat-log/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from './ChatBubble';
export * from './ChatMessage';
export * from './ChatMessageMeta';
export * from './ChatMessageMetaItem';
export * from './ChatLog';
export * from './types';
7 changes: 7 additions & 0 deletions packages/paste-core/components/chat-log/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type {BoxElementProps} from '@twilio-paste/box';

export type MessageVariants = 'inbound' | 'outbound';

export interface ChatMessageProps {
Expand All @@ -21,3 +23,8 @@ export interface ChatMessageMetaItemProps {
children: NonNullable<React.ReactNode>;
element?: string;
}

export interface ChatLogProps {
children?: React.ReactNode;
element?: BoxElementProps['element'];
}
90 changes: 83 additions & 7 deletions packages/paste-core/components/chat-log/stories/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {Box} from '@twilio-paste/box';
import {HelpText} from '@twilio-paste/help-text';
import {Button} from '@twilio-paste/button';
import type {StoryFn} from '@storybook/react';
import {ChatMessage, ChatBubble, ChatMessageMeta, ChatMessageMetaItem} from '../src';
import {ChatMessage, ChatBubble, ChatMessageMeta, ChatMessageMetaItem, ChatLog} from '../src';

// eslint-disable-next-line import/no-default-export
export default {
Expand Down Expand Up @@ -62,9 +62,79 @@ export const OutboundMessageWithMeta: StoryFn = () => (
</>
);

export const ScrollingChatLog: StoryFn = () => (
<Box maxHeight="size40" overflowY="scroll">
<ChatLog>
<ChatMessage variant="inbound">
<ChatBubble>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 4:30pm">
<ChatMessageMetaItem>
<Avatar name="Gibby Radki" size="sizeIcon20" />
Gibby Radki
</ChatMessageMetaItem>
<ChatMessageMetaItem>4:30 PM</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant="outbound">
<ChatBubble>Nulla sit amet elit mauris.</ChatBubble>
<ChatMessageMeta aria-label="said by you at 4:32pm">
<ChatMessageMetaItem>4:32 PM</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant="outbound">
<ChatBubble>
Curabitur enim lorem, cursus et massa non, pretium faucibus lacus. Donec odio neque, consectetur a suscipit
sit amet, blandit id erat.
</ChatBubble>
<ChatMessageMeta aria-label="said by you at 4:48pm">
<ChatMessageMetaItem>4:48 PM</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant="inbound">
<ChatBubble>
Quisque ullamcorper ipsum vitae lorem euismod sodales. Donec a nisi eget eros laoreet pellentesque. Donec sed
bibendum justo, at ornare mi. Sed eget tempor metus, sed sagittis lacus. Donec commodo nisi in ligula accumsan
euismod. Nam ornare lobortis orci, eget rhoncus ligula euismod ut.{' '}
</ChatBubble>
<ChatBubble>Donec sit amet orci hendrerit, varius diam in, porttitor felis.</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 5:04pm">
<ChatMessageMetaItem>Gibby Radki</ChatMessageMetaItem>
<ChatMessageMetaItem>5:04 PM</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant="outbound">
<ChatBubble>Donec sit amet orci hendrerit, varius diam in, porttitor felis.</ChatBubble>
<ChatMessageMeta aria-label="said by you 2 minutes ago">
<ChatMessageMetaItem>2 minutes ago</ChatMessageMetaItem>
</ChatMessageMeta>
<ChatMessageMeta aria-label="(read)">
<ChatMessageMetaItem>Read</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
<ChatMessage variant="outbound">
<ChatBubble>
Praesent in lectus commodo orci faucibus ullamcorper. Nulla sit amet sapien consectetur, tempor ante eget,
sagittis orci. Curabitur enim lorem, cursus et massa non, pretium faucibus lacus.
</ChatBubble>
<ChatMessageMeta aria-label="Message failed">
<ChatMessageMetaItem>
<HelpText variant="error" marginTop="space0">
Message failed
</HelpText>
</ChatMessageMetaItem>
<ChatMessageMetaItem>
<Button variant="link" onClick={() => {}}>
Resend
</Button>
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
</ChatLog>
</Box>
);

export const KitchenSink: StoryFn = () => (
// replace with ChatLog
<Box as="ul">
<ChatLog>
<ChatMessage variant="inbound">
<ChatBubble>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki at 4:30pm">
Expand Down Expand Up @@ -129,13 +199,19 @@ export const KitchenSink: StoryFn = () => (
</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
</Box>
</ChatLog>
);

export const CustomizedMessages: StoryFn = () => (
export const CustomizedKitchenSink: StoryFn = () => (
<CustomizationProvider
baseTheme="default"
elements={{
CHAT_LOG: {
padding: 'space100',
borderStyle: 'solid',
borderColor: 'colorBorder',
borderWidth: 'borderWidth10',
},
CHAT_MESSAGE: {
marginBottom: 'space100',
variants: {
Expand Down Expand Up @@ -163,7 +239,7 @@ export const CustomizedMessages: StoryFn = () => (
},
}}
>
<Box as="ul" width="100%">
<ChatLog>
<ChatMessage variant="inbound">
<ChatBubble>test</ChatBubble>
<ChatMessageMeta aria-label="said by Gibby Radki 4 minutes ago">
Expand All @@ -183,6 +259,6 @@ export const CustomizedMessages: StoryFn = () => (
<ChatMessageMetaItem>Read</ChatMessageMetaItem>
</ChatMessageMeta>
</ChatMessage>
</Box>
</ChatLog>
</CustomizationProvider>
);

0 comments on commit c9ee672

Please sign in to comment.