@patternfly/chatbot 6.5.0-prerelease.21 → 6.5.0-prerelease.23

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 (97) hide show
  1. package/dist/cjs/DeepThinking/DeepThinking.d.ts +13 -0
  2. package/dist/cjs/DeepThinking/DeepThinking.js +31 -3
  3. package/dist/cjs/DeepThinking/DeepThinking.test.js +80 -0
  4. package/dist/cjs/MarkdownContent/MarkdownContent.d.ts +39 -0
  5. package/dist/cjs/MarkdownContent/MarkdownContent.js +181 -0
  6. package/dist/cjs/MarkdownContent/MarkdownContent.test.d.ts +1 -0
  7. package/dist/cjs/MarkdownContent/MarkdownContent.test.js +192 -0
  8. package/dist/cjs/MarkdownContent/index.d.ts +2 -0
  9. package/dist/cjs/MarkdownContent/index.js +23 -0
  10. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.d.ts +3 -1
  11. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +3 -2
  12. package/dist/cjs/Message/LinkMessage/LinkMessage.d.ts +5 -1
  13. package/dist/cjs/Message/LinkMessage/LinkMessage.js +4 -3
  14. package/dist/cjs/Message/ListMessage/OrderedListMessage.d.ts +9 -1
  15. package/dist/cjs/Message/ListMessage/OrderedListMessage.js +2 -1
  16. package/dist/cjs/Message/ListMessage/UnorderedListMessage.d.ts +7 -1
  17. package/dist/cjs/Message/ListMessage/UnorderedListMessage.js +2 -1
  18. package/dist/cjs/Message/Message.js +2 -155
  19. package/dist/cjs/Message/TableMessage/TableMessage.d.ts +6 -1
  20. package/dist/cjs/Message/TableMessage/TableMessage.js +3 -2
  21. package/dist/cjs/Message/TextMessage/TextMessage.d.ts +8 -1
  22. package/dist/cjs/Message/TextMessage/TextMessage.js +3 -2
  23. package/dist/cjs/ToolCall/ToolCall.d.ts +11 -0
  24. package/dist/cjs/ToolCall/ToolCall.js +24 -3
  25. package/dist/cjs/ToolCall/ToolCall.test.js +57 -0
  26. package/dist/cjs/ToolResponse/ToolResponse.d.ts +17 -0
  27. package/dist/cjs/ToolResponse/ToolResponse.js +49 -3
  28. package/dist/cjs/ToolResponse/ToolResponse.test.js +100 -0
  29. package/dist/cjs/index.d.ts +2 -0
  30. package/dist/cjs/index.js +4 -1
  31. package/dist/css/main.css +48 -0
  32. package/dist/css/main.css.map +1 -1
  33. package/dist/dynamic/MarkdownContent/package.json +1 -0
  34. package/dist/esm/DeepThinking/DeepThinking.d.ts +13 -0
  35. package/dist/esm/DeepThinking/DeepThinking.js +28 -3
  36. package/dist/esm/DeepThinking/DeepThinking.test.js +80 -0
  37. package/dist/esm/MarkdownContent/MarkdownContent.d.ts +39 -0
  38. package/dist/esm/MarkdownContent/MarkdownContent.js +174 -0
  39. package/dist/esm/MarkdownContent/MarkdownContent.test.d.ts +1 -0
  40. package/dist/esm/MarkdownContent/MarkdownContent.test.js +187 -0
  41. package/dist/esm/MarkdownContent/index.d.ts +2 -0
  42. package/dist/esm/MarkdownContent/index.js +2 -0
  43. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.d.ts +3 -1
  44. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +3 -2
  45. package/dist/esm/Message/LinkMessage/LinkMessage.d.ts +5 -1
  46. package/dist/esm/Message/LinkMessage/LinkMessage.js +4 -3
  47. package/dist/esm/Message/ListMessage/OrderedListMessage.d.ts +9 -1
  48. package/dist/esm/Message/ListMessage/OrderedListMessage.js +2 -1
  49. package/dist/esm/Message/ListMessage/UnorderedListMessage.d.ts +7 -1
  50. package/dist/esm/Message/ListMessage/UnorderedListMessage.js +2 -1
  51. package/dist/esm/Message/Message.js +3 -156
  52. package/dist/esm/Message/TableMessage/TableMessage.d.ts +6 -1
  53. package/dist/esm/Message/TableMessage/TableMessage.js +3 -2
  54. package/dist/esm/Message/TextMessage/TextMessage.d.ts +8 -1
  55. package/dist/esm/Message/TextMessage/TextMessage.js +3 -2
  56. package/dist/esm/ToolCall/ToolCall.d.ts +11 -0
  57. package/dist/esm/ToolCall/ToolCall.js +21 -3
  58. package/dist/esm/ToolCall/ToolCall.test.js +57 -0
  59. package/dist/esm/ToolResponse/ToolResponse.d.ts +17 -0
  60. package/dist/esm/ToolResponse/ToolResponse.js +46 -3
  61. package/dist/esm/ToolResponse/ToolResponse.test.js +100 -0
  62. package/dist/esm/index.d.ts +2 -0
  63. package/dist/esm/index.js +2 -0
  64. package/dist/tsconfig.tsbuildinfo +1 -1
  65. package/package.json +1 -1
  66. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDeepThinking.tsx +25 -11
  67. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownDeepThinking.tsx +26 -0
  68. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownToolCall.tsx +29 -0
  69. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownToolResponse.tsx +200 -0
  70. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolCall.tsx +14 -1
  71. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolResponse.tsx +222 -105
  72. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +32 -0
  73. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +15 -1
  74. package/src/DeepThinking/DeepThinking.test.tsx +109 -0
  75. package/src/DeepThinking/DeepThinking.tsx +54 -5
  76. package/src/MarkdownContent/MarkdownContent.test.tsx +207 -0
  77. package/src/MarkdownContent/MarkdownContent.tsx +264 -0
  78. package/src/MarkdownContent/index.ts +2 -0
  79. package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +4 -0
  80. package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +5 -1
  81. package/src/Message/LinkMessage/LinkMessage.scss +5 -0
  82. package/src/Message/LinkMessage/LinkMessage.tsx +24 -2
  83. package/src/Message/ListMessage/ListMessage.scss +8 -0
  84. package/src/Message/ListMessage/OrderedListMessage.tsx +16 -2
  85. package/src/Message/ListMessage/UnorderedListMessage.tsx +12 -2
  86. package/src/Message/Message.tsx +21 -181
  87. package/src/Message/TableMessage/TableMessage.scss +11 -0
  88. package/src/Message/TableMessage/TableMessage.tsx +18 -2
  89. package/src/Message/TextMessage/TextMessage.scss +8 -0
  90. package/src/Message/TextMessage/TextMessage.tsx +29 -2
  91. package/src/ToolCall/ToolCall.test.tsx +91 -0
  92. package/src/ToolCall/ToolCall.tsx +49 -4
  93. package/src/ToolResponse/ToolResponse.scss +10 -0
  94. package/src/ToolResponse/ToolResponse.test.tsx +119 -0
  95. package/src/ToolResponse/ToolResponse.tsx +82 -7
  96. package/src/index.ts +3 -0
  97. package/src/main.scss +1 -0
@@ -1,4 +1,5 @@
1
1
  import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
2
3
  import '@testing-library/jest-dom';
3
4
  import ToolResponse from './ToolResponse';
4
5
 
@@ -105,4 +106,122 @@ describe('ToolResponse', () => {
105
106
  const { container } = render(<ToolResponse {...defaultProps} cardBody={undefined} />);
106
107
  expect(container.querySelector('.pf-v6-c-divider')).toBeFalsy();
107
108
  });
109
+
110
+ it('Renders expanded by default', () => {
111
+ render(<ToolResponse {...defaultProps} />);
112
+
113
+ expect(screen.getByRole('button', { name: defaultProps.toggleContent })).toHaveAttribute('aria-expanded', 'true');
114
+ expect(screen.getByText(defaultProps.cardTitle)).toBeVisible();
115
+ expect(screen.getByText(defaultProps.cardBody)).toBeVisible();
116
+ });
117
+
118
+ it('Renders collapsed when isDefaultExpanded is false', () => {
119
+ render(<ToolResponse isDefaultExpanded={false} {...defaultProps} />);
120
+
121
+ expect(screen.getByRole('button', { name: defaultProps.toggleContent })).toHaveAttribute('aria-expanded', 'false');
122
+ expect(screen.getByText(defaultProps.cardTitle)).not.toBeVisible();
123
+ expect(screen.getByText(defaultProps.cardBody)).not.toBeVisible();
124
+ });
125
+
126
+ it('expandableSectionProps.isExpanded overrides isDefaultExpanded', () => {
127
+ render(<ToolResponse {...defaultProps} isDefaultExpanded={false} expandableSectionProps={{ isExpanded: true }} />);
128
+
129
+ expect(screen.getByRole('button', { name: defaultProps.toggleContent })).toHaveAttribute('aria-expanded', 'true');
130
+ expect(screen.getByText(defaultProps.cardTitle)).toBeVisible();
131
+ expect(screen.getByText(defaultProps.cardBody)).toBeVisible();
132
+ });
133
+
134
+ it('expandableSectionProps.onToggle overrides internal onToggle behavior', async () => {
135
+ const user = userEvent.setup();
136
+ const customOnToggle = jest.fn();
137
+
138
+ render(
139
+ <ToolResponse {...defaultProps} isDefaultExpanded={false} expandableSectionProps={{ onToggle: customOnToggle }} />
140
+ );
141
+
142
+ const toggleButton = screen.getByRole('button', { name: defaultProps.toggleContent });
143
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
144
+
145
+ await user.click(toggleButton);
146
+
147
+ expect(customOnToggle).toHaveBeenCalledTimes(1);
148
+ expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
149
+ expect(screen.getByText(defaultProps.cardTitle)).not.toBeVisible();
150
+ expect(screen.getByText(defaultProps.cardBody)).not.toBeVisible();
151
+ });
152
+
153
+ it('should render toggleContent as markdown when isToggleContentMarkdown is true', () => {
154
+ const toggleContent = '**Bold toggle**';
155
+ const { container } = render(
156
+ <ToolResponse {...defaultProps} toggleContent={toggleContent} isToggleContentMarkdown />
157
+ );
158
+ expect(container.querySelector('strong')).toBeTruthy();
159
+ expect(screen.getByText('Bold toggle')).toBeTruthy();
160
+ });
161
+
162
+ it('should not render toggleContent as markdown when isToggleContentMarkdown is false', () => {
163
+ const toggleContent = '**Bold toggle**';
164
+ render(<ToolResponse {...defaultProps} toggleContent={toggleContent} />);
165
+ expect(screen.getByText('**Bold toggle**')).toBeTruthy();
166
+ });
167
+
168
+ it('should render subheading as markdown when isSubheadingMarkdown is true', () => {
169
+ const subheading = '**Bold subheading**';
170
+ const { container } = render(<ToolResponse {...defaultProps} subheading={subheading} isSubheadingMarkdown />);
171
+ expect(container.querySelector('strong')).toBeTruthy();
172
+ expect(screen.getByText('Bold subheading')).toBeTruthy();
173
+ });
174
+
175
+ it('should not render subheading as markdown when isSubheadingMarkdown is false', () => {
176
+ const subheading = '**Bold subheading**';
177
+ render(<ToolResponse {...defaultProps} subheading={subheading} />);
178
+ expect(screen.getByText('**Bold subheading**')).toBeTruthy();
179
+ });
180
+
181
+ it('should render body as markdown when isBodyMarkdown is true', () => {
182
+ const body = '**Bold body**';
183
+ const { container } = render(<ToolResponse {...defaultProps} body={body} isBodyMarkdown />);
184
+ expect(container.querySelector('strong')).toBeTruthy();
185
+ expect(screen.getByText('Bold body')).toBeTruthy();
186
+ });
187
+
188
+ it('should not render body as markdown when isBodyMarkdown is false', () => {
189
+ const body = '**Bold body**';
190
+ render(<ToolResponse {...defaultProps} body={body} />);
191
+ expect(screen.getByText('**Bold body**')).toBeTruthy();
192
+ });
193
+
194
+ it('should render cardTitle as markdown when isCardTitleMarkdown is true', () => {
195
+ const cardTitle = '**Bold card title**';
196
+ const { container } = render(<ToolResponse {...defaultProps} cardTitle={cardTitle} isCardTitleMarkdown />);
197
+ expect(container.querySelector('strong')).toBeTruthy();
198
+ expect(screen.getByText('Bold card title')).toBeTruthy();
199
+ });
200
+
201
+ it('should not render cardTitle as markdown when isCardTitleMarkdown is false', () => {
202
+ const cardTitle = '**Bold card title**';
203
+ render(<ToolResponse {...defaultProps} cardTitle={cardTitle} />);
204
+ expect(screen.getByText('**Bold card title**')).toBeTruthy();
205
+ });
206
+
207
+ it('should render cardBody as markdown when isCardBodyMarkdown is true', () => {
208
+ const cardBody = '**Bold card body**';
209
+ const { container } = render(<ToolResponse {...defaultProps} cardBody={cardBody} isCardBodyMarkdown />);
210
+ expect(container.querySelector('strong')).toBeTruthy();
211
+ expect(screen.getByText('Bold card body')).toBeTruthy();
212
+ });
213
+
214
+ it('should not render cardBody as markdown when isCardBodyMarkdown is false', () => {
215
+ const cardBody = '**Bold card body**';
216
+ render(<ToolResponse {...defaultProps} cardBody={cardBody} />);
217
+ expect(screen.getByText('**Bold card body**')).toBeTruthy();
218
+ });
219
+
220
+ it('should pass markdownContentProps to MarkdownContent component', () => {
221
+ const body = '**Bold body**';
222
+ const { container } = render(
223
+ <ToolResponse {...defaultProps} body={body} isBodyMarkdown markdownContentProps={{ isPrimary: true }} />
224
+ );
225
+ expect(container.querySelector('.pf-m-primary')).toBeTruthy();
226
+ });
108
227
  });
@@ -14,10 +14,14 @@ import {
14
14
  ExpandableSectionProps
15
15
  } from '@patternfly/react-core';
16
16
  import { useState, type FunctionComponent } from 'react';
17
+ import MarkdownContent from '../MarkdownContent';
18
+ import type { MarkdownContentProps } from '../MarkdownContent';
17
19
 
18
20
  export interface ToolResponseProps {
19
21
  /** Toggle content shown for expandable section */
20
22
  toggleContent: React.ReactNode;
23
+ /** Flag indicating whether the expandable content is expanded by default. */
24
+ isDefaultExpanded?: boolean;
21
25
  /** Additional props passed to expandable section */
22
26
  expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
23
27
  /** Subheading rendered inside expandable section */
@@ -40,6 +44,20 @@ export interface ToolResponseProps {
40
44
  toolResponseCardDividerProps?: DividerProps;
41
45
  /** Additional props passed to tool response card title */
42
46
  toolResponseCardTitleProps?: CardTitleProps;
47
+ /** Whether to enable markdown rendering for toggleContent. When true and toggleContent is a string, it will be parsed as markdown. */
48
+ isToggleContentMarkdown?: boolean;
49
+ /** Whether to enable markdown rendering for subheading. When true, subheading will be parsed as markdown. */
50
+ isSubheadingMarkdown?: boolean;
51
+ /** Whether to enable markdown rendering for body. When true and body is a string, it will be parsed as markdown. */
52
+ isBodyMarkdown?: boolean;
53
+ /** Whether to enable markdown rendering for cardBody. When true and cardBody is a string, it will be parsed as markdown. */
54
+ isCardBodyMarkdown?: boolean;
55
+ /** Whether to enable markdown rendering for cardTitle. When true and cardTitle is a string, it will be parsed as markdown. */
56
+ isCardTitleMarkdown?: boolean;
57
+ /** Props passed to MarkdownContent component when markdown is enabled */
58
+ markdownContentProps?: Omit<MarkdownContentProps, 'content'>;
59
+ /** Whether to retain styles in the MarkdownContent component. Defaults to false. */
60
+ shouldRetainStyles?: boolean;
43
61
  }
44
62
 
45
63
  export const ToolResponse: FunctionComponent<ToolResponseProps> = ({
@@ -51,22 +69,79 @@ export const ToolResponse: FunctionComponent<ToolResponseProps> = ({
51
69
  cardTitle,
52
70
  cardBodyProps,
53
71
  toggleContent,
72
+ isDefaultExpanded = true,
54
73
  toolResponseCardBodyProps,
55
74
  toolResponseCardDividerProps,
56
75
  toolResponseCardProps,
57
- toolResponseCardTitleProps
76
+ toolResponseCardTitleProps,
77
+ isToggleContentMarkdown,
78
+ isSubheadingMarkdown,
79
+ isBodyMarkdown,
80
+ isCardBodyMarkdown,
81
+ isCardTitleMarkdown,
82
+ markdownContentProps,
83
+ shouldRetainStyles = false
58
84
  }: ToolResponseProps) => {
59
- const [isExpanded, setIsExpanded] = useState(true);
85
+ const [isExpanded, setIsExpanded] = useState(isDefaultExpanded);
60
86
 
61
87
  const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {
62
88
  setIsExpanded(isExpanded);
63
89
  };
64
90
 
91
+ const renderToggleContent = () => {
92
+ if (isToggleContentMarkdown && typeof toggleContent === 'string') {
93
+ return (
94
+ <MarkdownContent shouldRetainStyles={shouldRetainStyles} content={toggleContent} {...markdownContentProps} />
95
+ );
96
+ }
97
+ return toggleContent;
98
+ };
99
+
100
+ const renderSubheading = () => {
101
+ if (!subheading) {
102
+ return null;
103
+ }
104
+ if (isSubheadingMarkdown) {
105
+ return <MarkdownContent shouldRetainStyles={shouldRetainStyles} content={subheading} {...markdownContentProps} />;
106
+ }
107
+ return subheading;
108
+ };
109
+
110
+ const renderBody = () => {
111
+ if (!body) {
112
+ return null;
113
+ }
114
+ if (isBodyMarkdown && typeof body === 'string') {
115
+ return <MarkdownContent shouldRetainStyles={shouldRetainStyles} content={body} {...markdownContentProps} />;
116
+ }
117
+ return body;
118
+ };
119
+
120
+ const renderCardTitle = () => {
121
+ if (!cardTitle) {
122
+ return null;
123
+ }
124
+ if (isCardTitleMarkdown && typeof cardTitle === 'string') {
125
+ return <MarkdownContent shouldRetainStyles={shouldRetainStyles} content={cardTitle} {...markdownContentProps} />;
126
+ }
127
+ return cardTitle;
128
+ };
129
+
130
+ const renderCardBody = () => {
131
+ if (!cardBody) {
132
+ return null;
133
+ }
134
+ if (isCardBodyMarkdown && typeof cardBody === 'string') {
135
+ return <MarkdownContent shouldRetainStyles={shouldRetainStyles} content={cardBody} {...markdownContentProps} />;
136
+ }
137
+ return cardBody;
138
+ };
139
+
65
140
  return (
66
141
  <Card isCompact className="pf-chatbot__tool-response" {...cardProps}>
67
142
  <CardBody {...cardBodyProps}>
68
143
  <ExpandableSection
69
- toggleContent={toggleContent}
144
+ toggleContent={renderToggleContent()}
70
145
  onToggle={onToggle}
71
146
  isExpanded={isExpanded}
72
147
  isIndented
@@ -76,15 +151,15 @@ export const ToolResponse: FunctionComponent<ToolResponseProps> = ({
76
151
  <div className="pf-chatbot__tool-response-section">
77
152
  {subheading && (
78
153
  <div className="pf-chatbot__tool-response-subheading">
79
- <span>{subheading}</span>
154
+ <span>{renderSubheading()}</span>
80
155
  </div>
81
156
  )}
82
- {body && <div className="pf-chatbot__tool-response-body">{body}</div>}
157
+ {body && <div className="pf-chatbot__tool-response-body">{renderBody()}</div>}
83
158
  {(cardTitle || cardBody) && (
84
159
  <Card isCompact className="pf-chatbot__tool-response-card" {...toolResponseCardProps}>
85
- {cardTitle && <CardTitle {...toolResponseCardTitleProps}>{cardTitle}</CardTitle>}
160
+ {cardTitle && <CardTitle {...toolResponseCardTitleProps}>{renderCardTitle()}</CardTitle>}
86
161
  {cardTitle && cardBody && <Divider {...toolResponseCardDividerProps} />}
87
- {cardBody && <CardBody {...toolResponseCardBodyProps}>{cardBody}</CardBody>}
162
+ {cardBody && <CardBody {...toolResponseCardBodyProps}>{renderCardBody()}</CardBody>}
88
163
  </Card>
89
164
  )}
90
165
  </div>
package/src/index.ts CHANGED
@@ -63,6 +63,9 @@ export * from './ImagePreview';
63
63
  export { default as LoadingMessage } from './LoadingMessage';
64
64
  export * from './LoadingMessage';
65
65
 
66
+ export { default as MarkdownContent } from './MarkdownContent';
67
+ export * from './MarkdownContent';
68
+
66
69
  export { default as Message } from './Message';
67
70
  export * from './Message';
68
71
 
package/src/main.scss CHANGED
@@ -20,6 +20,7 @@
20
20
  @import './Message/Message';
21
21
  @import './Message/CodeBlockMessage/CodeBlockMessage';
22
22
  @import './Message/ImageMessage/ImageMessage';
23
+ @import './Message/LinkMessage/LinkMessage';
23
24
  @import './Message/TextMessage/TextMessage';
24
25
  @import './Message/ListMessage/ListMessage';
25
26
  @import './Message/TableMessage/TableMessage';