@patternfly/chatbot 6.9.0-prerelease.1 → 6.9.0-prerelease.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/cjs/Chatbot/Chatbot.d.ts +2 -0
  2. package/dist/cjs/Chatbot/Chatbot.js +2 -2
  3. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +1 -1
  4. package/dist/cjs/ChatbotFooter/ChatbotFootnote.js +1 -1
  5. package/dist/cjs/ChatbotModal/ChatbotModal.js +1 -1
  6. package/dist/cjs/ChatbotWelcomePrompt/ChatbotWelcomePrompt.js +1 -1
  7. package/dist/cjs/MessageBar/MessageBar.d.ts +1 -1
  8. package/dist/cjs/MessageBar/MessageBar.js +4 -3
  9. package/dist/cjs/MessageBar/SendButton.js +2 -2
  10. package/dist/cjs/SourcesCard/SourcesCard.d.ts +2 -0
  11. package/dist/cjs/SourcesCardBase/SourcesCardBase.d.ts +2 -0
  12. package/dist/cjs/SourcesCardBase/SourcesCardBase.js +2 -2
  13. package/dist/css/main.css +201 -66
  14. package/dist/css/main.css.map +1 -1
  15. package/dist/esm/Chatbot/Chatbot.d.ts +2 -0
  16. package/dist/esm/Chatbot/Chatbot.js +3 -3
  17. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +1 -1
  18. package/dist/esm/ChatbotFooter/ChatbotFootnote.js +1 -1
  19. package/dist/esm/ChatbotModal/ChatbotModal.js +1 -1
  20. package/dist/esm/ChatbotWelcomePrompt/ChatbotWelcomePrompt.js +1 -1
  21. package/dist/esm/MessageBar/MessageBar.d.ts +1 -1
  22. package/dist/esm/MessageBar/MessageBar.js +4 -3
  23. package/dist/esm/MessageBar/SendButton.js +2 -2
  24. package/dist/esm/SourcesCard/SourcesCard.d.ts +2 -0
  25. package/dist/esm/SourcesCardBase/SourcesCardBase.d.ts +2 -0
  26. package/dist/esm/SourcesCardBase/SourcesCardBase.js +2 -2
  27. package/package.json +9 -9
  28. package/patternfly-docs/content/extensions/chatbot/chatbot.md +1 -0
  29. package/patternfly-docs/content/extensions/chatbot/examples/Analytics/Analytics.md +1 -1
  30. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithSources.tsx +31 -0
  31. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +2 -0
  32. package/patternfly-docs/content/extensions/chatbot/examples/demos/Canvas.md +132 -0
  33. package/patternfly-docs/content/extensions/chatbot/examples/demos/Canvas.tsx +615 -0
  34. package/patternfly-docs/content/extensions/chatbot/examples/demos/CanvasWithDockedNav.tsx +697 -0
  35. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +39 -5
  36. package/patternfly-docs/content/extensions/chatbot/examples/demos/FullscreenDockedNav.tsx +385 -0
  37. package/patternfly-docs/patternfly-docs.config.js +1 -1
  38. package/src/Canvas/Canvas.scss +150 -0
  39. package/src/Chatbot/Chatbot.scss +13 -1
  40. package/src/Chatbot/Chatbot.test.tsx +11 -0
  41. package/src/Chatbot/Chatbot.tsx +5 -1
  42. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +91 -77
  43. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +32 -13
  44. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +1 -0
  45. package/src/ChatbotFooter/ChatbotFooternote.test.tsx +50 -0
  46. package/src/ChatbotFooter/ChatbotFootnote.tsx +1 -1
  47. package/src/ChatbotModal/ChatbotModal.scss +2 -7
  48. package/src/ChatbotModal/ChatbotModal.tsx +1 -0
  49. package/src/ChatbotToggle/ChatbotToggle.scss +3 -2
  50. package/src/ChatbotToggle/ChatbotToggle.test.tsx +4 -0
  51. package/src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.scss +9 -0
  52. package/src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx +4 -2
  53. package/src/FileDetails/__snapshots__/FileDetails.test.tsx.snap +2 -6
  54. package/src/FileDetailsLabel/__snapshots__/FileDetailsLabel.test.tsx.snap +2 -6
  55. package/src/Message/Message.scss +9 -0
  56. package/src/MessageBar/AttachButton.scss +4 -21
  57. package/src/MessageBar/MessageBar.scss +2 -2
  58. package/src/MessageBar/MessageBar.test.tsx +20 -0
  59. package/src/MessageBar/MessageBar.tsx +7 -3
  60. package/src/MessageBar/SendButton.scss +1 -32
  61. package/src/MessageBar/SendButton.tsx +2 -2
  62. package/src/SourcesCard/SourcesCard.scss +6 -0
  63. package/src/SourcesCard/SourcesCard.test.tsx +16 -0
  64. package/src/SourcesCard/SourcesCard.tsx +2 -0
  65. package/src/SourcesCardBase/SourcesCardBase.test.tsx +62 -0
  66. package/src/SourcesCardBase/SourcesCardBase.tsx +8 -0
  67. package/src/main.scss +1 -0
@@ -172,81 +172,91 @@
172
172
 
173
173
  // Chatbot Header - Drawer
174
174
  // ----------------------------------------------------------------------------
175
+ // Child combinators keep these rules off nested drawers such as canvas.
175
176
  .pf-chatbot__history.pf-v6-c-drawer {
176
- --pf-v6-c-drawer__panel--MinWidth: 24rem;
177
- --pf-v6-c-drawer__panel--xl--MinWidth: 24rem;
178
177
  height: 70vh;
179
178
 
180
179
  // Drawer panel
181
- .pf-v6-c-drawer__panel {
180
+ > .pf-v6-c-drawer__main > .pf-v6-c-drawer__panel {
181
+ --pf-v6-c-drawer__panel--MinWidth: 24rem;
182
+ --pf-v6-c-drawer__panel--xl--MinWidth: 24rem;
182
183
  --pf-v6-c-drawer__panel--BackgroundColor: var(--pf-t--global--background--color--floating--default);
184
+ --pf-v6-c-drawer__panel--m-inline--BackgroundColor: var(--pf-t--global--background--color--floating--default);
185
+ --pf-v6-c-drawer__panel--m-inline--md--BackgroundColor: var(--pf-t--global--background--color--floating--default);
183
186
  --pf-v6-c-drawer__panel--PaddingBlockStart: var(--pf-t--global--spacer--lg);
184
187
  --pf-v6-c-drawer__panel--PaddingBlockEnd: var(--pf-t--global--spacer--lg);
185
188
  --pf-v6-c-drawer__panel--RowGap: var(--pf-t--global--spacer--gap--group-to-group--vertical--default);
186
189
  overflow-x: hidden;
187
190
  overflow-y: hidden;
188
- }
189
191
 
190
- // Drawer head
191
- .pf-v6-c-drawer__head {
192
- --pf-v6-c-drawer__head--PaddingBlockStart: 0;
193
- --pf-v6-c-drawer__head--PaddingBlockEnd: 0;
194
- --pf-v6-c-drawer__head--PaddingInlineStart: var(--pf-t--global--spacer--lg);
195
- --pf-v6-c-drawer__head--PaddingInlineEnd: var(--pf-t--global--spacer--lg);
192
+ // Drawer head
193
+ .pf-v6-c-drawer__head {
194
+ --pf-v6-c-drawer__head--PaddingBlockStart: 0;
195
+ --pf-v6-c-drawer__head--PaddingBlockEnd: 0;
196
+ --pf-v6-c-drawer__head--PaddingInlineStart: var(--pf-t--global--spacer--lg);
197
+ --pf-v6-c-drawer__head--PaddingInlineEnd: var(--pf-t--global--spacer--lg);
196
198
 
197
- display: flex;
198
- align-items: center;
199
- justify-content: space-between;
200
- height: var(--pf-t--global--spacer--2xl);
201
- }
199
+ display: flex;
200
+ align-items: center;
201
+ justify-content: space-between;
202
+ height: var(--pf-t--global--spacer--2xl);
203
+ }
202
204
 
203
- // Drawer actions
204
- .pf-v6-c-drawer__actions {
205
- --pf-v6-c-drawer__actions--MarginBlockStart: 0;
206
- --pf-v6-c-drawer__actions--MarginInlineEnd: 0;
205
+ // Drawer actions
206
+ .pf-v6-c-drawer__actions {
207
+ --pf-v6-c-drawer__actions--MarginBlockStart: 0;
208
+ --pf-v6-c-drawer__actions--MarginInlineEnd: 0;
207
209
 
208
- display: flex;
209
- align-items: center;
210
- justify-content: space-between;
211
- align-self: center;
212
- width: 100%;
213
- height: 100%;
214
- }
210
+ display: flex;
211
+ align-items: center;
212
+ justify-content: space-between;
213
+ align-self: center;
214
+ width: 100%;
215
+ height: 100%;
216
+ }
215
217
 
216
- .pf-v6-c-drawer__actions--reversed {
217
- flex-direction: row-reverse;
218
- }
218
+ .pf-v6-c-drawer__actions--reversed {
219
+ flex-direction: row-reverse;
220
+ }
219
221
 
220
- // Close drawer
221
- .pf-v6-c-drawer__close {
222
- .pf-v6-c-button {
223
- width: var(--pf-t--global--spacer--2xl);
224
- height: var(--pf-t--global--spacer--2xl);
225
- border-radius: var(--pf-t--global--border--radius--pill);
226
- justify-content: center;
227
- align-items: center;
222
+ // Close drawer
223
+ .pf-v6-c-drawer__close {
224
+ .pf-v6-c-button {
225
+ width: var(--pf-t--global--spacer--2xl);
226
+ height: var(--pf-t--global--spacer--2xl);
227
+ border-radius: var(--pf-t--global--border--radius--pill);
228
+ justify-content: center;
229
+ align-items: center;
230
+ }
228
231
  }
229
- }
230
232
 
231
- // Drawer body
232
- .pf-v6-c-drawer__body {
233
- --pf-v6-c-drawer__panel__body--PaddingBlockStart: 0;
234
- --pf-v6-c-drawer__panel__body--PaddingBlockEnd: 0;
235
- --pf-v6-c-drawer__panel__body--PaddingInlineStart: var(--pf-t--global--spacer--lg);
236
- --pf-v6-c-drawer__panel__body--PaddingInlineEnd: var(--pf-t--global--spacer--lg);
233
+ // Drawer body
234
+ .pf-v6-c-drawer__body {
235
+ --pf-v6-c-drawer__panel__body--PaddingBlockStart: 0;
236
+ --pf-v6-c-drawer__panel__body--PaddingBlockEnd: 0;
237
+ --pf-v6-c-drawer__panel__body--PaddingInlineStart: var(--pf-t--global--spacer--lg);
238
+ --pf-v6-c-drawer__panel__body--PaddingInlineEnd: var(--pf-t--global--spacer--lg);
239
+
240
+ overflow-y: auto;
241
+ display: flex;
242
+ flex-direction: column;
243
+ height: 70vh;
244
+ }
237
245
 
246
+ // Resizable drawer spacing is different - needs manual adjustment for gaps between buttons, inputs, etc.
247
+ &.pf-m-resizable {
248
+ .pf-v6-c-drawer__panel-main {
249
+ row-gap: var(--pf-v6-c-drawer__panel--RowGap);
250
+ }
251
+ }
252
+ }
253
+
254
+ > .pf-v6-c-drawer__main > .pf-v6-c-drawer__content > .pf-v6-c-drawer__body {
238
255
  overflow-y: auto;
239
256
  display: flex;
240
257
  flex-direction: column;
241
258
  height: 70vh;
242
259
  }
243
-
244
- // Resizable drawer spacing is different - needs manual adjustment for gaps between buttons, inputs, etc.
245
- .pf-v6-c-drawer__panel.pf-m-resizable {
246
- .pf-v6-c-drawer__panel-main {
247
- row-gap: var(--pf-v6-c-drawer__panel--RowGap);
248
- }
249
- }
250
260
  }
251
261
 
252
262
  .pf-chatbot:is(.pf-chatbot--drawer, .pf-chatbot--docked) .pf-chatbot__history {
@@ -279,7 +289,9 @@
279
289
  .pf-chatbot--fullscreen {
280
290
  .pf-chatbot__history.pf-v6-c-drawer {
281
291
  height: 100vh;
282
- .pf-v6-c-drawer__body {
292
+
293
+ > .pf-v6-c-drawer__main > .pf-v6-c-drawer__content > .pf-v6-c-drawer__body,
294
+ > .pf-v6-c-drawer__main > .pf-v6-c-drawer__panel .pf-v6-c-drawer__body {
283
295
  width: 100%;
284
296
  }
285
297
  }
@@ -291,11 +303,14 @@
291
303
  .pf-chatbot--embedded {
292
304
  .pf-chatbot__history.pf-v6-c-drawer {
293
305
  height: 100%;
294
- .pf-v6-c-drawer__body {
306
+
307
+ > .pf-v6-c-drawer__main > .pf-v6-c-drawer__content > .pf-v6-c-drawer__body,
308
+ > .pf-v6-c-drawer__main > .pf-v6-c-drawer__panel .pf-v6-c-drawer__body {
295
309
  width: 100%;
296
310
  height: 100%;
297
311
  }
298
- .pf-v6-c-drawer__panel {
312
+
313
+ > .pf-v6-c-drawer__main > .pf-v6-c-drawer__panel {
299
314
  height: 100%;
300
315
  }
301
316
  }
@@ -327,37 +342,36 @@
327
342
  }
328
343
 
329
344
  .pf-chatbot__history.pf-m-compact {
330
- .pf-v6-c-drawer__main {
331
- .pf-v6-c-drawer__panel {
332
- --pf-v6-c-drawer__panel--PaddingBlockStart: var(--pf-t--global--spacer--sm);
333
- --pf-v6-c-drawer__panel--PaddingBlockEnd: var(--pf-t--global--spacer--sm);
334
- --pf-v6-c-drawer__head--PaddingInlineStart: var(--pf-t--global--spacer--md);
335
- --pf-v6-c-drawer__head--PaddingInlineEnd: var(--pf-t--global--spacer--md);
336
- --pf-v6-c-drawer__panel--RowGap: var(--pf-t--global--spacer--md);
337
- }
345
+ > .pf-v6-c-drawer__main > .pf-v6-c-drawer__panel {
346
+ --pf-v6-c-drawer__panel--PaddingBlockStart: var(--pf-t--global--spacer--sm);
347
+ --pf-v6-c-drawer__panel--PaddingBlockEnd: var(--pf-t--global--spacer--sm);
348
+ --pf-v6-c-drawer__head--PaddingInlineStart: var(--pf-t--global--spacer--md);
349
+ --pf-v6-c-drawer__head--PaddingInlineEnd: var(--pf-t--global--spacer--md);
350
+ --pf-v6-c-drawer__panel--RowGap: var(--pf-t--global--spacer--md);
338
351
 
339
352
  .pf-v6-c-drawer__body {
340
353
  --pf-v6-c-drawer__panel__body--PaddingInlineStart: var(--pf-t--global--spacer--md);
341
354
  --pf-v6-c-drawer__panel__body--PaddingInlineEnd: var(--pf-t--global--spacer--md);
342
355
  }
356
+
357
+ .pf-v6-c-drawer__head {
358
+ --pf-v6-c-drawer__head--PaddingInlineStart: var(--pf-t--global--spacer--lg);
359
+ --pf-v6-c-drawer__head--PaddingInlineEnd: var(--pf-t--global--spacer--lg);
360
+ }
361
+
362
+ .pf-v6-c-drawer__close {
363
+ .pf-v6-c-button {
364
+ width: 2rem;
365
+ height: 2rem;
366
+ --pf-v6-c-button--m-plain--PaddingInlineEnd: var(--pf-t--global--spacer--xs);
367
+ --pf-v6-c-button--m-plain--PaddingInlineStart: var(--pf-t--global--spacer--xs);
368
+ --pf-v6-c-button--PaddingBlockStart: var(--pf-t--global--spacer--xs);
369
+ --pf-v6-c-button--PaddingBlockEnd: var(--pf-t--global--spacer--xs);
370
+ }
371
+ }
343
372
  }
344
373
 
345
374
  .pf-chatbot__menu-item {
346
375
  font-size: var(--pf-t--global--font--size--body--md);
347
376
  }
348
-
349
- .pf-v6-c-drawer__head {
350
- --pf-v6-c-drawer__head--PaddingInlineStart: var(--pf-t--global--spacer--lg);
351
- --pf-v6-c-drawer__head--PaddingInlineEnd: var(--pf-t--global--spacer--lg);
352
- }
353
- .pf-v6-c-drawer__close {
354
- .pf-v6-c-button {
355
- width: 2rem;
356
- height: 2rem;
357
- --pf-v6-c-button--m-plain--PaddingInlineEnd: var(--pf-t--global--spacer--xs);
358
- --pf-v6-c-button--m-plain--PaddingInlineStart: var(--pf-t--global--spacer--xs);
359
- --pf-v6-c-button--PaddingBlockStart: var(--pf-t--global--spacer--xs);
360
- --pf-v6-c-button--PaddingBlockEnd: var(--pf-t--global--spacer--xs);
361
- }
362
- }
363
377
  }
@@ -161,17 +161,23 @@ describe('ChatbotConversationHistoryNav', () => {
161
161
  });
162
162
 
163
163
  it('should close the drawer when escape key is pressed', async () => {
164
- render(
165
- <ChatbotConversationHistoryNav
166
- onDrawerToggle={onDrawerToggle}
167
- isDrawerOpen={true}
168
- displayMode={ChatbotDisplayMode.fullscreen}
169
- setIsDrawerOpen={jest.fn()}
170
- reverseButtonOrder={false}
171
- handleTextInputChange={jest.fn()}
172
- conversations={initialConversations}
173
- />
174
- );
164
+ const HistoryNavigationTest = () => {
165
+ const [isDrawerOpen, setIsDrawerOpen] = useState(true);
166
+
167
+ return (
168
+ <ChatbotConversationHistoryNav
169
+ onDrawerToggle={onDrawerToggle}
170
+ isDrawerOpen={isDrawerOpen}
171
+ displayMode={ChatbotDisplayMode.fullscreen}
172
+ setIsDrawerOpen={setIsDrawerOpen}
173
+ reverseButtonOrder={false}
174
+ handleTextInputChange={jest.fn()}
175
+ conversations={initialConversations}
176
+ />
177
+ );
178
+ };
179
+
180
+ render(<HistoryNavigationTest />);
175
181
 
176
182
  fireEvent.keyDown(screen.getByPlaceholderText(/Search/i), {
177
183
  key: 'Escape',
@@ -180,8 +186,8 @@ describe('ChatbotConversationHistoryNav', () => {
180
186
  charCode: 27
181
187
  });
182
188
 
183
- waitFor(() => {
184
- expect(screen.queryByText('ChatBot documentation')).not.toBeInTheDocument();
189
+ await waitFor(() => {
190
+ expect(screen.getByRole('dialog', { hidden: true })).toHaveAttribute('hidden');
185
191
  });
186
192
  });
187
193
 
@@ -204,6 +210,19 @@ describe('ChatbotConversationHistoryNav', () => {
204
210
  );
205
211
  });
206
212
 
213
+ it('should keep an opaque panel background in glass theme', () => {
214
+ render(
215
+ <ChatbotConversationHistoryNav
216
+ onDrawerToggle={onDrawerToggle}
217
+ isDrawerOpen={true}
218
+ displayMode={ChatbotDisplayMode.fullscreen}
219
+ setIsDrawerOpen={jest.fn()}
220
+ conversations={initialConversations}
221
+ />
222
+ );
223
+ expect(screen.getByRole('dialog')).toHaveClass('pf-m-no-plain-on-glass');
224
+ });
225
+
207
226
  it('should accept drawerContentProps', () => {
208
227
  const { container } = render(
209
228
  <ChatbotConversationHistoryNav
@@ -683,6 +683,7 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
683
683
  aria-live="polite"
684
684
  focusTrap={{ enabled: true }}
685
685
  defaultSize="384px"
686
+ isNoPlainOnGlass
686
687
  {...drawerPanelContentProps}
687
688
  >
688
689
  {drawer}
@@ -1,6 +1,9 @@
1
1
  import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
2
2
  import ChatbotFootnote from './ChatbotFootnote';
3
3
 
4
+ const POPOVER_CLOSE_ERROR =
5
+ 'ChatbotFootnote: You must provide either the popover.cta or popover.showClose props in order to render a button that can close the popover.';
6
+
4
7
  describe('ChatbotFooternote', () => {
5
8
  const onClick = jest.fn();
6
9
  const popoverProps = {
@@ -20,11 +23,58 @@ describe('ChatbotFooternote', () => {
20
23
  }
21
24
  };
22
25
 
26
+ let consoleErrorSpy: jest.SpyInstance;
27
+
28
+ beforeEach(() => {
29
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn());
30
+ });
31
+
32
+ afterEach(() => {
33
+ consoleErrorSpy.mockRestore();
34
+ });
35
+
23
36
  it('should render ChatbotFooternote', () => {
24
37
  render(<ChatbotFootnote label="Chatbot footer" />);
25
38
  expect(screen.getByText('Chatbot footer')).toBeTruthy();
26
39
  });
27
40
 
41
+ it('should not log a console error when no popover is provided', () => {
42
+ render(<ChatbotFootnote label="Chatbot footer" />);
43
+ expect(consoleErrorSpy).not.toHaveBeenCalledWith(POPOVER_CLOSE_ERROR);
44
+ });
45
+
46
+ it('should not log a console error when popover has a cta', () => {
47
+ render(<ChatbotFootnote label="Chatbot footer" popover={popoverProps} />);
48
+ expect(consoleErrorSpy).not.toHaveBeenCalledWith(POPOVER_CLOSE_ERROR);
49
+ });
50
+
51
+ it('should not log a console error when popover has showClose', () => {
52
+ render(
53
+ <ChatbotFootnote
54
+ label="Chatbot footer"
55
+ popover={{
56
+ title: 'Verify accuracy',
57
+ description: 'description',
58
+ showClose: true
59
+ }}
60
+ />
61
+ );
62
+ expect(consoleErrorSpy).not.toHaveBeenCalledWith(POPOVER_CLOSE_ERROR);
63
+ });
64
+
65
+ it('should log a console error when popover is provided without cta or showClose', () => {
66
+ render(
67
+ <ChatbotFootnote
68
+ label="Chatbot footer"
69
+ popover={{
70
+ title: 'Verify accuracy',
71
+ description: 'description'
72
+ }}
73
+ />
74
+ );
75
+ expect(consoleErrorSpy).toHaveBeenCalledWith(POPOVER_CLOSE_ERROR);
76
+ });
77
+
28
78
  it('should render ChatbotFooternote with popover', async () => {
29
79
  render(<ChatbotFootnote label="Chatbot footer" popover={popoverProps} />);
30
80
 
@@ -63,7 +63,7 @@ export const ChatbotFootnote: FunctionComponent<ChatbotFootnoteProps> = ({
63
63
  className,
64
64
  ...props
65
65
  }: ChatbotFootnoteProps) => {
66
- if (!popover?.cta && !popover?.showClose) {
66
+ if (popover && !popover.cta && !popover.showClose) {
67
67
  // eslint-disable-next-line no-console
68
68
  console.error(
69
69
  'ChatbotFootnote: You must provide either the popover.cta or popover.showClose props in order to render a button that can close the popover.'
@@ -27,13 +27,8 @@
27
27
  }
28
28
  }
29
29
 
30
- :root:where(.pf-v6-theme-glass) {
31
- .pf-chatbot__chatbot-modal {
32
- --pf-v6-c-modal-box--BackgroundColor: var(
33
- --pf-t--global--background--color--glass--primary--default,
34
- var(--pf-t--global--background--color--secondary--default)
35
- );
36
- }
30
+ :root:where(.pf-v6-theme-glass) .pf-chatbot__code-modal {
31
+ --pf-v6-c-modal-box--BackgroundColor: var(--pf-t--global--background--color--floating--secondary--default);
37
32
  }
38
33
 
39
34
  // ============================================================================
@@ -32,6 +32,7 @@ export const ChatbotModal: FunctionComponent<ChatbotModalProps> = ({
32
32
  aria-describedby="chatbot-modal"
33
33
  className={`pf-chatbot__chatbot-modal pf-chatbot__chatbot-modal--${displayMode} ${isCompact ? 'pf-m-compact' : ''} ${className}`}
34
34
  backdropClassName="pf-chatbot__chatbot-modal-backdrop"
35
+ hasAnimations={false}
35
36
  {...props}
36
37
  >
37
38
  {children}
@@ -5,6 +5,7 @@
5
5
  position: fixed;
6
6
  inset-block-end: var(--pf-t--global--spacer--md);
7
7
  inset-inline-end: var(--pf-t--global--spacer--md);
8
+ --pf-v6-c-button--BorderRadius: 0;
8
9
  --pf-v6-c-button--m-plain--BackgroundColor: var(--pf-t--global--background--color--floating--default);
9
10
  --pf-v6-c-button--m-plain--hover--BackgroundColor: var(--pf-t--global--background--color--floating--hover);
10
11
  --pf-v6-c-button--m-plain--m-clicked--BackgroundColor: var(--pf-t--global--background--color--floating--clicked);
@@ -48,8 +49,8 @@
48
49
  }
49
50
  }
50
51
 
51
- .pf-chatbot__button--round {
52
- border-radius: var(--pf-t--global--border--radius--pill);
52
+ .pf-chatbot__button.pf-chatbot__button--round {
53
+ --pf-v6-c-button--BorderRadius: var(--pf-t--global--border--radius--pill);
53
54
  width: 3rem;
54
55
  height: 3rem;
55
56
  }
@@ -38,6 +38,10 @@ describe('ChatbotToggle', () => {
38
38
  expect(screen.getByRole('button')).toHaveClass('pf-chatbot__button');
39
39
  expect(screen.getByRole('button')).toHaveClass('pf-chatbot__button--round');
40
40
  });
41
+ it('should handle isRound correctly when false', () => {
42
+ render(<ChatbotToggle tooltipLabel="Chatbot" isRound={false} />);
43
+ expect(screen.getByRole('button')).not.toHaveClass('pf-chatbot__button--round');
44
+ });
41
45
  it('should handle className correctly', () => {
42
46
  render(<ChatbotToggle tooltipLabel="Chatbot" className="test" />);
43
47
  expect(screen.getByRole('button')).toHaveClass('pf-chatbot__button');
@@ -30,6 +30,15 @@
30
30
  flex: 1;
31
31
  overflow: visible;
32
32
  height: 100%;
33
+ min-width: 0;
34
+ }
35
+
36
+ .pf-chatbot__prompt-suggestion-body {
37
+ overflow-wrap: anywhere;
38
+ }
39
+
40
+ .pf-chatbot__prompt-suggestion-title {
41
+ --pf-v6-c-card__title-text--OverflowWrap: anywhere;
33
42
  }
34
43
  }
35
44
 
@@ -64,9 +64,11 @@ export const ChatbotWelcomePrompt: FunctionComponent<ChatbotWelcomePromptProps>
64
64
  selectableActionAriaLabelledby: `welcome-prompt-title-${index}`
65
65
  }}
66
66
  >
67
- <CardTitle id={`welcome-prompt-title-${index}`}>{prompt.title}</CardTitle>
67
+ <CardTitle className="pf-chatbot__prompt-suggestion-title" id={`welcome-prompt-title-${index}`}>
68
+ {prompt.title}
69
+ </CardTitle>
68
70
  </CardHeader>
69
- {prompt.message && <CardBody>{prompt.message}</CardBody>}
71
+ {prompt.message && <CardBody className="pf-chatbot__prompt-suggestion-body">{prompt.message}</CardBody>}
70
72
  </Card>
71
73
  ))}
72
74
  </div>
@@ -43,15 +43,11 @@ exports[`FileDetails should render file details 1`] = `
43
43
  <div
44
44
  class="pf-v6-l-flex pf-m-gap-xs"
45
45
  >
46
- <div
47
- class=""
48
- >
46
+ <div>
49
47
  <div
50
48
  class="pf-v6-l-flex pf-m-column pf-m-gap-none"
51
49
  >
52
- <div
53
- class=""
54
- >
50
+ <div>
55
51
  <span
56
52
  class="pf-chatbot__code-fileName"
57
53
  >
@@ -55,15 +55,11 @@ exports[`FileDetailsLabel should render file details label 1`] = `
55
55
  <div
56
56
  class="pf-v6-l-flex pf-m-gap-xs"
57
57
  >
58
- <div
59
- class=""
60
- >
58
+ <div>
61
59
  <div
62
60
  class="pf-v6-l-flex pf-m-column pf-m-gap-none"
63
61
  >
64
- <div
65
- class=""
66
- >
62
+ <div>
67
63
  <span
68
64
  class="pf-chatbot__code-fileName"
69
65
  >
@@ -55,6 +55,7 @@
55
55
 
56
56
  // Author name
57
57
  .pf-chatbot__message-name {
58
+ display: flex;
58
59
  font-family: var(
59
60
  --pf-v6-c-content--heading--FontFamily,
60
61
  redhatdisplayvf,
@@ -65,6 +66,14 @@
65
66
  );
66
67
  font-weight: 600;
67
68
  font-size: var(--pf-t--global--font--size--sm);
69
+
70
+ // Truncate measures this container and treats textWidth >= parentWidth as
71
+ // truncated. This extra space keeps full names stay untruncated and out of
72
+ // the tab flow.
73
+ &::after {
74
+ content: '';
75
+ flex: 0 0 1px;
76
+ }
68
77
  }
69
78
 
70
79
  // Badge
@@ -7,30 +7,13 @@
7
7
  width: 3rem;
8
8
  height: 3rem;
9
9
 
10
- .pf-v6-c-button__icon {
11
- color: var(--pf-t--global--icon--color--subtle);
12
- }
13
-
14
- // Interactive states
15
- &:hover {
16
- .pf-v6-c-button__icon {
17
- color: var(--pf-t--global--icon--color--regular);
18
- }
19
- }
20
-
21
- &:active,
22
- &:focus {
10
+ &.pf-m-clicked,
11
+ &.pf-m-clicked:hover,
12
+ &.pf-m-clicked:focus {
23
13
  background-color: var(--pf-t--global--color--brand--clicked);
24
14
 
25
15
  .pf-v6-c-button__icon {
26
- color: var(--pf-t--global--icon--color--inverse);
27
- }
28
-
29
- &:hover,
30
- &:focus {
31
- .pf-v6-c-button__icon {
32
- color: var(--pf-t--global--icon--color--inverse);
33
- }
16
+ color: var(--pf-t--global--icon--color--on-brand--default);
34
17
  }
35
18
  }
36
19
  }
@@ -46,14 +46,14 @@
46
46
 
47
47
  &:hover {
48
48
  &::after {
49
- border-color: var(--pf-t--global--border--color--control--hover);
49
+ border-color: var(--pf-t--global--border--color--hover);
50
50
  border-width: var(--pf-t--global--border--width--control--hover);
51
51
  }
52
52
  }
53
53
 
54
54
  &:focus-within {
55
55
  &::after {
56
- border-color: var(--pf-t--global--border--color--control--clicked);
56
+ border-color: var(--pf-t--global--border--color--clicked);
57
57
  border-width: var(--pf-t--global--border--width--control--clicked);
58
58
  }
59
59
  }
@@ -191,6 +191,9 @@ describe('Message bar', () => {
191
191
  }}
192
192
  />
193
193
  );
194
+ const attachButton = screen.getByRole('button', { name: 'Attach' });
195
+ expect(attachButton).toHaveClass('pf-m-clicked');
196
+ expect(attachButton).toHaveAttribute('aria-expanded', 'true');
194
197
  expect(screen.getByRole('textbox', { name: /Filter menu items/i })).toBeTruthy();
195
198
  expect(screen.getByRole('menuitem', { name: /auth-operator/i })).toBeTruthy();
196
199
  expect(screen.getByRole('menuitem', { name: /Alerts/i })).toBeTruthy();
@@ -224,6 +227,23 @@ describe('Message bar', () => {
224
227
  await userEvent.click(attachButton);
225
228
  expect(attachToggleClickSpy).toHaveBeenCalledTimes(1);
226
229
  });
230
+ it('can toggle attach menu without an optional toggle callback', async () => {
231
+ const setIsAttachMenuOpen = jest.fn();
232
+ render(
233
+ <MessageBar
234
+ onSendMessage={jest.fn}
235
+ attachMenuProps={{
236
+ isAttachMenuOpen: false,
237
+ setIsAttachMenuOpen,
238
+ attachMenuItems: ATTACH_MENU_ITEMS
239
+ }}
240
+ />
241
+ );
242
+
243
+ await userEvent.click(screen.getByRole('button', { name: 'Attach' }));
244
+
245
+ expect(setIsAttachMenuOpen).toHaveBeenCalledWith(true);
246
+ });
227
247
  it('can pass searchInputProps to search input in AttachMenu', () => {
228
248
  render(
229
249
  <MessageBar
@@ -28,7 +28,7 @@ export interface MessageBarWithAttachMenuProps {
28
28
  /** Items in menu */
29
29
  attachMenuItems: React.ReactNode;
30
30
  /** A callback for when the attachment menu toggle is clicked */
31
- onAttachMenuToggleClick: () => void;
31
+ onAttachMenuToggleClick?: () => void;
32
32
  /** A callback for when the input value in the menu changes. */
33
33
  onAttachMenuInputChange?: (value: string) => void;
34
34
  /** Function callback called when user selects item in menu. */
@@ -368,7 +368,7 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
368
368
 
369
369
  const handleAttachMenuToggle = () => {
370
370
  attachMenuProps?.setIsAttachMenuOpen && attachMenuProps?.setIsAttachMenuOpen(!attachMenuProps?.isAttachMenuOpen);
371
- attachMenuProps?.onAttachMenuToggleClick();
371
+ attachMenuProps?.onAttachMenuToggleClick?.();
372
372
  };
373
373
 
374
374
  const handleSpeechRecognition = (message) => {
@@ -419,6 +419,8 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
419
419
  validator={validator}
420
420
  dropzoneProps={dropzoneProps}
421
421
  {...buttonProps?.attach}
422
+ isClicked={attachMenuProps.isAttachMenuOpen}
423
+ aria-expanded={attachMenuProps.isAttachMenuOpen}
422
424
  />
423
425
  );
424
426
  }
@@ -523,7 +525,9 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
523
525
  {...(attachMenuProps && { handleTextInputChange: attachMenuProps.onAttachMenuInputChange })}
524
526
  popperProps={{ direction: 'up', distance: 8 }}
525
527
  searchInputPlaceholder={attachMenuProps?.attachMenuInputPlaceholder}
526
- {...attachMenuProps}
528
+ menuSearchProps={attachMenuProps?.menuSearchProps}
529
+ menuSearchInputProps={attachMenuProps?.menuSearchInputProps}
530
+ searchInputProps={attachMenuProps?.searchInputProps}
527
531
  />
528
532
  );
529
533
  }