@patternfly/chatbot 6.4.0-prerelease.4 → 6.4.0-prerelease.6
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.js +1 -1
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +6 -6
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +13 -4
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +6 -12
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +21 -0
- package/dist/cjs/MessageBar/MessageBar.js +19 -4
- package/dist/css/main.css +31 -27
- package/dist/css/main.css.map +1 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +1 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +6 -6
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +13 -4
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +7 -13
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +21 -0
- package/dist/esm/MessageBar/MessageBar.js +19 -4
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotConversationEditing.tsx +202 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +14 -1
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx +6 -6
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +0 -1
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +40 -32
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +70 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +55 -49
- package/src/ChatbotModal/ChatbotModal.scss +1 -1
- package/src/MessageBar/MessageBar.tsx +23 -3
|
@@ -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,
|
|
@@ -33,9 +31,10 @@ import {
|
|
|
33
31
|
DrawerCloseButtonProps,
|
|
34
32
|
DrawerPanelBodyProps,
|
|
35
33
|
SkeletonProps,
|
|
36
|
-
Title,
|
|
37
34
|
Icon,
|
|
38
|
-
|
|
35
|
+
MenuProps, // Remove in next breaking change
|
|
36
|
+
TitleProps,
|
|
37
|
+
ListProps
|
|
39
38
|
} from '@patternfly/react-core';
|
|
40
39
|
|
|
41
40
|
import { OutlinedClockIcon, OutlinedCommentAltIcon, PenToSquareIcon } from '@patternfly/react-icons';
|
|
@@ -61,8 +60,10 @@ export interface Conversation {
|
|
|
61
60
|
label?: string;
|
|
62
61
|
/** Callback for when user selects item. */
|
|
63
62
|
onSelect?: (event?: React.MouseEvent, value?: string | number) => void;
|
|
64
|
-
/** Additional props passed to conversation
|
|
65
|
-
additionalProps?:
|
|
63
|
+
/** Additional props passed to conversation button item */
|
|
64
|
+
additionalProps?: ButtonProps;
|
|
65
|
+
/** Additional props passed to conversation list item */
|
|
66
|
+
listItemProps?: Omit<ListItemProps, 'children'>;
|
|
66
67
|
}
|
|
67
68
|
export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
68
69
|
/** Function called to toggle drawer */
|
|
@@ -79,6 +80,10 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
|
79
80
|
conversations: Conversation[] | { [key: string]: Conversation[] };
|
|
80
81
|
/** Additional button props for new chat button. */
|
|
81
82
|
newChatButtonProps?: ButtonProps;
|
|
83
|
+
/** Additional props applied to all conversation list headers */
|
|
84
|
+
titleProps?: Partial<TitleProps>;
|
|
85
|
+
/** Additional props applied to conversation list. If conversations is an object, you should pass an object of ListProps for each group. */
|
|
86
|
+
listProps?: ListProps | { [key: string]: ListProps };
|
|
82
87
|
/** Text shown in blue button */
|
|
83
88
|
newChatButtonText?: string;
|
|
84
89
|
/** Callback function for when blue button is clicked. Omit to hide blue "new chat button" */
|
|
@@ -97,7 +102,7 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
|
97
102
|
reverseButtonOrder?: boolean;
|
|
98
103
|
/** Custom test id for the drawer actions */
|
|
99
104
|
drawerActionsTestId?: string;
|
|
100
|
-
/** Additional props applied to
|
|
105
|
+
/** @deprecated Additional props applied to list container */
|
|
101
106
|
menuProps?: MenuProps;
|
|
102
107
|
/** Additional props applied to panel */
|
|
103
108
|
drawerPanelContentProps?: DrawerPanelContentProps;
|
|
@@ -136,6 +141,8 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
136
141
|
activeItemId,
|
|
137
142
|
onSelectActiveItem,
|
|
138
143
|
conversations,
|
|
144
|
+
titleProps,
|
|
145
|
+
listProps,
|
|
139
146
|
newChatButtonText = 'New chat',
|
|
140
147
|
drawerContent,
|
|
141
148
|
onNewChat,
|
|
@@ -146,7 +153,6 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
146
153
|
displayMode,
|
|
147
154
|
reverseButtonOrder = false,
|
|
148
155
|
drawerActionsTestId = 'chatbot-nav-drawer-actions',
|
|
149
|
-
menuProps,
|
|
150
156
|
drawerPanelContentProps,
|
|
151
157
|
drawerContentProps,
|
|
152
158
|
drawerContentBodyProps,
|
|
@@ -170,55 +176,59 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
170
176
|
};
|
|
171
177
|
|
|
172
178
|
const getNavItem = (conversation: Conversation) => (
|
|
173
|
-
<
|
|
174
|
-
className={`pf-
|
|
175
|
-
itemId={conversation.id}
|
|
179
|
+
<ListItem
|
|
180
|
+
className={`pf-chatbot__conversation-list-item ${activeItemId && activeItemId === conversation.id ? 'pf-chatbot__conversation-list-item--active' : ''}`}
|
|
176
181
|
key={conversation.id}
|
|
177
|
-
{...
|
|
178
|
-
/* eslint-disable indent */
|
|
179
|
-
{...(conversation.menuItems
|
|
180
|
-
? {
|
|
181
|
-
actions: (
|
|
182
|
-
<ConversationHistoryDropdown
|
|
183
|
-
menuClassName={conversation.menuClassName}
|
|
184
|
-
onSelect={conversation.onSelect}
|
|
185
|
-
menuItems={conversation.menuItems}
|
|
186
|
-
label={conversation.label}
|
|
187
|
-
/>
|
|
188
|
-
)
|
|
189
|
-
}
|
|
190
|
-
: {})}
|
|
191
|
-
{...conversation.additionalProps}
|
|
182
|
+
{...conversation.listItemProps}
|
|
192
183
|
/* eslint-enable indent */
|
|
193
184
|
>
|
|
194
|
-
|
|
195
|
-
|
|
185
|
+
<>
|
|
186
|
+
<Button
|
|
187
|
+
className="pf-chatbot__conversation-history-item"
|
|
188
|
+
variant="link"
|
|
189
|
+
{...conversation.additionalProps}
|
|
190
|
+
{...(conversation.noIcon ? {} : { icon: conversation.icon ?? <OutlinedCommentAltIcon /> })}
|
|
191
|
+
onClick={(event) => onSelectActiveItem?.(event, conversation.id)}
|
|
192
|
+
>
|
|
193
|
+
{conversation.text}
|
|
194
|
+
</Button>
|
|
195
|
+
{conversation.menuItems && (
|
|
196
|
+
<ConversationHistoryDropdown
|
|
197
|
+
menuClassName={conversation.menuClassName}
|
|
198
|
+
onSelect={conversation.onSelect}
|
|
199
|
+
menuItems={conversation.menuItems}
|
|
200
|
+
label={conversation.label}
|
|
201
|
+
/>
|
|
202
|
+
)}
|
|
203
|
+
</>
|
|
204
|
+
</ListItem>
|
|
196
205
|
);
|
|
197
206
|
|
|
198
|
-
const
|
|
207
|
+
const buildConversations = () => {
|
|
199
208
|
if (Array.isArray(conversations)) {
|
|
200
|
-
// Render for array of MenuItemObject
|
|
201
209
|
return (
|
|
202
|
-
<
|
|
210
|
+
<List className="pf-chatbot__conversation-list" isPlain {...listProps}>
|
|
203
211
|
{conversations.map((conversation) => (
|
|
204
212
|
<Fragment key={conversation.id}>{getNavItem(conversation)}</Fragment>
|
|
205
213
|
))}
|
|
206
|
-
</
|
|
214
|
+
</List>
|
|
207
215
|
);
|
|
208
216
|
} else {
|
|
209
|
-
// Render for object with NavItemObject arrays as values
|
|
210
217
|
return (
|
|
211
|
-
|
|
218
|
+
<div>
|
|
212
219
|
{Object.keys(conversations).map((navGroup) => (
|
|
213
|
-
<
|
|
214
|
-
<
|
|
220
|
+
<section key={navGroup}>
|
|
221
|
+
<Title headingLevel="h4" className="pf-chatbot__conversation-list-header" {...titleProps}>
|
|
222
|
+
{navGroup}
|
|
223
|
+
</Title>
|
|
224
|
+
<List className="pf-chatbot__conversation-list" isPlain {...listProps?.[navGroup]}>
|
|
215
225
|
{conversations[navGroup].map((conversation) => (
|
|
216
226
|
<Fragment key={conversation.id}>{getNavItem(conversation)}</Fragment>
|
|
217
227
|
))}
|
|
218
|
-
</
|
|
219
|
-
</
|
|
228
|
+
</List>
|
|
229
|
+
</section>
|
|
220
230
|
))}
|
|
221
|
-
|
|
231
|
+
</div>
|
|
222
232
|
);
|
|
223
233
|
}
|
|
224
234
|
};
|
|
@@ -238,11 +248,7 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
238
248
|
if (noResultsState) {
|
|
239
249
|
return <HistoryEmptyState {...noResultsState} />;
|
|
240
250
|
}
|
|
241
|
-
return (
|
|
242
|
-
<Menu isPlain onSelect={onSelectActiveItem} activeItemId={activeItemId} {...menuProps}>
|
|
243
|
-
<MenuContent>{buildMenu()}</MenuContent>
|
|
244
|
-
</Menu>
|
|
245
|
-
);
|
|
251
|
+
return <>{buildConversations()}</>;
|
|
246
252
|
};
|
|
247
253
|
|
|
248
254
|
const renderDrawerContent = () => (
|
|
@@ -141,6 +141,7 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
|
|
|
141
141
|
const [message, setMessage] = useState<string | number>(value ?? '');
|
|
142
142
|
const [isListeningMessage, setIsListeningMessage] = useState<boolean>(false);
|
|
143
143
|
const [hasSentMessage, setHasSentMessage] = useState(false);
|
|
144
|
+
const [isComposing, setIsComposing] = useState(false);
|
|
144
145
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
|
145
146
|
const textareaRef = (innerRef as React.RefObject<HTMLTextAreaElement>) ?? inputRef;
|
|
146
147
|
const attachButtonRef = useRef<HTMLButtonElement>(null);
|
|
@@ -285,21 +286,38 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
|
|
|
285
286
|
|
|
286
287
|
const handleKeyDown = useCallback(
|
|
287
288
|
(event: ReactKeyboardEvent) => {
|
|
288
|
-
|
|
289
|
+
// Japanese and other languages may use IME for character input.
|
|
290
|
+
// In these cases, enter is used to select the final input, so we need to check for composition end instead.
|
|
291
|
+
// See more info at https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/
|
|
292
|
+
// Chrome, Edge, and Firefox seem to work well with just the compose event.
|
|
293
|
+
// Safari is a little bit special. We need to handle 229 as well in this case.
|
|
294
|
+
const nativeEvent = event.nativeEvent as KeyboardEvent;
|
|
295
|
+
const isCompositionKey = nativeEvent.which === 229;
|
|
296
|
+
const isCurrentlyComposing = isComposing || isCompositionKey;
|
|
297
|
+
|
|
298
|
+
if (event.key === 'Enter' && !isCurrentlyComposing && !event.shiftKey) {
|
|
289
299
|
event.preventDefault();
|
|
290
300
|
if (!isSendButtonDisabled && !hasStopButton) {
|
|
291
301
|
handleSend(message);
|
|
292
302
|
}
|
|
293
303
|
}
|
|
294
|
-
if (event.key === 'Enter' && event.shiftKey) {
|
|
304
|
+
if (event.key === 'Enter' && !isCurrentlyComposing && event.shiftKey) {
|
|
295
305
|
if (textareaRef.current) {
|
|
296
306
|
handleNewLine(textareaRef.current);
|
|
297
307
|
}
|
|
298
308
|
}
|
|
299
309
|
},
|
|
300
|
-
[isSendButtonDisabled, hasStopButton, handleSend, message]
|
|
310
|
+
[isSendButtonDisabled, hasStopButton, handleSend, message, isComposing]
|
|
301
311
|
);
|
|
302
312
|
|
|
313
|
+
const handleCompositionStart = useCallback(() => {
|
|
314
|
+
setIsComposing(true);
|
|
315
|
+
}, []);
|
|
316
|
+
|
|
317
|
+
const handleCompositionEnd = useCallback(() => {
|
|
318
|
+
setIsComposing(false);
|
|
319
|
+
}, []);
|
|
320
|
+
|
|
303
321
|
const handleAttachMenuToggle = () => {
|
|
304
322
|
attachMenuProps?.setIsAttachMenuOpen && attachMenuProps?.setIsAttachMenuOpen(!attachMenuProps?.isAttachMenuOpen);
|
|
305
323
|
attachMenuProps?.onAttachMenuToggleClick();
|
|
@@ -402,6 +420,8 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
|
|
|
402
420
|
placeholder={isListeningMessage ? listeningText : placeholder}
|
|
403
421
|
ref={textareaRef}
|
|
404
422
|
onKeyDown={handleKeyDown}
|
|
423
|
+
onCompositionStart={handleCompositionStart}
|
|
424
|
+
onCompositionEnd={handleCompositionEnd}
|
|
405
425
|
{...props}
|
|
406
426
|
/>
|
|
407
427
|
</div>
|