@patternfly/chatbot 2.2.0-prerelease.20 → 2.2.0-prerelease.22

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 (53) hide show
  1. package/dist/cjs/Message/Message.d.ts +3 -0
  2. package/dist/cjs/Message/Message.js +22 -5
  3. package/dist/cjs/Message/Message.test.js +94 -0
  4. package/dist/cjs/Message/TableMessage/TableMessage.d.ts +20 -0
  5. package/dist/cjs/Message/TableMessage/TableMessage.js +67 -0
  6. package/dist/cjs/Message/TableMessage/TbodyMessage.d.ts +7 -0
  7. package/dist/cjs/Message/TableMessage/TbodyMessage.js +33 -0
  8. package/dist/cjs/Message/TableMessage/TdMessage.d.ts +5 -0
  9. package/dist/cjs/Message/TableMessage/TdMessage.js +26 -0
  10. package/dist/cjs/Message/TableMessage/ThMessage.d.ts +5 -0
  11. package/dist/cjs/Message/TableMessage/ThMessage.js +26 -0
  12. package/dist/cjs/Message/TableMessage/TheadMessage.d.ts +5 -0
  13. package/dist/cjs/Message/TableMessage/TheadMessage.js +26 -0
  14. package/dist/cjs/Message/TableMessage/TrMessage.d.ts +7 -0
  15. package/dist/cjs/Message/TableMessage/TrMessage.js +37 -0
  16. package/dist/cjs/MessageBar/MessageBar.d.ts +4 -1
  17. package/dist/cjs/MessageBar/MessageBar.js +125 -39
  18. package/dist/css/main.css +59 -17
  19. package/dist/css/main.css.map +1 -1
  20. package/dist/esm/Message/Message.d.ts +3 -0
  21. package/dist/esm/Message/Message.js +22 -5
  22. package/dist/esm/Message/Message.test.js +94 -0
  23. package/dist/esm/Message/TableMessage/TableMessage.d.ts +20 -0
  24. package/dist/esm/Message/TableMessage/TableMessage.js +62 -0
  25. package/dist/esm/Message/TableMessage/TbodyMessage.d.ts +7 -0
  26. package/dist/esm/Message/TableMessage/TbodyMessage.js +28 -0
  27. package/dist/esm/Message/TableMessage/TdMessage.d.ts +5 -0
  28. package/dist/esm/Message/TableMessage/TdMessage.js +21 -0
  29. package/dist/esm/Message/TableMessage/ThMessage.d.ts +5 -0
  30. package/dist/esm/Message/TableMessage/ThMessage.js +21 -0
  31. package/dist/esm/Message/TableMessage/TheadMessage.d.ts +5 -0
  32. package/dist/esm/Message/TableMessage/TheadMessage.js +21 -0
  33. package/dist/esm/Message/TableMessage/TrMessage.d.ts +7 -0
  34. package/dist/esm/Message/TableMessage/TrMessage.js +32 -0
  35. package/dist/esm/MessageBar/MessageBar.d.ts +4 -1
  36. package/dist/esm/MessageBar/MessageBar.js +125 -39
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +1 -1
  39. package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +27 -1
  40. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +27 -1
  41. package/src/Message/Message.test.tsx +99 -0
  42. package/src/Message/Message.tsx +25 -4
  43. package/src/Message/TableMessage/TableMessage.scss +23 -0
  44. package/src/Message/TableMessage/TableMessage.tsx +83 -0
  45. package/src/Message/TableMessage/TbodyMessage.tsx +20 -0
  46. package/src/Message/TableMessage/TdMessage.tsx +11 -0
  47. package/src/Message/TableMessage/ThMessage.tsx +11 -0
  48. package/src/Message/TableMessage/TheadMessage.tsx +11 -0
  49. package/src/Message/TableMessage/TrMessage.tsx +27 -0
  50. package/src/Message/TextMessage/TextMessage.scss +5 -0
  51. package/src/MessageBar/MessageBar.scss +35 -18
  52. package/src/MessageBar/MessageBar.tsx +144 -53
  53. package/src/main.scss +1 -0
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { ButtonProps, DropEvent } from '@patternfly/react-core';
2
+ import { ButtonProps, DropEvent, TextArea } from '@patternfly/react-core';
3
3
 
4
4
  // Import Chatbot components
5
5
  import SendButton from './SendButton';
@@ -7,7 +7,7 @@ import MicrophoneButton from './MicrophoneButton';
7
7
  import { AttachButton } from './AttachButton';
8
8
  import AttachMenu from '../AttachMenu';
9
9
  import StopButton from './StopButton';
10
- import DOMPurify from 'dompurify';
10
+ import { ChatbotDisplayMode } from '../Chatbot';
11
11
 
12
12
  export interface MessageBarWithAttachMenuProps {
13
13
  /** Flag to enable whether attach menu is open */
@@ -63,7 +63,9 @@ export interface MessageBarProps {
63
63
  };
64
64
  };
65
65
  /** A callback for when the text area value changes. */
66
- onChange?: (event: React.ChangeEvent<HTMLDivElement>, value: string) => void;
66
+ onChange?: (event: React.ChangeEvent<HTMLTextAreaElement>, value: string) => void;
67
+ /** Display mode of chatbot, if you want to message bar to resize when the display mode changes */
68
+ displayMode?: ChatbotDisplayMode;
67
69
  }
68
70
 
69
71
  export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
@@ -79,46 +81,148 @@ export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
79
81
  hasStopButton,
80
82
  buttonProps,
81
83
  onChange,
84
+ displayMode,
82
85
  ...props
83
86
  }: MessageBarProps) => {
84
87
  // Text Input
85
88
  // --------------------------------------------------------------------------
86
89
  const [message, setMessage] = React.useState<string>('');
87
90
  const [isListeningMessage, setIsListeningMessage] = React.useState<boolean>(false);
88
- const [showPlaceholder, setShowPlaceholder] = React.useState(true);
89
- const textareaRef = React.useRef<HTMLDivElement>(null);
91
+ const [hasSentMessage, setHasSentMessage] = React.useState(false);
92
+ const textareaRef = React.useRef<HTMLTextAreaElement>(null);
90
93
  const attachButtonRef = React.useRef<HTMLButtonElement>(null);
91
94
 
92
- const handleInput = (event) => {
93
- // newMessage === '' doesn't work unless we trim, which causes other problems
94
- // textContent seems to work, but doesn't allow for markdown, so we need both
95
- const messageText = DOMPurify.sanitize(event.target.textContent);
96
- if (messageText === '') {
97
- setShowPlaceholder(true);
98
- setMessage('');
99
- onChange && onChange(event, '');
100
- } else {
101
- setShowPlaceholder(false);
102
- // this is so that tests work; RTL doesn't seem to like event.target.innerText, but browsers don't pick up markdown without it
103
- let newMessage = messageText;
104
- if (event.target.innerText) {
105
- newMessage = DOMPurify.sanitize(event.target.innerText);
95
+ const setInitialLineHeight = (field: HTMLTextAreaElement) => {
96
+ field.style.setProperty('line-height', '1rem');
97
+ const parent = field.parentElement;
98
+ if (parent) {
99
+ parent.style.setProperty('margin-top', `1rem`);
100
+ parent.style.setProperty('margin-bottom', `0rem`);
101
+ parent.style.setProperty('height', 'inherit');
102
+
103
+ const grandparent = parent.parentElement;
104
+ if (grandparent) {
105
+ grandparent.style.setProperty('flex-basis', 'auto');
106
106
  }
107
- setMessage(newMessage);
108
- onChange && onChange(event, newMessage);
109
107
  }
110
108
  };
111
109
 
112
- // Handle sending message
113
- const handleSend = React.useCallback(() => {
114
- onSendMessage(message);
110
+ const setAutoHeight = (field: HTMLTextAreaElement) => {
111
+ const parent = field.parentElement;
112
+ if (parent) {
113
+ parent.style.setProperty('height', 'inherit');
114
+ const computed = window.getComputedStyle(field);
115
+ // Calculate the height
116
+ const height =
117
+ parseInt(computed.getPropertyValue('border-top-width')) +
118
+ parseInt(computed.getPropertyValue('padding-top')) +
119
+ field.scrollHeight +
120
+ parseInt(computed.getPropertyValue('padding-bottom')) +
121
+ parseInt(computed.getPropertyValue('border-bottom-width'));
122
+ parent.style.setProperty('height', `${height}px`);
123
+
124
+ if (height > 32 || window.innerWidth <= 507) {
125
+ parent.style.setProperty('margin-bottom', `1rem`);
126
+ parent.style.setProperty('margin-top', `1rem`);
127
+ }
128
+ }
129
+ };
130
+
131
+ const textIsLongerThan2Lines = (field: HTMLTextAreaElement) => {
132
+ const lineHeight = parseFloat(window.getComputedStyle(field).lineHeight);
133
+ const lines = field.scrollHeight / lineHeight;
134
+ return lines > 2;
135
+ };
136
+
137
+ const setAutoWidth = (field: HTMLTextAreaElement) => {
138
+ const parent = field.parentElement;
139
+ if (parent) {
140
+ const grandparent = parent.parentElement;
141
+ if (textIsLongerThan2Lines(field) && grandparent) {
142
+ grandparent.style.setProperty('flex-basis', `100%`);
143
+ }
144
+ }
145
+ };
146
+
147
+ const handleNewLine = (field: HTMLTextAreaElement) => {
148
+ const parent = field.parentElement;
149
+ if (parent) {
150
+ parent.style.setProperty('margin-bottom', `1rem`);
151
+ parent.style.setProperty('margin-top', `1rem`);
152
+ }
153
+ };
154
+
155
+ React.useEffect(() => {
156
+ const field = textareaRef.current;
157
+ if (field) {
158
+ if (field.value === '') {
159
+ if (window.innerWidth > 507) {
160
+ setInitialLineHeight(field);
161
+ }
162
+ } else {
163
+ setAutoHeight(field);
164
+ setAutoWidth(field);
165
+ }
166
+ }
167
+ const resetHeight = () => {
168
+ if (field) {
169
+ if (field.value === '') {
170
+ if (window.innerWidth > 507) {
171
+ setInitialLineHeight(field);
172
+ }
173
+ } else {
174
+ setAutoHeight(field);
175
+ setAutoWidth(field);
176
+ }
177
+ }
178
+ };
179
+ window.addEventListener('resize', resetHeight);
180
+
181
+ return () => {
182
+ window.removeEventListener('resize', resetHeight);
183
+ };
184
+ }, []);
185
+
186
+ React.useEffect(() => {
187
+ const field = textareaRef.current;
188
+ if (field) {
189
+ if (field.value === '') {
190
+ setInitialLineHeight(textareaRef.current);
191
+ } else {
192
+ setAutoHeight(textareaRef.current);
193
+ setAutoWidth(field);
194
+ }
195
+ }
196
+ }, [displayMode, message]);
197
+
198
+ React.useEffect(() => {
199
+ const field = textareaRef.current;
200
+ if (field) {
201
+ setInitialLineHeight(field);
202
+ setHasSentMessage(false);
203
+ }
204
+ }, [hasSentMessage]);
205
+
206
+ const handleChange = React.useCallback((event) => {
207
+ onChange && onChange(event, event.target.value);
115
208
  if (textareaRef.current) {
116
- textareaRef.current.innerText = '';
117
- setShowPlaceholder(true);
118
- textareaRef.current.blur();
209
+ if (event.target.value === '') {
210
+ setInitialLineHeight(textareaRef.current);
211
+ } else {
212
+ setAutoHeight(textareaRef.current);
213
+ }
119
214
  }
120
- setMessage('');
121
- }, [onSendMessage, message]);
215
+ setMessage(event.target.value);
216
+ }, []);
217
+
218
+ // Handle sending message
219
+ const handleSend = React.useCallback(() => {
220
+ setMessage((m) => {
221
+ onSendMessage(m);
222
+ setHasSentMessage(true);
223
+ return '';
224
+ });
225
+ }, [onSendMessage]);
122
226
 
123
227
  const handleKeyDown = React.useCallback(
124
228
  (event: React.KeyboardEvent) => {
@@ -128,6 +232,11 @@ export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
128
232
  handleSend();
129
233
  }
130
234
  }
235
+ if (event.key === 'Enter' && event.shiftKey) {
236
+ if (textareaRef.current) {
237
+ handleNewLine(textareaRef.current);
238
+ }
239
+ }
131
240
  },
132
241
  [handleSend, isSendButtonDisabled, handleStopButton]
133
242
  );
@@ -139,12 +248,7 @@ export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
139
248
 
140
249
  const handleSpeechRecognition = (message) => {
141
250
  setMessage(message);
142
- const textarea = textareaRef.current;
143
- if (textarea) {
144
- textarea.focus();
145
- textarea.textContent = DOMPurify.sanitize(message);
146
- }
147
- onChange && onChange({} as React.ChangeEvent<HTMLDivElement>, message);
251
+ onChange && onChange({} as React.ChangeEvent<HTMLTextAreaElement>, message);
148
252
  };
149
253
 
150
254
  const renderButtons = () => {
@@ -200,28 +304,15 @@ export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
200
304
  );
201
305
  };
202
306
 
203
- const placeholder = isListeningMessage ? 'Listening' : 'Send a message...';
204
-
205
307
  const messageBarContents = (
206
308
  <>
207
309
  <div className="pf-chatbot__message-bar-input">
208
- {(showPlaceholder || message === '') && (
209
- <div className="pf-chatbot__message-bar-placeholder">{placeholder}</div>
210
- )}
211
- <div
212
- contentEditable
213
- suppressContentEditableWarning={true}
214
- role="textbox"
215
- aria-multiline="false"
310
+ <TextArea
216
311
  className="pf-chatbot__message-textarea"
217
- onInput={handleInput}
218
- onFocus={() => setShowPlaceholder(false)}
219
- onBlur={() => {
220
- if (message === '') {
221
- setShowPlaceholder(!showPlaceholder);
222
- }
223
- }}
224
- aria-label={placeholder}
312
+ value={message}
313
+ onChange={handleChange}
314
+ aria-label={isListeningMessage ? 'Listening' : 'Send a message...'}
315
+ placeholder={isListeningMessage ? 'Listening' : 'Send a message...'}
225
316
  ref={textareaRef}
226
317
  onKeyDown={handleKeyDown}
227
318
  {...props}
package/src/main.scss CHANGED
@@ -18,6 +18,7 @@
18
18
  @import './Message/CodeBlockMessage/CodeBlockMessage';
19
19
  @import './Message/TextMessage/TextMessage';
20
20
  @import './Message/ListMessage/ListMessage';
21
+ @import './Message/TableMessage/TableMessage';
21
22
  @import './Message/MessageLoading';
22
23
  @import './Message/QuickStarts/QuickStartTile';
23
24
  @import './Message/QuickResponse/QuickResponse';