-
Notifications
You must be signed in to change notification settings - Fork 77
[LG-5935] feat(message-feed) InitialMessage Subcomponent #3490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 38 commits
45120ed
1277ed5
defdad3
958d58a
c701f84
a6d7616
e427185
0d9295d
eb31dd4
fbb16db
478ee3c
43fc610
8b67331
8926ff5
bd83d5f
6441471
9e0a42e
bebc9bf
7dcc812
3516dd6
87414ee
7caaef2
e41b22b
5f6e619
1d87c3b
1ef0ae9
d4adca5
52846e0
eb70b3f
a33deba
d7f10d4
298ffc1
770c81f
5e005d2
bce10f3
c075973
9a145bc
499fc40
338cbec
9db8c4d
748ef93
da60688
730e077
308b6b5
9572937
72f8c20
abf16ff
e4afa54
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| import React from 'react'; | ||
| import { render, screen } from '@testing-library/react'; | ||
| import { axe } from 'jest-axe'; | ||
|
|
||
| import { MessageFeedProvider } from '../../MessageFeedContext'; | ||
|
|
||
| import { | ||
| INITIAL_MESSAGE_DESCRIPTION, | ||
| INITIAL_MESSAGE_TITLE, | ||
| } from './constants'; | ||
| import { InitialMessage } from './InitialMessage'; | ||
| import { InitialMessageProps } from './InitialMessage.types'; | ||
|
|
||
| jest.mock('@lg-chat/lg-markdown', () => ({ | ||
| LGMarkdown: jest.fn(({ children }) => <div>{children}</div>), | ||
| })); | ||
|
|
||
| const renderInitialMessage = ({ | ||
| shouldHideInitialMessage = false, | ||
| ...rest | ||
| }: InitialMessageProps & { shouldHideInitialMessage?: boolean }) => { | ||
| return render( | ||
| <MessageFeedProvider shouldHideInitialMessage={shouldHideInitialMessage}> | ||
| <InitialMessage {...rest} /> | ||
| </MessageFeedProvider>, | ||
| ); | ||
| }; | ||
|
|
||
| describe('InitialMessage', () => { | ||
| describe('a11y', () => { | ||
| test('does not have basic accessibility issues', async () => { | ||
| const { container } = renderInitialMessage({}); | ||
| const results = await axe(container); | ||
| expect(results).toHaveNoViolations(); | ||
| }); | ||
| }); | ||
|
|
||
| test('renders the title and description', () => { | ||
| renderInitialMessage({}); | ||
| expect(screen.getByText(INITIAL_MESSAGE_TITLE)).toBeInTheDocument(); | ||
| expect(screen.getByText(INITIAL_MESSAGE_DESCRIPTION)).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| test('renders the children', () => { | ||
| renderInitialMessage({ | ||
| children: <div>I heard you like MongoDB</div>, | ||
| }); | ||
| expect(screen.getByText('I heard you like MongoDB')).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| test('is hidden when the shouldHideInitialMessage is true', () => { | ||
| renderInitialMessage({ | ||
| shouldHideInitialMessage: true, | ||
| children: <div>I heard you like MongoDB</div>, | ||
| }); | ||
| expect(screen.getByText(INITIAL_MESSAGE_TITLE)).not.toBeVisible(); | ||
| expect(screen.getByText(INITIAL_MESSAGE_DESCRIPTION)).not.toBeVisible(); | ||
| expect(screen.getByText('I heard you like MongoDB')).not.toBeVisible(); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| import React from 'react'; | ||
| import { storybookArgTypes, StoryMetaType } from '@lg-tools/storybook-utils'; | ||
| import { StoryFn } from '@storybook/react'; | ||
|
|
||
| import { MessageFeedProvider } from '../../MessageFeedContext'; | ||
|
|
||
| import { InitialMessage, InitialMessageProps } from '.'; | ||
|
|
||
| const meta: StoryMetaType<typeof InitialMessage> = { | ||
| title: 'Composition/Chat/MessageFeed/InitialMessage', | ||
| component: InitialMessage, | ||
| parameters: { | ||
| default: 'LiveExample', | ||
| generate: { | ||
| combineArgs: { | ||
| darkMode: [false, true], | ||
| }, | ||
| decorator: Instance => { | ||
| return ( | ||
| <MessageFeedProvider shouldHideInitialMessage={false}> | ||
| <Instance /> | ||
| </MessageFeedProvider> | ||
| ); | ||
| }, | ||
| }, | ||
| }, | ||
| argTypes: { | ||
| darkMode: storybookArgTypes.darkMode, | ||
| }, | ||
| args: { | ||
| children: <div>I heard you like MongoDB</div>, // TODO: will replace with a real content in the next PR | ||
| }, | ||
| decorators: [ | ||
| Instance => ( | ||
| <MessageFeedProvider shouldHideInitialMessage={false}> | ||
| <Instance /> | ||
| </MessageFeedProvider> | ||
| ), | ||
| ], | ||
| }; | ||
|
|
||
| export default meta; | ||
|
|
||
| const Template: StoryFn<InitialMessageProps> = props => ( | ||
| <InitialMessage {...props} /> | ||
| ); | ||
|
|
||
| export const LiveExample = { | ||
| render: Template, | ||
| args: {}, | ||
| }; | ||
|
|
||
| export const Generated = () => {}; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import { css, cx } from '@leafygreen-ui/emotion'; | ||
| import { spacing, transitionDuration, typeScales } from '@leafygreen-ui/tokens'; | ||
|
|
||
| const FOCUS_RING_WIDTH = 4; | ||
|
|
||
| const baseOuterWrapperStyles = css` | ||
| display: grid; | ||
| grid-template-rows: 1fr; | ||
| gap: ${spacing[200]}px; | ||
| `; | ||
|
|
||
| const transitionStyles = css` | ||
| transform-origin: top left; | ||
| transition-property: grid-template-rows, opacity, transform; | ||
| transition-duration: ${transitionDuration.slower}ms; | ||
| transition-timing-function: ease-out; | ||
| `; | ||
|
|
||
| const hiddenWrapperStyles = css` | ||
| grid-template-rows: 0fr; | ||
| opacity: 0; | ||
| transform: scale(0.8); | ||
| `; | ||
|
|
||
| export const getWrapperStyles = ({ shouldHide }: { shouldHide: boolean }) => | ||
| cx(baseOuterWrapperStyles, transitionStyles, { | ||
| [hiddenWrapperStyles]: shouldHide, | ||
| }); | ||
|
|
||
| export const titleStyles = css` | ||
| font-size: ${typeScales.body2.fontSize}px; | ||
| line-height: ${typeScales.body2.lineHeight}px; | ||
| `; | ||
|
|
||
| export const innerWrapperStyles = css` | ||
| overflow: hidden; | ||
| margin: -${FOCUS_RING_WIDTH}px; | ||
| padding: ${FOCUS_RING_WIDTH}px; | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: ${spacing[400]}px; | ||
| `; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,58 @@ | ||||||
| import React, { forwardRef } from 'react'; | ||||||
| import { Message } from '@lg-chat/message'; | ||||||
|
|
||||||
| import { AssistantAvatar } from '@leafygreen-ui/avatar'; | ||||||
| import { CompoundSubComponent } from '@leafygreen-ui/compound-component'; | ||||||
| import { Body } from '@leafygreen-ui/typography'; | ||||||
|
|
||||||
| import { useMessageFeedContext } from '../../MessageFeedContext'; | ||||||
| import { MessageFeedSubcomponentProperty } from '../../shared.types'; | ||||||
|
|
||||||
| import { | ||||||
| INITIAL_MESSAGE_DESCRIPTION, | ||||||
| INITIAL_MESSAGE_TITLE, | ||||||
| } from './constants'; | ||||||
| import { | ||||||
| getWrapperStyles, | ||||||
| innerWrapperStyles, | ||||||
| titleStyles, | ||||||
| } from './InitialMessage.styles'; | ||||||
| import { type InitialMessageProps } from './InitialMessage.types'; | ||||||
| /** | ||||||
| * Renders an initial message in the message feed. | ||||||
| * | ||||||
| * @returns The rendered initial message component. | ||||||
| */ | ||||||
| export const InitialMessage = CompoundSubComponent( | ||||||
| // eslint-disable-next-line react/display-name | ||||||
| forwardRef<HTMLDivElement, InitialMessageProps>( | ||||||
| ({ children, ...rest }, fwdRef) => { | ||||||
| const { shouldHideInitialMessage } = useMessageFeedContext(); | ||||||
|
|
||||||
| return ( | ||||||
| <Message sourceType="markdown" isSender={false} ref={fwdRef} {...rest}> | ||||||
|
||||||
| <div | ||||||
| className={getWrapperStyles({ | ||||||
| shouldHide: shouldHideInitialMessage, | ||||||
| })} | ||||||
| > | ||||||
| <div className={innerWrapperStyles}> | ||||||
| <div> | ||||||
| <AssistantAvatar size={20} /> | ||||||
|
||||||
| <AssistantAvatar size={20} /> | |
| <AssistantAvatar size={AvatarSize.Large} /> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| import { MessageProps } from '@lg-chat/message'; | ||
|
|
||
| export interface InitialMessageProps | ||
| extends Omit<MessageProps, 'messageBody' | 'isSender'> {} | ||
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export const INITIAL_MESSAGE_TITLE = 'Hello! How can I help you?'; | ||
| export const INITIAL_MESSAGE_DESCRIPTION = | ||
| "I'm here to give expert guidance and recommendations for all things MongoDB."; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export { InitialMessage } from './InitialMessage'; | ||
| export { type InitialMessageProps } from './InitialMessage.types'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export { InitialMessage } from './InitialMessage'; | ||
|
||
Uh oh!
There was an error while loading. Please reload this page.