@patternfly/chatbot 6.3.1 → 6.4.0-prerelease.10
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.
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +2 -0
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +6 -6
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +27 -4
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +8 -14
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +53 -2
- package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.js +1 -1
- package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.test.js +1 -1
- package/dist/cjs/ChatbotHeader/ChatbotHeaderNewChatButton.d.ts +18 -0
- package/dist/cjs/ChatbotHeader/ChatbotHeaderNewChatButton.js +25 -0
- package/dist/cjs/ChatbotHeader/ChatbotHeaderNewChatButton.test.d.ts +1 -0
- package/dist/cjs/ChatbotHeader/ChatbotHeaderNewChatButton.test.js +22 -0
- package/dist/cjs/ChatbotHeader/index.d.ts +1 -0
- package/dist/cjs/ChatbotHeader/index.js +1 -0
- package/dist/cjs/FileDropZone/FileDropZone.d.ts +1 -2
- package/dist/cjs/Message/Message.d.ts +9 -2
- package/dist/cjs/Message/Message.js +40 -34
- package/dist/cjs/Message/Message.test.js +37 -0
- package/dist/cjs/Message/MessageInput.d.ts +3 -1
- package/dist/cjs/Message/MessageInput.js +2 -2
- package/dist/cjs/MessageBar/AttachButton.d.ts +2 -2
- package/dist/cjs/MessageBar/MessageBar.d.ts +2 -2
- package/dist/cjs/MessageBar/MessageBar.js +19 -4
- package/dist/cjs/MessageBox/JumpButton.d.ts +5 -0
- package/dist/cjs/MessageBox/JumpButton.js +1 -1
- package/dist/cjs/MessageBox/JumpButton.test.js +4 -4
- package/dist/cjs/MessageBox/MessageBox.d.ts +9 -0
- package/dist/cjs/MessageBox/MessageBox.js +2 -2
- package/dist/cjs/MessageBox/MessageBox.test.js +2 -2
- package/dist/cjs/MessageDivider/MessageDivider.d.ts +9 -0
- package/dist/cjs/MessageDivider/MessageDivider.js +23 -0
- package/dist/cjs/MessageDivider/MessageDivider.test.d.ts +1 -0
- package/dist/cjs/MessageDivider/MessageDivider.test.js +29 -0
- package/dist/cjs/MessageDivider/index.d.ts +2 -0
- package/dist/cjs/MessageDivider/index.js +23 -0
- package/dist/cjs/ResponseActions/ResponseActions.d.ts +1 -0
- package/dist/cjs/ResponseActions/ResponseActions.js +4 -4
- package/dist/cjs/ResponseActions/ResponseActions.test.js +6 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +4 -1
- package/dist/css/main.css +103 -81
- package/dist/css/main.css.map +1 -1
- package/dist/dynamic/MessageDivider/package.json +1 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +2 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +6 -6
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +27 -4
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +10 -16
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +54 -3
- package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +1 -1
- package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.test.js +1 -1
- package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.d.ts +18 -0
- package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.js +22 -0
- package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.test.d.ts +1 -0
- package/dist/esm/ChatbotHeader/ChatbotHeaderNewChatButton.test.js +20 -0
- package/dist/esm/ChatbotHeader/index.d.ts +1 -0
- package/dist/esm/ChatbotHeader/index.js +1 -0
- package/dist/esm/FileDropZone/FileDropZone.d.ts +1 -2
- package/dist/esm/Message/Message.d.ts +9 -2
- package/dist/esm/Message/Message.js +40 -34
- package/dist/esm/Message/Message.test.js +37 -0
- package/dist/esm/Message/MessageInput.d.ts +3 -1
- package/dist/esm/Message/MessageInput.js +2 -2
- package/dist/esm/MessageBar/AttachButton.d.ts +2 -2
- package/dist/esm/MessageBar/MessageBar.d.ts +2 -2
- package/dist/esm/MessageBar/MessageBar.js +19 -4
- package/dist/esm/MessageBox/JumpButton.d.ts +5 -0
- package/dist/esm/MessageBox/JumpButton.js +1 -1
- package/dist/esm/MessageBox/JumpButton.test.js +4 -4
- package/dist/esm/MessageBox/MessageBox.d.ts +9 -0
- package/dist/esm/MessageBox/MessageBox.js +2 -2
- package/dist/esm/MessageBox/MessageBox.test.js +2 -2
- package/dist/esm/MessageDivider/MessageDivider.d.ts +9 -0
- package/dist/esm/MessageDivider/MessageDivider.js +21 -0
- package/dist/esm/MessageDivider/MessageDivider.test.d.ts +1 -0
- package/dist/esm/MessageDivider/MessageDivider.test.js +24 -0
- package/dist/esm/MessageDivider/index.d.ts +2 -0
- package/dist/esm/MessageDivider/index.js +2 -0
- package/dist/esm/ResponseActions/ResponseActions.d.ts +1 -0
- package/dist/esm/ResponseActions/ResponseActions.js +5 -5
- package/dist/esm/ResponseActions/ResponseActions.test.js +6 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -4
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDividers.tsx +24 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +15 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +39 -7
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotConversationEditing.tsx +202 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderBasic.tsx +17 -3
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawer.tsx +45 -5
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithPin.tsx +206 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +30 -4
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +33 -1
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotDisplayMode.tsx +486 -0
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotTranscripts.tsx +565 -0
- package/src/Chatbot/Chatbot.scss +1 -1
- package/src/ChatbotContent/ChatbotContent.scss +1 -1
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx +6 -6
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +5 -2
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +70 -32
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +176 -3
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +110 -60
- package/src/ChatbotFooter/ChatbotFooter.scss +1 -1
- package/src/ChatbotHeader/ChatbotHeader.scss +3 -3
- package/src/ChatbotHeader/ChatbotHeaderMenu.test.tsx +1 -1
- package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +2 -2
- package/src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx +25 -0
- package/src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx +64 -0
- package/src/ChatbotHeader/index.ts +1 -0
- package/src/ChatbotModal/ChatbotModal.scss +1 -1
- package/src/ChatbotToggle/ChatbotToggle.scss +2 -2
- package/src/FileDetails/__snapshots__/FileDetails.test.tsx.snap +6 -9
- package/src/FileDetailsLabel/__snapshots__/FileDetailsLabel.test.tsx.snap +6 -9
- package/src/FileDropZone/FileDropZone.tsx +2 -2
- package/src/Message/Message.scss +9 -7
- package/src/Message/Message.test.tsx +54 -0
- package/src/Message/Message.tsx +70 -50
- package/src/Message/MessageInput.tsx +5 -1
- package/src/MessageBar/AttachButton.tsx +2 -2
- package/src/MessageBar/MessageBar.tsx +25 -5
- package/src/MessageBar/SendButton.scss +3 -3
- package/src/MessageBox/JumpButton.scss +1 -1
- package/src/MessageBox/JumpButton.test.tsx +4 -4
- package/src/MessageBox/JumpButton.tsx +20 -4
- package/src/MessageBox/MessageBox.test.tsx +2 -2
- package/src/MessageBox/MessageBox.tsx +23 -2
- package/src/MessageDivider/MessageDivider.scss +45 -0
- package/src/MessageDivider/MessageDivider.test.tsx +24 -0
- package/src/MessageDivider/MessageDivider.tsx +35 -0
- package/src/MessageDivider/index.ts +3 -0
- package/src/ResponseActions/ResponseActions.test.tsx +6 -1
- package/src/ResponseActions/ResponseActions.tsx +24 -3
- package/src/index.ts +3 -0
- package/src/main.scss +1 -52
|
@@ -2,63 +2,101 @@
|
|
|
2
2
|
// Chatbot Header - Menu
|
|
3
3
|
// ============================================================================
|
|
4
4
|
.pf-chatbot__history {
|
|
5
|
+
// hide from view but not assistive technologies
|
|
6
|
+
// https://css-tricks.com/inclusively-hidden/
|
|
7
|
+
.pf-chatbot__filter-announcement {
|
|
8
|
+
clip: rect(0 0 0 0);
|
|
9
|
+
clip-path: inset(50%);
|
|
10
|
+
height: 1px;
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
position: absolute;
|
|
13
|
+
white-space: nowrap;
|
|
14
|
+
width: 1px;
|
|
15
|
+
}
|
|
16
|
+
|
|
5
17
|
.pf-chatbot__drawer-backdrop {
|
|
6
18
|
position: absolute;
|
|
7
19
|
border-radius: var(--pf-t--global--border--radius--medium);
|
|
8
20
|
}
|
|
9
|
-
|
|
21
|
+
|
|
22
|
+
// Drawer title
|
|
10
23
|
// ----------------------------------------------------------------------------
|
|
11
|
-
.pf-
|
|
24
|
+
.pf-chatbot__heading-container {
|
|
12
25
|
padding-inline-start: var(--pf-t--global--spacer--lg);
|
|
13
26
|
padding-inline-end: var(--pf-t--global--spacer--lg);
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
row-gap: var(--pf-t--global--spacer--sm);
|
|
30
|
+
}
|
|
31
|
+
.pf-chatbot__title {
|
|
32
|
+
font-size: var(--pf-v6-c-title--m-h3--FontSize);
|
|
33
|
+
font-weight: var(--pf-v6-c-title--m-h3--FontWeight);
|
|
34
|
+
line-height: var(--pf-v6-c-title--m-h3--LineHeight);
|
|
35
|
+
}
|
|
36
|
+
.pf-chatbot__title-container {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: row;
|
|
39
|
+
align-items: baseline;
|
|
40
|
+
justify-content: flex-start;
|
|
41
|
+
gap: var(--pf-t--global--spacer--gap--text-to-element--default);
|
|
14
42
|
}
|
|
15
|
-
|
|
16
43
|
// Drawer menu
|
|
17
44
|
// ----------------------------------------------------------------------------
|
|
18
|
-
.pf-
|
|
19
|
-
--pf-v6-c-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
.pf-v6-c-menu__item-main {
|
|
25
|
-
--pf-v6-c-menu__item-main--ColumnGap: var(--pf-t--global--spacer--md);
|
|
45
|
+
.pf-chatbot__conversation-list {
|
|
46
|
+
--pf-v6-c-list--Gap: var(--pf-t--global--spacer--xs);
|
|
47
|
+
|
|
48
|
+
margin-block-start: var(--pf-t--global--spacer--md);
|
|
49
|
+
margin-block-end: var(--pf-t--global--spacer--md);
|
|
26
50
|
}
|
|
27
|
-
|
|
51
|
+
|
|
52
|
+
.pf-chatbot__conversation-list-header {
|
|
28
53
|
color: var(--pf-t--global--text--color--subtle);
|
|
29
54
|
font-weight: var(--pf-t--global--font--weight--body--bold);
|
|
30
55
|
font-size: var(--pf-t--global--icon--size--font--sm);
|
|
31
|
-
|
|
32
|
-
|
|
56
|
+
padding-inline-start: var(--pf-t--global--spacer--sm);
|
|
57
|
+
padding-inline-end: var(--pf-t--global--spacer--sm);
|
|
33
58
|
position: -webkit-sticky;
|
|
34
59
|
position: sticky;
|
|
35
60
|
top: 0;
|
|
36
61
|
background-color: var(--pf-t--global--background--color--floating--default);
|
|
37
62
|
z-index: var(--pf-t--global--z-index--md);
|
|
38
63
|
}
|
|
39
|
-
.pf-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
.pf-chatbot__conversation-list-item {
|
|
65
|
+
& > span {
|
|
66
|
+
display: flex;
|
|
67
|
+
column-gap: var(--pf-t--global--spacer--sm);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
& .pf-chatbot__conversation-history-item {
|
|
71
|
+
--pf-v6-c-button--JustifyContent: flex-start;
|
|
72
|
+
--pf-v6-c-button--FontSize: var(--pf-t--global--font--size--body--lg);
|
|
73
|
+
--pf-v6-c-button--m-link--Color: var(--pf-t--global--text--color--regular);
|
|
74
|
+
--pf-v6-c-button--m-link__icon--Color: var(--pf-t--global--icon--color--regular);
|
|
75
|
+
--pf-v6-c-button--m-link--hover--Color: var(--pf-t--global--text--color--regular--hover);
|
|
76
|
+
--pf-v6-c-button--m-link--hover__icon--Color: var(--pf-t--global--icon--color--regular);
|
|
77
|
+
--pf-v6-c-button--m-link--m-clicked--Color: var(--pf-t--global--text--color--regular--clicked);
|
|
78
|
+
--pf-v6-c-button--m-link--m-clicked__icon--Color: var(--pf-t--global--icon--color--regular);
|
|
79
|
+
|
|
80
|
+
column-gap: var(--pf-t--global--spacer--md);
|
|
81
|
+
flex-basis: 100%;
|
|
82
|
+
|
|
83
|
+
& .pf-v6-c-button__text {
|
|
84
|
+
overflow: hidden;
|
|
85
|
+
text-overflow: ellipsis;
|
|
86
|
+
white-space: nowrap;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
52
89
|
}
|
|
90
|
+
|
|
53
91
|
.pf-chatbot__history-actions {
|
|
54
92
|
transform: rotate(90deg);
|
|
55
93
|
}
|
|
56
94
|
|
|
57
|
-
.pf-
|
|
95
|
+
.pf-chatbot__conversation-list-item--active {
|
|
58
96
|
background-color: var(--pf-t--global--background--color--action--plain--clicked);
|
|
59
97
|
}
|
|
60
98
|
|
|
61
|
-
button.pf-
|
|
99
|
+
button.pf-chatbot__conversation-list-item--active {
|
|
62
100
|
background-color: initial;
|
|
63
101
|
}
|
|
64
102
|
}
|
|
@@ -75,7 +113,7 @@
|
|
|
75
113
|
--pf-v6-c-drawer__panel--BackgroundColor: var(--pf-t--global--background--color--floating--default);
|
|
76
114
|
--pf-v6-c-drawer__panel--PaddingBlockStart: var(--pf-t--global--spacer--lg);
|
|
77
115
|
--pf-v6-c-drawer__panel--PaddingBlockEnd: var(--pf-t--global--spacer--lg);
|
|
78
|
-
--pf-v6-c-drawer__panel--RowGap: var(--pf-t--global--spacer--
|
|
116
|
+
--pf-v6-c-drawer__panel--RowGap: var(--pf-t--global--spacer--gap--group-to-group--vertical--default);
|
|
79
117
|
overflow-x: hidden;
|
|
80
118
|
overflow-y: hidden;
|
|
81
119
|
}
|
|
@@ -221,8 +259,8 @@
|
|
|
221
259
|
}
|
|
222
260
|
}
|
|
223
261
|
|
|
224
|
-
.pf-
|
|
225
|
-
|
|
262
|
+
.pf-chatbot__conversation-history-item {
|
|
263
|
+
--pf-v6-c-button--FontSize: var(--pf-t--global--font--size--body--md);
|
|
226
264
|
}
|
|
227
265
|
|
|
228
266
|
.pf-v6-c-drawer__head {
|
|
@@ -4,7 +4,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
|
4
4
|
import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
|
|
5
5
|
import ChatbotConversationHistoryNav, { Conversation } from './ChatbotConversationHistoryNav';
|
|
6
6
|
import { EmptyStateStatus, Spinner } from '@patternfly/react-core';
|
|
7
|
-
import { OutlinedCommentsIcon, SearchIcon } from '@patternfly/react-icons';
|
|
7
|
+
import { BellIcon, OutlinedCommentsIcon, SearchIcon } from '@patternfly/react-icons';
|
|
8
8
|
import { ComponentType } from 'react';
|
|
9
9
|
|
|
10
10
|
const ERROR = {
|
|
@@ -104,6 +104,23 @@ describe('ChatbotConversationHistoryNav', () => {
|
|
|
104
104
|
expect(screen.getByTestId('chatbot-nav-drawer-actions')).toHaveClass('pf-v6-c-drawer__actions--reversed');
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
+
it('should disable new chat button', () => {
|
|
108
|
+
render(
|
|
109
|
+
<ChatbotConversationHistoryNav
|
|
110
|
+
onDrawerToggle={onDrawerToggle}
|
|
111
|
+
isDrawerOpen={true}
|
|
112
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
113
|
+
setIsDrawerOpen={jest.fn()}
|
|
114
|
+
reverseButtonOrder
|
|
115
|
+
conversations={initialConversations}
|
|
116
|
+
newChatButtonProps={{ isDisabled: true }}
|
|
117
|
+
onNewChat={jest.fn()}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
expect(screen.getByRole('button', { name: 'New chat' })).toBeDisabled();
|
|
122
|
+
});
|
|
123
|
+
|
|
107
124
|
it('should not apply the reversed class when reverseButtonOrder is false', () => {
|
|
108
125
|
render(
|
|
109
126
|
<ChatbotConversationHistoryNav
|
|
@@ -331,7 +348,7 @@ describe('ChatbotConversationHistoryNav', () => {
|
|
|
331
348
|
).toBeTruthy();
|
|
332
349
|
expect(screen.getByRole('button', { name: /Close drawer panel/i })).toBeTruthy();
|
|
333
350
|
expect(screen.getByRole('button', { name: /Loading... Reload/i })).toBeTruthy();
|
|
334
|
-
expect(screen.getByRole('textbox', { name: /
|
|
351
|
+
expect(screen.getByRole('textbox', { name: /Search previous conversations/i })).toBeTruthy();
|
|
335
352
|
expect(screen.getByRole('heading', { name: /Could not load chat history/i })).toBeTruthy();
|
|
336
353
|
});
|
|
337
354
|
|
|
@@ -355,7 +372,7 @@ describe('ChatbotConversationHistoryNav', () => {
|
|
|
355
372
|
).toBeTruthy();
|
|
356
373
|
expect(screen.getByRole('button', { name: /Close drawer panel/i })).toBeTruthy();
|
|
357
374
|
expect(screen.queryByRole('button', { name: /Loading... Reload/i })).toBeFalsy();
|
|
358
|
-
expect(screen.getByRole('textbox', { name: /
|
|
375
|
+
expect(screen.getByRole('textbox', { name: /Search previous conversations/i })).toBeTruthy();
|
|
359
376
|
expect(screen.getByRole('heading', { name: /Could not load chat history/i })).toBeTruthy();
|
|
360
377
|
});
|
|
361
378
|
|
|
@@ -433,4 +450,160 @@ describe('ChatbotConversationHistoryNav', () => {
|
|
|
433
450
|
);
|
|
434
451
|
expect(screen.getByTestId('drawer')).toHaveClass('pf-m-compact');
|
|
435
452
|
});
|
|
453
|
+
|
|
454
|
+
it('should display the default title', () => {
|
|
455
|
+
render(
|
|
456
|
+
<ChatbotConversationHistoryNav
|
|
457
|
+
onDrawerToggle={onDrawerToggle}
|
|
458
|
+
isDrawerOpen={true}
|
|
459
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
460
|
+
setIsDrawerOpen={jest.fn()}
|
|
461
|
+
conversations={initialConversations}
|
|
462
|
+
/>
|
|
463
|
+
);
|
|
464
|
+
expect(screen.getByText('Chat history')).toBeInTheDocument();
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('should display the custom title', () => {
|
|
468
|
+
render(
|
|
469
|
+
<ChatbotConversationHistoryNav
|
|
470
|
+
title="PatternFly history"
|
|
471
|
+
onDrawerToggle={onDrawerToggle}
|
|
472
|
+
isDrawerOpen={true}
|
|
473
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
474
|
+
setIsDrawerOpen={jest.fn()}
|
|
475
|
+
conversations={initialConversations}
|
|
476
|
+
/>
|
|
477
|
+
);
|
|
478
|
+
expect(screen.getByText('PatternFly history')).toBeInTheDocument();
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
it('should display the clock icon', () => {
|
|
482
|
+
const { container } = render(
|
|
483
|
+
<ChatbotConversationHistoryNav
|
|
484
|
+
onDrawerToggle={onDrawerToggle}
|
|
485
|
+
isDrawerOpen={true}
|
|
486
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
487
|
+
setIsDrawerOpen={jest.fn()}
|
|
488
|
+
conversations={initialConversations}
|
|
489
|
+
/>
|
|
490
|
+
);
|
|
491
|
+
const iconElement = container.querySelector('.pf-chatbot__title-icon');
|
|
492
|
+
expect(iconElement).toBeInTheDocument();
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it('Passes listTitleProps to Title', () => {
|
|
496
|
+
render(
|
|
497
|
+
<ChatbotConversationHistoryNav
|
|
498
|
+
onDrawerToggle={onDrawerToggle}
|
|
499
|
+
isDrawerOpen={true}
|
|
500
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
501
|
+
setIsDrawerOpen={jest.fn()}
|
|
502
|
+
conversations={{ Today: initialConversations }}
|
|
503
|
+
listTitleProps={{ className: 'test' }}
|
|
504
|
+
/>
|
|
505
|
+
);
|
|
506
|
+
expect(screen.getByRole('heading', { name: /Today/i })).toHaveClass('test');
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
it('Overrides list title heading level when titleProps.headingLevel is passed', () => {
|
|
510
|
+
render(
|
|
511
|
+
<ChatbotConversationHistoryNav
|
|
512
|
+
onDrawerToggle={onDrawerToggle}
|
|
513
|
+
isDrawerOpen={true}
|
|
514
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
515
|
+
setIsDrawerOpen={jest.fn()}
|
|
516
|
+
conversations={{ Today: initialConversations }}
|
|
517
|
+
listTitleProps={{ headingLevel: 'h2' }}
|
|
518
|
+
/>
|
|
519
|
+
);
|
|
520
|
+
expect(screen.queryByRole('heading', { name: /Today/i, level: 4 })).not.toBeInTheDocument();
|
|
521
|
+
expect(screen.getByRole('heading', { name: /Today/i, level: 2 })).toBeInTheDocument();
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
it('Passes listProps to List when conversations is an array', () => {
|
|
525
|
+
render(
|
|
526
|
+
<ChatbotConversationHistoryNav
|
|
527
|
+
onDrawerToggle={onDrawerToggle}
|
|
528
|
+
isDrawerOpen={true}
|
|
529
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
530
|
+
setIsDrawerOpen={jest.fn()}
|
|
531
|
+
conversations={initialConversations}
|
|
532
|
+
listProps={{ className: 'test' }}
|
|
533
|
+
/>
|
|
534
|
+
);
|
|
535
|
+
expect(screen.getByRole('list')).toHaveClass('test');
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
it('Passes listProps to List when conversations is an object', () => {
|
|
539
|
+
render(
|
|
540
|
+
<ChatbotConversationHistoryNav
|
|
541
|
+
onDrawerToggle={onDrawerToggle}
|
|
542
|
+
isDrawerOpen={true}
|
|
543
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
544
|
+
setIsDrawerOpen={jest.fn()}
|
|
545
|
+
conversations={{ Today: initialConversations }}
|
|
546
|
+
listProps={{ Today: { className: 'test' } }}
|
|
547
|
+
/>
|
|
548
|
+
);
|
|
549
|
+
expect(screen.getByRole('list')).toHaveClass('test');
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
it('Passes listItemProps to ListItem', () => {
|
|
553
|
+
render(
|
|
554
|
+
<ChatbotConversationHistoryNav
|
|
555
|
+
onDrawerToggle={onDrawerToggle}
|
|
556
|
+
isDrawerOpen={true}
|
|
557
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
558
|
+
setIsDrawerOpen={jest.fn()}
|
|
559
|
+
conversations={[{ id: '1', text: 'ChatBot documentation', listItemProps: { className: 'test' } }]}
|
|
560
|
+
/>
|
|
561
|
+
);
|
|
562
|
+
expect(screen.getByRole('listitem')).toHaveClass('test');
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
it('should be able to spread search input props when searchInputProps is passed', () => {
|
|
566
|
+
render(
|
|
567
|
+
<ChatbotConversationHistoryNav
|
|
568
|
+
onDrawerToggle={onDrawerToggle}
|
|
569
|
+
isDrawerOpen={true}
|
|
570
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
571
|
+
setIsDrawerOpen={jest.fn()}
|
|
572
|
+
conversations={initialConversations}
|
|
573
|
+
handleTextInputChange={jest.fn()}
|
|
574
|
+
searchInputProps={{ value: 'I am a sample search' }}
|
|
575
|
+
/>
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
expect(screen.getByRole('dialog', { name: /Chat history I am a sample search/i })).toBeInTheDocument();
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
it('overrides nav title heading level when navTitleProps.headingLevel is passed', () => {
|
|
582
|
+
render(
|
|
583
|
+
<ChatbotConversationHistoryNav
|
|
584
|
+
onDrawerToggle={onDrawerToggle}
|
|
585
|
+
isDrawerOpen={true}
|
|
586
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
587
|
+
setIsDrawerOpen={jest.fn()}
|
|
588
|
+
conversations={{ Today: initialConversations }}
|
|
589
|
+
navTitleProps={{ headingLevel: 'h1' }}
|
|
590
|
+
/>
|
|
591
|
+
);
|
|
592
|
+
expect(screen.queryByRole('heading', { name: /Chat history/i, level: 2 })).not.toBeInTheDocument();
|
|
593
|
+
expect(screen.getByRole('heading', { name: /Chat history/i, level: 1 })).toBeInTheDocument();
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
it('overrides nav title icon when navTitleIcon is passed in', () => {
|
|
597
|
+
render(
|
|
598
|
+
<ChatbotConversationHistoryNav
|
|
599
|
+
onDrawerToggle={onDrawerToggle}
|
|
600
|
+
isDrawerOpen={true}
|
|
601
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
602
|
+
setIsDrawerOpen={jest.fn()}
|
|
603
|
+
conversations={initialConversations}
|
|
604
|
+
navTitleIcon={<BellIcon data-testid="bell" />}
|
|
605
|
+
/>
|
|
606
|
+
);
|
|
607
|
+
expect(screen.getByTestId('bell')).toBeInTheDocument();
|
|
608
|
+
});
|
|
436
609
|
});
|
|
@@ -8,6 +8,7 @@ import { useRef, Fragment } from 'react';
|
|
|
8
8
|
// Import PatternFly components
|
|
9
9
|
import {
|
|
10
10
|
Button,
|
|
11
|
+
ButtonProps,
|
|
11
12
|
Drawer,
|
|
12
13
|
DrawerPanelContent,
|
|
13
14
|
DrawerContent,
|
|
@@ -18,13 +19,10 @@ import {
|
|
|
18
19
|
DrawerCloseButton,
|
|
19
20
|
DrawerContentBody,
|
|
20
21
|
SearchInput,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
MenuContent,
|
|
26
|
-
MenuItemProps,
|
|
27
|
-
MenuProps,
|
|
22
|
+
List,
|
|
23
|
+
ListItem,
|
|
24
|
+
ListItemProps,
|
|
25
|
+
Title,
|
|
28
26
|
DrawerPanelContentProps,
|
|
29
27
|
DrawerContentProps,
|
|
30
28
|
DrawerContentBodyProps,
|
|
@@ -32,10 +30,15 @@ import {
|
|
|
32
30
|
DrawerActionsProps,
|
|
33
31
|
DrawerCloseButtonProps,
|
|
34
32
|
DrawerPanelBodyProps,
|
|
35
|
-
SkeletonProps
|
|
33
|
+
SkeletonProps,
|
|
34
|
+
Icon,
|
|
35
|
+
MenuProps, // Remove in next breaking change
|
|
36
|
+
TitleProps,
|
|
37
|
+
ListProps,
|
|
38
|
+
SearchInputProps
|
|
36
39
|
} from '@patternfly/react-core';
|
|
37
40
|
|
|
38
|
-
import { OutlinedCommentAltIcon } from '@patternfly/react-icons';
|
|
41
|
+
import { OutlinedClockIcon, OutlinedCommentAltIcon, PenToSquareIcon } from '@patternfly/react-icons';
|
|
39
42
|
import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
|
|
40
43
|
import ConversationHistoryDropdown from './ChatbotConversationHistoryDropdown';
|
|
41
44
|
import LoadingState from './LoadingState';
|
|
@@ -58,8 +61,12 @@ export interface Conversation {
|
|
|
58
61
|
label?: string;
|
|
59
62
|
/** Callback for when user selects item. */
|
|
60
63
|
onSelect?: (event?: React.MouseEvent, value?: string | number) => void;
|
|
61
|
-
/** Additional props passed to conversation
|
|
62
|
-
additionalProps?:
|
|
64
|
+
/** Additional props passed to conversation button item */
|
|
65
|
+
additionalProps?: ButtonProps;
|
|
66
|
+
/** Additional props passed to conversation list item */
|
|
67
|
+
listItemProps?: Omit<ListItemProps, 'children'>;
|
|
68
|
+
/** Custom dropdown ID to ensure uniqueness across demo instances */
|
|
69
|
+
dropdownId?: string;
|
|
63
70
|
}
|
|
64
71
|
export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
65
72
|
/** Function called to toggle drawer */
|
|
@@ -74,6 +81,12 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
|
74
81
|
onSelectActiveItem?: (event?: React.MouseEvent, itemId?: string | number) => void;
|
|
75
82
|
/** Items shown in conversation history */
|
|
76
83
|
conversations: Conversation[] | { [key: string]: Conversation[] };
|
|
84
|
+
/** Additional button props for new chat button. */
|
|
85
|
+
newChatButtonProps?: ButtonProps;
|
|
86
|
+
/** Additional props applied to all conversation list headers */
|
|
87
|
+
listTitleProps?: Partial<TitleProps>;
|
|
88
|
+
/** Additional props applied to conversation list. If conversations is an object, you should pass an object of ListProps for each group. */
|
|
89
|
+
listProps?: ListProps | { [key: string]: ListProps };
|
|
77
90
|
/** Text shown in blue button */
|
|
78
91
|
newChatButtonText?: string;
|
|
79
92
|
/** Callback function for when blue button is clicked. Omit to hide blue "new chat button" */
|
|
@@ -84,6 +97,8 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
|
84
97
|
searchInputPlaceholder?: string;
|
|
85
98
|
/** Aria label for search input */
|
|
86
99
|
searchInputAriaLabel?: string;
|
|
100
|
+
/** Additional props passed to search input */
|
|
101
|
+
searchInputProps?: SearchInputProps;
|
|
87
102
|
/** A callback for when the input value changes. Omit to hide input field */
|
|
88
103
|
handleTextInputChange?: (value: string) => void;
|
|
89
104
|
/** Display mode of chatbot */
|
|
@@ -92,7 +107,7 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
|
92
107
|
reverseButtonOrder?: boolean;
|
|
93
108
|
/** Custom test id for the drawer actions */
|
|
94
109
|
drawerActionsTestId?: string;
|
|
95
|
-
/** Additional props applied to
|
|
110
|
+
/** @deprecated Additional props applied to list container */
|
|
96
111
|
menuProps?: MenuProps;
|
|
97
112
|
/** Additional props applied to panel */
|
|
98
113
|
drawerPanelContentProps?: DrawerPanelContentProps;
|
|
@@ -120,6 +135,14 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
|
120
135
|
noResultsState?: HistoryEmptyStateProps;
|
|
121
136
|
/** Sets drawer to compact styling. */
|
|
122
137
|
isCompact?: boolean;
|
|
138
|
+
/** Display title */
|
|
139
|
+
title?: string;
|
|
140
|
+
/** Icon displayed in title */
|
|
141
|
+
navTitleIcon?: React.ReactNode;
|
|
142
|
+
/** Title header level */
|
|
143
|
+
navTitleProps?: Partial<TitleProps>;
|
|
144
|
+
/** Visually hidden text that gets announced by assistive technologies. Should be used to convey the result count when the search input value changes. */
|
|
145
|
+
searchInputScreenReaderText?: string;
|
|
123
146
|
}
|
|
124
147
|
|
|
125
148
|
export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversationHistoryNavProps> = ({
|
|
@@ -129,16 +152,19 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
129
152
|
activeItemId,
|
|
130
153
|
onSelectActiveItem,
|
|
131
154
|
conversations,
|
|
155
|
+
listTitleProps,
|
|
156
|
+
listProps,
|
|
132
157
|
newChatButtonText = 'New chat',
|
|
133
158
|
drawerContent,
|
|
134
159
|
onNewChat,
|
|
160
|
+
newChatButtonProps,
|
|
135
161
|
searchInputPlaceholder = 'Search previous conversations...',
|
|
136
|
-
searchInputAriaLabel = '
|
|
162
|
+
searchInputAriaLabel = 'Search previous conversations',
|
|
163
|
+
searchInputProps,
|
|
137
164
|
handleTextInputChange,
|
|
138
165
|
displayMode,
|
|
139
166
|
reverseButtonOrder = false,
|
|
140
167
|
drawerActionsTestId = 'chatbot-nav-drawer-actions',
|
|
141
|
-
menuProps,
|
|
142
168
|
drawerPanelContentProps,
|
|
143
169
|
drawerContentProps,
|
|
144
170
|
drawerContentBodyProps,
|
|
@@ -152,6 +178,10 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
152
178
|
emptyState,
|
|
153
179
|
noResultsState,
|
|
154
180
|
isCompact,
|
|
181
|
+
title = 'Chat history',
|
|
182
|
+
navTitleProps,
|
|
183
|
+
navTitleIcon = <OutlinedClockIcon />,
|
|
184
|
+
searchInputScreenReaderText,
|
|
155
185
|
...props
|
|
156
186
|
}: ChatbotConversationHistoryNavProps) => {
|
|
157
187
|
const drawerRef = useRef<HTMLDivElement>(null);
|
|
@@ -161,55 +191,60 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
161
191
|
};
|
|
162
192
|
|
|
163
193
|
const getNavItem = (conversation: Conversation) => (
|
|
164
|
-
<
|
|
165
|
-
className={`pf-
|
|
166
|
-
itemId={conversation.id}
|
|
194
|
+
<ListItem
|
|
195
|
+
className={`pf-chatbot__conversation-list-item ${activeItemId && activeItemId === conversation.id ? 'pf-chatbot__conversation-list-item--active' : ''}`}
|
|
167
196
|
key={conversation.id}
|
|
168
|
-
{...
|
|
169
|
-
/* eslint-disable indent */
|
|
170
|
-
{...(conversation.menuItems
|
|
171
|
-
? {
|
|
172
|
-
actions: (
|
|
173
|
-
<ConversationHistoryDropdown
|
|
174
|
-
menuClassName={conversation.menuClassName}
|
|
175
|
-
onSelect={conversation.onSelect}
|
|
176
|
-
menuItems={conversation.menuItems}
|
|
177
|
-
label={conversation.label}
|
|
178
|
-
/>
|
|
179
|
-
)
|
|
180
|
-
}
|
|
181
|
-
: {})}
|
|
182
|
-
{...conversation.additionalProps}
|
|
197
|
+
{...conversation.listItemProps}
|
|
183
198
|
/* eslint-enable indent */
|
|
184
199
|
>
|
|
185
|
-
|
|
186
|
-
|
|
200
|
+
<>
|
|
201
|
+
<Button
|
|
202
|
+
className="pf-chatbot__conversation-history-item"
|
|
203
|
+
variant="link"
|
|
204
|
+
{...conversation.additionalProps}
|
|
205
|
+
{...(conversation.noIcon ? {} : { icon: conversation.icon ?? <OutlinedCommentAltIcon /> })}
|
|
206
|
+
onClick={(event) => onSelectActiveItem?.(event, conversation.id)}
|
|
207
|
+
>
|
|
208
|
+
{conversation.text}
|
|
209
|
+
</Button>
|
|
210
|
+
{conversation.menuItems && (
|
|
211
|
+
<ConversationHistoryDropdown
|
|
212
|
+
menuClassName={conversation.menuClassName}
|
|
213
|
+
onSelect={conversation.onSelect}
|
|
214
|
+
menuItems={conversation.menuItems}
|
|
215
|
+
label={conversation.label}
|
|
216
|
+
id={conversation.dropdownId}
|
|
217
|
+
/>
|
|
218
|
+
)}
|
|
219
|
+
</>
|
|
220
|
+
</ListItem>
|
|
187
221
|
);
|
|
188
222
|
|
|
189
|
-
const
|
|
223
|
+
const buildConversations = () => {
|
|
190
224
|
if (Array.isArray(conversations)) {
|
|
191
|
-
// Render for array of MenuItemObject
|
|
192
225
|
return (
|
|
193
|
-
<
|
|
226
|
+
<List className="pf-chatbot__conversation-list" isPlain {...listProps}>
|
|
194
227
|
{conversations.map((conversation) => (
|
|
195
228
|
<Fragment key={conversation.id}>{getNavItem(conversation)}</Fragment>
|
|
196
229
|
))}
|
|
197
|
-
</
|
|
230
|
+
</List>
|
|
198
231
|
);
|
|
199
232
|
} else {
|
|
200
|
-
// Render for object with NavItemObject arrays as values
|
|
201
233
|
return (
|
|
202
|
-
|
|
234
|
+
<div>
|
|
203
235
|
{Object.keys(conversations).map((navGroup) => (
|
|
204
|
-
<
|
|
205
|
-
<
|
|
236
|
+
<section key={navGroup}>
|
|
237
|
+
<Title headingLevel="h4" className="pf-chatbot__conversation-list-header" {...listTitleProps}>
|
|
238
|
+
{navGroup}
|
|
239
|
+
</Title>
|
|
240
|
+
<List className="pf-chatbot__conversation-list" isPlain {...listProps?.[navGroup]}>
|
|
206
241
|
{conversations[navGroup].map((conversation) => (
|
|
207
242
|
<Fragment key={conversation.id}>{getNavItem(conversation)}</Fragment>
|
|
208
243
|
))}
|
|
209
|
-
</
|
|
210
|
-
</
|
|
244
|
+
</List>
|
|
245
|
+
</section>
|
|
211
246
|
))}
|
|
212
|
-
|
|
247
|
+
</div>
|
|
213
248
|
);
|
|
214
249
|
}
|
|
215
250
|
};
|
|
@@ -229,24 +264,11 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
229
264
|
if (noResultsState) {
|
|
230
265
|
return <HistoryEmptyState {...noResultsState} />;
|
|
231
266
|
}
|
|
232
|
-
return (
|
|
233
|
-
<Menu isPlain onSelect={onSelectActiveItem} activeItemId={activeItemId} {...menuProps}>
|
|
234
|
-
<MenuContent>{buildMenu()}</MenuContent>
|
|
235
|
-
</Menu>
|
|
236
|
-
);
|
|
267
|
+
return <>{buildConversations()}</>;
|
|
237
268
|
};
|
|
238
269
|
|
|
239
270
|
const renderDrawerContent = () => (
|
|
240
271
|
<>
|
|
241
|
-
{handleTextInputChange && (
|
|
242
|
-
<div className="pf-chatbot__input">
|
|
243
|
-
<SearchInput
|
|
244
|
-
aria-label={searchInputAriaLabel}
|
|
245
|
-
onChange={(_event, value) => handleTextInputChange(value)}
|
|
246
|
-
placeholder={searchInputPlaceholder}
|
|
247
|
-
/>
|
|
248
|
-
</div>
|
|
249
|
-
)}
|
|
250
272
|
<DrawerPanelBody {...drawerPanelBodyProps}>{renderMenuContent()}</DrawerPanelBody>
|
|
251
273
|
</>
|
|
252
274
|
);
|
|
@@ -262,12 +284,40 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
262
284
|
>
|
|
263
285
|
<DrawerCloseButton onClick={onDrawerToggle} {...drawerCloseButtonProps} />
|
|
264
286
|
{onNewChat && (
|
|
265
|
-
<Button
|
|
287
|
+
<Button
|
|
288
|
+
size={isCompact ? 'sm' : undefined}
|
|
289
|
+
onClick={onNewChat}
|
|
290
|
+
icon={<PenToSquareIcon />}
|
|
291
|
+
{...newChatButtonProps}
|
|
292
|
+
>
|
|
266
293
|
{newChatButtonText}
|
|
267
294
|
</Button>
|
|
268
295
|
)}
|
|
269
296
|
</DrawerActions>
|
|
270
297
|
</DrawerHead>
|
|
298
|
+
<div className="pf-chatbot__heading-container">
|
|
299
|
+
<div className="pf-chatbot__title-container">
|
|
300
|
+
<Icon size="lg" className="pf-chatbot__title-icon">
|
|
301
|
+
{navTitleIcon}
|
|
302
|
+
</Icon>
|
|
303
|
+
<Title className="pf-chatbot__title" headingLevel="h2" {...navTitleProps}>
|
|
304
|
+
{title}
|
|
305
|
+
</Title>
|
|
306
|
+
</div>
|
|
307
|
+
{!isLoading && handleTextInputChange && (
|
|
308
|
+
<div className="pf-chatbot__input">
|
|
309
|
+
<SearchInput
|
|
310
|
+
aria-label={searchInputAriaLabel}
|
|
311
|
+
onChange={(_event, value) => handleTextInputChange(value)}
|
|
312
|
+
placeholder={searchInputPlaceholder}
|
|
313
|
+
{...searchInputProps}
|
|
314
|
+
/>
|
|
315
|
+
{searchInputScreenReaderText && (
|
|
316
|
+
<div className="pf-chatbot__filter-announcement">{searchInputScreenReaderText}</div>
|
|
317
|
+
)}
|
|
318
|
+
</div>
|
|
319
|
+
)}
|
|
320
|
+
</div>
|
|
271
321
|
{isLoading ? <LoadingState {...loadingState} /> : renderDrawerContent()}
|
|
272
322
|
</>
|
|
273
323
|
);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// ============================================================================
|
|
7
7
|
.pf-chatbot__footer {
|
|
8
8
|
--pf-chatbot__footer--RowGap: var(--pf-t--global--spacer--md);
|
|
9
|
-
background-color: var(--pf-t--
|
|
9
|
+
background-color: var(--pf-t--global--background--color--secondary--default);
|
|
10
10
|
display: flex;
|
|
11
11
|
flex-direction: column;
|
|
12
12
|
row-gap: var(--pf-chatbot__footer--RowGap);
|