Skip to content

Commit 10e1e8a

Browse files
authored
[LG-5936] feat(message-feed): ResourceList Subcomponent (#3495)
* refactor(MessageFeed): convert to CompoundComponent and temp remove assistant name * refactor(MessageFeed): enhance component structure * feat(MessageFeed): add MessageFeedContext * docs(MessageFeed): add changeset * fix(MessageFeed): update error message for context provider * refactor(Message): undo message changes * chore(MessageFeed): add compound-component dependency * chore(pnpm-lock): add compound-component to dependencies * chore(MessageFeed): update dependencies for compound-component integration * refactor(MessageFeed): move shared types * refactor(InitialMessage): update import path for shared types and use enum for key * feat(InitialMessage): integrate MessageFeedContext to manage initial message visibility * chore(changeset): update dependency version for @lg-chat/message-feed * fix(tsconfig): add missing newline at end of file * fix(MessageFeedContext): handle error boundary for React 17 in context hook tests * feat(InitialMessage): implement styles and update component structure for initial message display * feat(InitialMessage): enhance initial message component with structured content and styles * refactor(InitialMessage): replace hardcoded title and description with constants for improved maintainability * feat(ChatWindow): add initial message prompts and enhance message handling in chat window stories * refactor(ChatWindow): remove enableHideOnSelect prop from Suggested Prompts in initial message component * test(InitialMessage): add unit tests for accessibility, rendering, and visibility behavior * test(MessageFeed): enhance tests with scrollTo mock and update query methods for initial message visibility * refactor(InitialMessage): simplify getWrapperStyles function and remove unused props * chore(MessageFeed): update dependencies and tsconfig to include new LeafyGreen UI components * refactor(ChatWindow): rename initial message component and update props for message prompts * chore(MessageFeed): remove unused @leafygreen-ui/hooks dependency from package.json and pnpm-lock.yaml * refactor(MessageFeed): remove commented-out MyMessage component from InitialMessage story * chore(MessageFeed): update changeset * refactor(MessageFeed): integrate MessagePrompts and MessagePrompt components into InitialMessage * refactor(InitialMessage): update styles for title and description components * refactor(InitialMessage): adjust inner wrapper styles with focus ring for improved layout * test(InitialMessage, MessagePrompt, MessagePrompts): enhance tests for rendering and type validation * refactor(InitialMessage): rename component and add message prompts for enhanced user interaction * chore(pnpm-lock): add '@lg-chat/message-prompts' dependency and clean up unused entries * test(InitialMessage, MessagePrompts): improve error handling tests for enableHideOnSelect prop * chore(changeset): update to include new components * test(InitialMessage): fix JSX syntax in type validation tests for proper rendering * test(MessageFeed): add tests for rendering MessagePrompts and its child MessagePrompt components * feat(MessageFeed): add ResourceLists and ResourceList properties to MessageFeedSubcomponentProperty * feat(MessageFeed): add InitialMessageWithResourceList story and update InitialMessage component to include ResourceList and ResourceListItem * refactor(InitialMessage): restructure inner wrapper and remove description styles for cleaner layout * refactor(ResourceListItem): update styles to use theme-based icon colors and improve structure * refactor(InitialMessage): integrate LeafyGreenProvider for dark mode support and simplify props in stories * test(InitialMessage, MessageFeed): update tests to ensure proper rendering of MessagePrompts and prevent rendering of children when not a subcomponent * refactor(InitialMessage): remove LeafyGreenProvider and simplify component structure for improved readability * refactor(InitialMessage): remove LeafyGreenProvider and streamline component structure for improved readability * feat(InitialMessage): add generated story for initialMessage * feat(InitialMessage): enhance story with interactive MessagePrompts and update children prop for better demonstration * chore(ALL_PACKAGES): revert ALL_PACKAGES * fix(InitialMessage): remove unused darkMode prop from story and include resourceList in the InitialMessage component * feat(ResourceList): integrate LeafyGreenProvider for dark mode support and update ResourceListProps to include DarkModeProps * feat(InitialMessage): add additional resource list items and update story configuration for enhanced interactivity * fix(ResourceListItem): update prop documentation for glyph and children to clarify usage * docs(MessageFeed): update changeset * refactor(InitialMessage): update AssistantAvatar size and adjust props in InitialMessage types for improved clarity * fix(InitialMessage): export InitialMessageProps type for better type safety * refactor(InitialMessage): Components to components * refactor(InitialMessage): update import paths from Components to components * feat(InitialMessage): add interactive story for message addition with state management * fix(InitialMessage): add visibility property to transition styles for improved animation handling * feat(MessageFeed): enhance InitialMessage stories with new message handling and improve visibility checks in tests * feat(InitialMessage): rename Components to components * fix(InitialMessage): update import paths from Components to components for consistency * refactor(InitialMessage): replace MessageFeedSubcomponentProperty with InitialMessageSubcomponentProperty in relevant components * feat(MessagePromptsItem): add MessagePromptsItem component with associated types and tests * refactor(MessagePrompts): rename MessagePrompt to MessagePromptsItem across components and update related tests and stories * feat(InitialMessage): implement InitialMessage component with accessibility tests, styles, and subcomponents for prompts and resource lists * fix(MessageFeed): correct import paths for InitialMessage component * feat(ResourceListItem): export ResourceListItemProps type for improved type safety * test(InitialMessage): add tests for ResourceList subcomponent and update existing tests * refactor(MessageFeed): simplify initial message handling by removing unnecessary state and improving readability * refactor(MessageFeed): export InitialMessageProps type for better accessibility in message feed components * feat(index): export ResourceList and its props for improved component accessibility * refactor(MessageFeed): export additional message prompts types for improved component integration
1 parent f74ae7e commit 10e1e8a

17 files changed

+296
-2
lines changed

.changeset/dark-pots-tell.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
- [LG-5934](https://jira.mongodb.org/browse/LG-5934): add `MessageFeedProvider` and `useMessageFeedContext`
77
- [LG-5935](https://jira.mongodb.org/browse/LG-5935): add `MessageFeed.InitialMessage` component
88
- [LG-5933](https://jira.mongodb.org/browse/LG-5933): add `MessageFeed.InitialMessage.MessagePrompts` and `MessageFeed.InitialMessage.MessagePrompt` components.
9+
- [LG-5936](https://jira.mongodb.org/browse/LG-5936): add `MessageFeed.InitialMessage.ResourceList` and `MessageFeed.InitialMessage.ResourceListItem` components.

chat/message-feed/src/MessageFeed.stories.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,31 @@ const ChangingMessagesComponent = ({ darkMode, ...rest }: MessageFeedProps) => {
163163
);
164164
};
165165

166+
export const InitialMessageWithResourceList = ({
167+
...rest
168+
}: MessageFeedProps) => {
169+
return (
170+
<div>
171+
<MessageFeed style={{ width: 400, height: 400 }} {...rest}>
172+
<MessageFeed.InitialMessage>
173+
<MessageFeed.InitialMessage.ResourceList>
174+
<MessageFeed.InitialMessage.ResourceListItem glyph="QuestionMarkWithCircle">
175+
Ask me technical questions
176+
</MessageFeed.InitialMessage.ResourceListItem>
177+
<MessageFeed.InitialMessage.ResourceListItem glyph="Bulb">
178+
Learn best practices
179+
</MessageFeed.InitialMessage.ResourceListItem>
180+
<MessageFeed.InitialMessage.ResourceListItem glyph="InfoWithCircle">
181+
Note: I won’t have access to any of your data unless you provide
182+
it
183+
</MessageFeed.InitialMessage.ResourceListItem>
184+
</MessageFeed.InitialMessage.ResourceList>
185+
</MessageFeed.InitialMessage>
186+
</MessageFeed>
187+
</div>
188+
);
189+
};
190+
166191
export const InitialMessageWithMessagePrompts = ({
167192
...rest
168193
}: MessageFeedProps) => {

chat/message-feed/src/components/InitialMessage/InitialMessage.spec.tsx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,35 @@ describe('InitialMessage', () => {
8888
expect(screen.getByText('What is blue but not heavy?')).toBeInTheDocument();
8989
});
9090

91+
// renders the ResourceList subcomponent
92+
test('renders the ResourceList subcomponent', () => {
93+
renderInitialMessage({
94+
children: (
95+
<InitialMessage.ResourceList>
96+
<InitialMessage.ResourceListItem glyph="QuestionMarkWithCircle">
97+
Ask me technical questions
98+
</InitialMessage.ResourceListItem>
99+
<InitialMessage.ResourceListItem glyph="Bulb">
100+
Learn best practices
101+
</InitialMessage.ResourceListItem>
102+
<InitialMessage.ResourceListItem glyph="InfoWithCircle">
103+
Note: I won’t have access to any of your data unless you provide it
104+
</InitialMessage.ResourceListItem>
105+
</InitialMessage.ResourceList>
106+
),
107+
});
108+
expect(screen.getByText('Ask me technical questions')).toBeInTheDocument();
109+
expect(screen.getByText('Learn best practices')).toBeInTheDocument();
110+
expect(
111+
screen.getByText(
112+
'Note: I won’t have access to any of your data unless you provide it',
113+
),
114+
).toBeInTheDocument();
115+
});
116+
91117
/* eslint-disable jest/no-disabled-tests */
92118
describe.skip('types behave as expected', () => {
93-
test('does not throw errors', () => {
119+
test('does not throw errors with MessagePrompts subcomponent', () => {
94120
<InitialMessage>
95121
<InitialMessage.MessagePrompts label="hello">
96122
<InitialMessage.MessagePromptsItem selected>
@@ -106,6 +132,16 @@ describe('InitialMessage', () => {
106132
</InitialMessage>;
107133
});
108134

135+
test('does not throw errors with ResourceList subcomponent', () => {
136+
<InitialMessage>
137+
<InitialMessage.ResourceList>
138+
<InitialMessage.ResourceListItem glyph="QuestionMarkWithCircle">
139+
Ask me technical questions
140+
</InitialMessage.ResourceListItem>
141+
</InitialMessage.ResourceList>
142+
</InitialMessage>;
143+
});
144+
109145
test('throws errors when enableHideOnSelect is used', () => {
110146
<InitialMessage>
111147
{/* @ts-expect-error - enableHideOnSelect is not a prop */}

chat/message-feed/src/components/InitialMessage/InitialMessage.stories.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,26 @@ const messagePrompts = [
1818
<InitialMessage.MessagePromptsItem>
1919
How do I query MongoDB?
2020
</InitialMessage.MessagePromptsItem>
21+
<InitialMessage.MessagePromptsItem>
22+
What is MongoDB&apos;s favorite color?
23+
</InitialMessage.MessagePromptsItem>
2124
</InitialMessage.MessagePrompts>,
2225
];
2326

27+
const resourceList = [
28+
<InitialMessage.ResourceList key="resource-list">
29+
<InitialMessage.ResourceListItem glyph="QuestionMarkWithCircle">
30+
Ask me technical questions
31+
</InitialMessage.ResourceListItem>
32+
<InitialMessage.ResourceListItem glyph="Bulb">
33+
Learn best practices
34+
</InitialMessage.ResourceListItem>
35+
<InitialMessage.ResourceListItem glyph="InfoWithCircle">
36+
Note: I won’t have access to any of your data unless you provide it
37+
</InitialMessage.ResourceListItem>
38+
</InitialMessage.ResourceList>,
39+
];
40+
2441
const meta: StoryMetaType<typeof InitialMessage> = {
2542
title: 'Composition/Chat/MessageFeed/InitialMessage',
2643
component: InitialMessage,
@@ -29,7 +46,7 @@ const meta: StoryMetaType<typeof InitialMessage> = {
2946
generate: {
3047
combineArgs: {
3148
darkMode: [false, true],
32-
children: [messagePrompts, undefined],
49+
children: [messagePrompts, resourceList, undefined],
3350
},
3451
decorator: Instance => {
3552
return (

chat/message-feed/src/components/InitialMessage/InitialMessage.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { useMessageFeedContext } from '../../MessageFeedContext';
1212
import { MessageFeedSubcomponentProperty } from '../../shared.types';
1313
import { MessagePrompts } from '../MessagePrompts';
1414
import { MessagePromptsItem } from '../MessagePromptsItem';
15+
import { ResourceList } from '../ResourceList';
16+
import { ResourceListItem } from '../ResourceListItem';
1517

1618
import {
1719
INITIAL_MESSAGE_DESCRIPTION,
@@ -42,6 +44,11 @@ export const InitialMessage = CompoundSubComponent(
4244
InitialMessageSubcomponentProperty.MessagePrompts,
4345
);
4446

47+
const resourceList = findChild(
48+
children,
49+
InitialMessageSubcomponentProperty.ResourceList,
50+
);
51+
4552
return (
4653
<Message isSender={false} ref={fwdRef} {...rest}>
4754
<div
@@ -58,6 +65,7 @@ export const InitialMessage = CompoundSubComponent(
5865
<Body>{INITIAL_MESSAGE_DESCRIPTION}</Body>
5966
</div>
6067
{messagePrompts}
68+
{resourceList}
6169
</div>
6270
</div>
6371
</Message>
@@ -69,5 +77,7 @@ export const InitialMessage = CompoundSubComponent(
6977
key: MessageFeedSubcomponentProperty.InitialMessage,
7078
MessagePrompts,
7179
MessagePromptsItem,
80+
ResourceList,
81+
ResourceListItem,
7282
},
7383
);

chat/message-feed/src/components/InitialMessage/InitialMessage.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export interface InitialMessageProps
1313
export const InitialMessageSubcomponentProperty = {
1414
MessagePrompts: 'isLGInitialMessageMessagePrompts',
1515
MessagePromptsItem: 'isLGInitialMessageMessagePromptsItem',
16+
ResourceList: 'isLGInitialMessageResourceList',
17+
ResourceListItem: 'isLGInitialMessageResourceListItem',
1618
} as const;
1719

1820
/**
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import React from 'react';
2+
import { storybookArgTypes, StoryMetaType } from '@lg-tools/storybook-utils';
3+
import { StoryFn } from '@storybook/react';
4+
5+
import { ResourceListItem } from '../ResourceListItem';
6+
7+
import { ResourceList, ResourceListProps } from '.';
8+
9+
const meta: StoryMetaType<typeof ResourceList> = {
10+
title: 'Composition/Chat/MessageFeed/ResourceList',
11+
component: ResourceList,
12+
parameters: {
13+
default: 'LiveExample',
14+
generate: {
15+
combineArgs: {
16+
darkMode: [false, true],
17+
},
18+
},
19+
},
20+
argTypes: {
21+
darkMode: storybookArgTypes.darkMode,
22+
},
23+
args: {
24+
children: [
25+
<ResourceListItem
26+
key="resource-list-item-1"
27+
glyph="QuestionMarkWithCircle"
28+
>
29+
Ask me technical questions
30+
</ResourceListItem>,
31+
<ResourceListItem key="resource-list-item-2" glyph="Bulb">
32+
Learn best practices
33+
</ResourceListItem>,
34+
<ResourceListItem key="resource-list-item-3" glyph="InfoWithCircle">
35+
Note: I won’t have access to any of your data unless you provide it
36+
</ResourceListItem>,
37+
],
38+
},
39+
};
40+
41+
export default meta;
42+
43+
const Template: StoryFn<ResourceListProps> = props => (
44+
<ResourceList {...props} />
45+
);
46+
47+
export const LiveExample = {
48+
render: Template,
49+
args: {},
50+
};
51+
52+
export const Generated = () => {};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { css, cx } from '@leafygreen-ui/emotion';
2+
import { spacing } from '@leafygreen-ui/tokens';
3+
4+
export const getListStyles = ({ className }: { className?: string }) =>
5+
cx(
6+
css`
7+
display: flex;
8+
flex-direction: column;
9+
gap: ${spacing[400]}px;
10+
padding: 0;
11+
margin: 0;
12+
`,
13+
className,
14+
);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React, { forwardRef } from 'react';
2+
3+
import { CompoundSubComponent } from '@leafygreen-ui/compound-component';
4+
import LeafyGreenProvider, {
5+
useDarkMode,
6+
} from '@leafygreen-ui/leafygreen-provider';
7+
8+
import { InitialMessageSubcomponentProperty } from '../InitialMessage/InitialMessage.types';
9+
10+
import { getListStyles } from './ResourceList.styles';
11+
import { type ResourceListProps } from './ResourceList.types';
12+
13+
/**
14+
* Renders a resource list in the message feed.
15+
*
16+
* @returns The rendered resource list component.
17+
*/
18+
export const ResourceList = CompoundSubComponent(
19+
// eslint-disable-next-line react/display-name
20+
forwardRef<HTMLUListElement, ResourceListProps>(
21+
({ children, className, darkMode: darkModeProp, ...rest }, fwdRef) => {
22+
const { darkMode } = useDarkMode(darkModeProp);
23+
return (
24+
<LeafyGreenProvider darkMode={darkMode}>
25+
<ul ref={fwdRef} className={getListStyles({ className })} {...rest}>
26+
{children}
27+
</ul>
28+
</LeafyGreenProvider>
29+
);
30+
},
31+
),
32+
{
33+
displayName: 'ResourceList',
34+
key: InitialMessageSubcomponentProperty.ResourceList,
35+
},
36+
);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { ComponentPropsWithRef } from 'react';
2+
3+
import { DarkModeProps } from '@leafygreen-ui/lib';
4+
5+
export interface ResourceListProps
6+
extends ComponentPropsWithRef<'ul'>,
7+
DarkModeProps {}

0 commit comments

Comments
 (0)