Skip to content

Commit b894e1b

Browse files
committed
feat(Message): Adjust components for use on white backgrounds
Added styles so components behave well on primary ChatBot background color (white). The specific components are the attachment label, table, loading indicator, and inline code block.
1 parent 9ae1deb commit b894e1b

File tree

12 files changed

+107
-18
lines changed

12 files changed

+107
-18
lines changed

packages/module/patternfly-docs/content/extensions/chatbot/examples/demos/WhiteEmbeddedChatbot.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ const MessageLoading = () => (
9797
export default MessageLoading;
9898
9999
~~~
100+
101+
Here is a table:
102+
103+
| Version | GA date | User role
104+
|-|-|-|
105+
| 2.5 | September 30, 2024 | Administrator |
106+
| 2.5 | June 27, 2023 | Editor |
107+
| 3.0 | April 1, 2025 | Administrator
100108
`;
101109

102110
// It's important to set a date and timestamp prop since the Message components re-render.
@@ -111,7 +119,8 @@ const initialMessages: MessageProps[] = [
111119
name: 'User',
112120
avatar: userAvatar,
113121
timestamp: date.toLocaleString(),
114-
avatarProps: { isBordered: true }
122+
avatarProps: { isBordered: true },
123+
isPrimary: true
115124
},
116125
{
117126
id: '2',
@@ -131,7 +140,9 @@ const initialMessages: MessageProps[] = [
131140
download: { onClick: () => console.log('Download') },
132141
// eslint-disable-next-line no-console
133142
listen: { onClick: () => console.log('Listen') }
134-
}
143+
},
144+
isPrimary: true,
145+
attachments: [{ name: 'auth-operator.yml', id: '1' }]
135146
}
136147
];
137148

@@ -220,7 +231,8 @@ export const EmbeddedChatbotDemo: FunctionComponent = () => {
220231
name: 'User',
221232
avatar: userAvatar,
222233
timestamp: date.toLocaleString(),
223-
avatarProps: { isBordered: true }
234+
avatarProps: { isBordered: true },
235+
isPrimary: true
224236
});
225237
newMessages.push({
226238
id: generateId(),
@@ -229,7 +241,8 @@ export const EmbeddedChatbotDemo: FunctionComponent = () => {
229241
name: 'Bot',
230242
avatar: patternflyAvatar,
231243
isLoading: true,
232-
timestamp: date.toLocaleString()
244+
timestamp: date.toLocaleString(),
245+
isPrimary: true
233246
});
234247
setMessages(newMessages);
235248
// make announcement to assistive devices that new messages have been added
@@ -261,7 +274,8 @@ export const EmbeddedChatbotDemo: FunctionComponent = () => {
261274
// eslint-disable-next-line no-console
262275
listen: { onClick: () => console.log('Listen') }
263276
},
264-
timestamp: date.toLocaleString()
277+
timestamp: date.toLocaleString(),
278+
isPrimary: true
265279
});
266280
setMessages(loadedMessages);
267281
// make announcement to assistive devices that new message has loaded

packages/module/src/FileDetailsLabel/FileDetailsLabel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { PropsWithChildren } from 'react';
2-
import { Button, Label } from '@patternfly/react-core';
2+
import { Button, Label, LabelProps } from '@patternfly/react-core';
33
import FileDetails from '../FileDetails';
44
import { Spinner } from '@patternfly/react-core';
55
import { TimesIcon } from '@patternfly/react-icons';
66

7-
export interface FileDetailsLabelProps {
7+
export interface FileDetailsLabelProps extends Omit<LabelProps, 'onClose' | 'onClick'> {
88
/** Name of file, including extension */
99
fileName: string;
1010
/** Unique id of file */

packages/module/src/Message/CodeBlockMessage/CodeBlockMessage.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@
8181
--pf-chatbot-message-text-inline-code-font-size: var(--pf-t--global--font--size--body--default);
8282
background-color: var(--pf-t--global--background--color--tertiary--default);
8383
font-size: var(--pf-chatbot-message-text-inline-code-font-size);
84+
85+
&.pf-m-primary {
86+
background-color: var(--pf-t--global--background--color--secondary--default);
87+
}
8488
}
8589

8690
.pf-chatbot__message-code-toggle {

packages/module/src/Message/CodeBlockMessage/CodeBlockMessage.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export interface CodeBlockMessageProps {
3939
collapsedText?: string;
4040
/** Custom actions added to header of code block, after any default actions such as the "copy" action. */
4141
customActions?: React.ReactNode;
42+
/** Sets background colors to be appropriate on primary chatbot background */
43+
isPrimary?: boolean;
4244
}
4345

4446
const DEFAULT_EXPANDED_TEXT = 'Show less';
@@ -54,6 +56,7 @@ const CodeBlockMessage = ({
5456
expandedText = DEFAULT_EXPANDED_TEXT,
5557
collapsedText = DEFAULT_COLLAPSED_TEXT,
5658
customActions,
59+
isPrimary,
5760
...props
5861
}: CodeBlockMessageProps) => {
5962
const [copied, setCopied] = useState(false);
@@ -108,7 +111,7 @@ const CodeBlockMessage = ({
108111

109112
if (!String(children).includes('\n')) {
110113
return (
111-
<code {...props} className="pf-chatbot__message-inline-code">
114+
<code {...props} className={`pf-chatbot__message-inline-code ${isPrimary ? 'pf-m-primary' : ''}`}>
112115
{children}
113116
</code>
114117
);

packages/module/src/Message/Message.test.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,4 +1093,41 @@ describe('Message', () => {
10931093
expect(screen.getByText('Thought for 3 seconds')).toBeTruthy();
10941094
expect(screen.getByText("Here's why I said this.")).toBeTruthy();
10951095
});
1096+
it('should handle isPrimary correctly for inline code when it is true', () => {
1097+
const { container } = render(<Message avatar="./img" role="user" name="User" content={INLINE_CODE} isPrimary />);
1098+
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
1099+
});
1100+
it('should handle isPrimary correctly for inline code when it is false', () => {
1101+
const { container } = render(<Message avatar="./img" role="user" name="User" content={INLINE_CODE} />);
1102+
expect(container.querySelector('.pf-m-primary')).toBeFalsy();
1103+
});
1104+
it('should handle isPrimary correctly for table when it is true', () => {
1105+
const { container } = render(<Message avatar="./img" role="user" name="User" content={TABLE} isPrimary />);
1106+
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
1107+
});
1108+
it('should handle isPrimary correctly for table when it is false', () => {
1109+
const { container } = render(<Message avatar="./img" role="user" name="User" content={TABLE} />);
1110+
expect(container.querySelector('.pf-m-primary')).toBeFalsy();
1111+
});
1112+
it('should handle isPrimary correctly for loading when it is true', () => {
1113+
const { container } = render(<Message avatar="./img" role="user" name="User" content="" isPrimary isLoading />);
1114+
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
1115+
});
1116+
it('should handle isPrimary correctly for loading when it is false', () => {
1117+
const { container } = render(<Message avatar="./img" role="user" name="User" content="" isLoading />);
1118+
1119+
expect(container.querySelector('.pf-m-primary')).toBeFalsy();
1120+
});
1121+
it('should handle isPrimary correctly for attachments when it is true', () => {
1122+
const { container } = render(
1123+
<Message avatar="./img" role="user" name="User" content="" isPrimary attachments={[{ name: 'testAttachment' }]} />
1124+
);
1125+
expect(container.querySelector('.pf-m-outline')).toBeTruthy();
1126+
});
1127+
it('should handle isPrimary correctly for attachments when it is false', () => {
1128+
const { container } = render(
1129+
<Message avatar="./img" role="user" name="User" content="" attachments={[{ name: 'testAttachment' }]} />
1130+
);
1131+
expect(container.querySelector('.pf-m-outline')).toBeFalsy();
1132+
});
10961133
});

packages/module/src/Message/Message.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
189189
toolCall?: ToolCallProps;
190190
/** Whether user messages default to stripping out images in markdown */
191191
hasNoImagesInUserMessages?: boolean;
192+
/** Sets background colors to be appropriate on primary chatbot background */
193+
isPrimary?: boolean;
192194
}
193195

194196
export const MessageBase: FunctionComponent<MessageProps> = ({
@@ -236,6 +238,7 @@ export const MessageBase: FunctionComponent<MessageProps> = ({
236238
remarkGfmProps,
237239
toolCall,
238240
hasNoImagesInUserMessages = true,
241+
isPrimary,
239242
...props
240243
}: MessageProps) => {
241244
const [messageText, setMessageText] = useState(content);
@@ -286,13 +289,13 @@ export const MessageBase: FunctionComponent<MessageProps> = ({
286289
p: (props) => {
287290
// eslint-disable-next-line @typescript-eslint/no-unused-vars
288291
const { node, ...rest } = props;
289-
return <TextMessage component={ContentVariants.p} {...rest} />;
292+
return <TextMessage component={ContentVariants.p} {...rest} isPrimary={isPrimary} />;
290293
},
291294
code: ({ children, ...props }) => {
292295
// eslint-disable-next-line @typescript-eslint/no-unused-vars
293296
const { node, ...codeProps } = props;
294297
return (
295-
<CodeBlockMessage {...codeProps} {...codeBlockProps}>
298+
<CodeBlockMessage {...codeProps} {...codeBlockProps} isPrimary={isPrimary}>
296299
{children}
297300
</CodeBlockMessage>
298301
);
@@ -348,7 +351,7 @@ export const MessageBase: FunctionComponent<MessageProps> = ({
348351
return <ListItemMessage {...rest} />;
349352
},
350353
// table requires node attribute for calculating headers for mobile breakpoint
351-
table: (props) => <TableMessage {...props} {...tableProps} />,
354+
table: (props) => <TableMessage {...props} {...tableProps} isPrimary={isPrimary} />,
352355
tbody: (props) => {
353356
// eslint-disable-next-line @typescript-eslint/no-unused-vars
354357
const { node, ...rest } = props;
@@ -416,7 +419,7 @@ export const MessageBase: FunctionComponent<MessageProps> = ({
416419

417420
const renderMessage = () => {
418421
if (isLoading) {
419-
return <MessageLoading loadingWord={loadingWord} />;
422+
return <MessageLoading loadingWord={loadingWord} isPrimary={isPrimary} />;
420423
}
421424
if (isEditable) {
422425
return (
@@ -522,6 +525,7 @@ export const MessageBase: FunctionComponent<MessageProps> = ({
522525
closeButtonAriaLabel={attachment.closeButtonAriaLabel}
523526
languageTestId={attachment.languageTestId}
524527
spinnerTestId={attachment.spinnerTestId}
528+
variant={isPrimary ? 'outline' : undefined}
525529
/>
526530
</div>
527531
))}

packages/module/src/Message/MessageLoading.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,8 @@
5050
background-color: rgba(41, 41, 41, 0.25);
5151
}
5252
}
53+
54+
&.pf-m-primary {
55+
background-color: var(--pf-t--global--background--color--secondary--default);
56+
}
5357
}

packages/module/src/Message/MessageLoading.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// Chatbot Main - Message - Processing
33
// ============================================================================
44

5-
const MessageLoading = ({ loadingWord }) => (
6-
<div className="pf-chatbot__message-loading">
5+
const MessageLoading = ({ loadingWord, isPrimary }) => (
6+
<div className={`pf-chatbot__message-loading ${isPrimary ? 'pf-m-primary' : ''}`}>
77
<span className="pf-chatbot__message-loading-dots">
88
<span className="pf-v6-screen-reader">{loadingWord}</span>
99
</span>

packages/module/src/Message/TableMessage/TableMessage.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
border-block-start: 0;
99
}
1010

11+
&.pf-m-primary {
12+
--pf-v6-c-table--BackgroundColor: var(--pf-t--global--background--color--secondary--default) !important;
13+
}
14+
1115
tbody {
1216
border-radius: var(--pf-t--global--border--radius--small);
1317
}

packages/module/src/Message/TableMessage/TableMessage.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ export interface TableNode {
1919
type: string;
2020
}
2121

22-
const TableMessage = ({ children, ...props }: Omit<TableProps, 'ref'> & ExtraProps) => {
22+
export interface TableMessageProps {
23+
isPrimary?: boolean;
24+
}
25+
26+
const TableMessage = ({ children, isPrimary, ...props }: Omit<TableProps, 'ref'> & ExtraProps & TableMessageProps) => {
2327
const { className, ...rest } = props;
2428

2529
// This allows us to parse the nested data we get back from the 3rd party Markdown parser
@@ -72,7 +76,7 @@ const TableMessage = ({ children, ...props }: Omit<TableProps, 'ref'> & ExtraPro
7276
<Table
7377
aria-label={props['aria-label']}
7478
gridBreakPoint="grid"
75-
className={`pf-chatbot__message-table ${className ? className : ''}`}
79+
className={`pf-chatbot__message-table ${isPrimary ? 'pf-m-primary' : ''} ${className ? className : ''}`}
7680
{...rest}
7781
>
7882
{modifyChildren(children)}

0 commit comments

Comments
 (0)