@patternfly/chatbot 6.5.0-prerelease.20 → 6.5.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.
- package/dist/cjs/DeepThinking/DeepThinking.d.ts +2 -0
- package/dist/cjs/DeepThinking/DeepThinking.js +2 -2
- package/dist/cjs/DeepThinking/DeepThinking.test.js +41 -0
- package/dist/cjs/Message/Message.d.ts +15 -3
- package/dist/cjs/Message/Message.js +1 -1
- package/dist/cjs/Message/Message.test.js +125 -2
- package/dist/cjs/ToolCall/ToolCall.d.ts +2 -0
- package/dist/cjs/ToolCall/ToolCall.js +7 -2
- package/dist/cjs/ToolCall/ToolCall.test.js +26 -0
- package/dist/cjs/ToolResponse/ToolResponse.d.ts +2 -0
- package/dist/cjs/ToolResponse/ToolResponse.js +2 -2
- package/dist/cjs/ToolResponse/ToolResponse.test.js +40 -0
- package/dist/css/main.css +10 -0
- package/dist/css/main.css.map +1 -1
- package/dist/esm/DeepThinking/DeepThinking.d.ts +2 -0
- package/dist/esm/DeepThinking/DeepThinking.js +2 -2
- package/dist/esm/DeepThinking/DeepThinking.test.js +41 -0
- package/dist/esm/Message/Message.d.ts +15 -3
- package/dist/esm/Message/Message.js +1 -1
- package/dist/esm/Message/Message.test.js +125 -2
- package/dist/esm/ToolCall/ToolCall.d.ts +2 -0
- package/dist/esm/ToolCall/ToolCall.js +7 -2
- package/dist/esm/ToolCall/ToolCall.test.js +26 -0
- package/dist/esm/ToolResponse/ToolResponse.d.ts +2 -0
- package/dist/esm/ToolResponse/ToolResponse.js +2 -2
- package/dist/esm/ToolResponse/ToolResponse.test.js +40 -0
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDeepThinking.tsx +25 -11
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMultipleActionGroups.tsx +61 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolCall.tsx +14 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolResponse.tsx +222 -105
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +18 -0
- package/src/DeepThinking/DeepThinking.test.tsx +61 -0
- package/src/DeepThinking/DeepThinking.tsx +4 -1
- package/src/Message/Message.test.tsx +198 -2
- package/src/Message/Message.tsx +35 -6
- package/src/ResponseActions/ResponseActions.scss +11 -0
- package/src/ToolCall/ToolCall.test.tsx +51 -0
- package/src/ToolCall/ToolCall.tsx +12 -1
- package/src/ToolResponse/ToolResponse.test.tsx +44 -0
- package/src/ToolResponse/ToolResponse.tsx +4 -1
package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolResponse.tsx
CHANGED
|
@@ -23,113 +23,230 @@ export const MessageWithToolResponseExample: FunctionComponent = () => {
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<Flex gap={{ default: 'gapXs' }}>
|
|
41
|
-
<FlexItem>
|
|
42
|
-
<WrenchIcon style={{ color: 'var(--pf-t--global--icon--color--brand--default' }} />
|
|
43
|
-
</FlexItem>
|
|
44
|
-
<FlexItem>toolName</FlexItem>
|
|
45
|
-
</Flex>
|
|
46
|
-
</FlexItem>
|
|
47
|
-
<FlexItem>
|
|
48
|
-
<Flex gap={{ default: 'gapSm' }} style={{ fontSize: '12px', fontWeight: '400' }}>
|
|
49
|
-
<FlexItem>Execution time:</FlexItem>
|
|
50
|
-
<FlexItem>0.12 seconds</FlexItem>
|
|
51
|
-
</Flex>
|
|
52
|
-
</FlexItem>
|
|
53
|
-
</Flex>
|
|
54
|
-
</FlexItem>
|
|
55
|
-
<FlexItem>
|
|
56
|
-
<Button
|
|
57
|
-
variant="plain"
|
|
58
|
-
aria-label="Copy tool response to clipboard"
|
|
59
|
-
icon={<CopyIcon style={{ color: 'var(--pf-t--global--icon--color--subtle)' }} />}
|
|
60
|
-
></Button>
|
|
61
|
-
</FlexItem>
|
|
62
|
-
</Flex>
|
|
63
|
-
),
|
|
64
|
-
cardBody: (
|
|
65
|
-
<>
|
|
66
|
-
<DescriptionList
|
|
67
|
-
style={{ '--pf-v6-c-description-list--RowGap': 'var(--pf-t--global--spacer--md)' } as any}
|
|
68
|
-
aria-label="Tool response"
|
|
26
|
+
<>
|
|
27
|
+
<Message
|
|
28
|
+
name="Bot"
|
|
29
|
+
role="bot"
|
|
30
|
+
avatar={patternflyAvatar}
|
|
31
|
+
content="This message has a body description that's within the recommended limit of 2 lines:"
|
|
32
|
+
toolResponse={{
|
|
33
|
+
toggleContent: 'Tool response: toolName',
|
|
34
|
+
subheading: 'Thought for 3 seconds',
|
|
35
|
+
body: "Here's the summary for your toolName response:",
|
|
36
|
+
cardTitle: (
|
|
37
|
+
<Flex
|
|
38
|
+
alignItems={{ default: 'alignItemsCenter' }}
|
|
39
|
+
justifyContent={{ default: 'justifyContentSpaceBetween' }}
|
|
69
40
|
>
|
|
70
|
-
<
|
|
71
|
-
|
|
41
|
+
<FlexItem>
|
|
42
|
+
<Flex direction={{ default: 'column' }} gap={{ default: 'gapXs' }}>
|
|
43
|
+
<FlexItem grow={{ default: 'grow' }}>
|
|
44
|
+
<Flex gap={{ default: 'gapXs' }}>
|
|
45
|
+
<FlexItem>
|
|
46
|
+
<WrenchIcon style={{ color: 'var(--pf-t--global--icon--color--brand--default' }} />
|
|
47
|
+
</FlexItem>
|
|
48
|
+
<FlexItem>toolName</FlexItem>
|
|
49
|
+
</Flex>
|
|
50
|
+
</FlexItem>
|
|
51
|
+
<FlexItem>
|
|
52
|
+
<Flex gap={{ default: 'gapSm' }} style={{ fontSize: '12px', fontWeight: '400' }}>
|
|
53
|
+
<FlexItem>Execution time:</FlexItem>
|
|
54
|
+
<FlexItem>0.12 seconds</FlexItem>
|
|
55
|
+
</Flex>
|
|
56
|
+
</FlexItem>
|
|
57
|
+
</Flex>
|
|
58
|
+
</FlexItem>
|
|
59
|
+
<FlexItem>
|
|
60
|
+
<Button
|
|
61
|
+
variant="plain"
|
|
62
|
+
aria-label="Copy tool response to clipboard"
|
|
63
|
+
icon={<CopyIcon style={{ color: 'var(--pf-t--global--icon--color--subtle)' }} />}
|
|
64
|
+
></Button>
|
|
65
|
+
</FlexItem>
|
|
66
|
+
</Flex>
|
|
67
|
+
),
|
|
68
|
+
cardBody: (
|
|
69
|
+
<>
|
|
70
|
+
<DescriptionList
|
|
71
|
+
style={{ '--pf-v6-c-description-list--RowGap': 'var(--pf-t--global--spacer--md)' } as any}
|
|
72
|
+
aria-label="Tool response"
|
|
72
73
|
>
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
74
|
+
<DescriptionListGroup
|
|
75
|
+
style={{ '--pf-v6-c-description-list__group--RowGap': 'var(--pf-t--global--spacer--xs)' } as any}
|
|
76
|
+
>
|
|
77
|
+
<DescriptionListTerm>Parameters</DescriptionListTerm>
|
|
78
|
+
<DescriptionListDescription>
|
|
79
|
+
<Flex direction={{ default: 'column' }}>
|
|
80
|
+
<FlexItem>Optional description text for parameters.</FlexItem>
|
|
81
|
+
<FlexItem>
|
|
82
|
+
<Flex gap={{ default: 'gapSm' }}>
|
|
83
|
+
<FlexItem>
|
|
84
|
+
<Label variant="outline" color="blue">
|
|
85
|
+
type
|
|
86
|
+
</Label>
|
|
87
|
+
</FlexItem>
|
|
88
|
+
<FlexItem>
|
|
89
|
+
<Label variant="outline" color="blue">
|
|
90
|
+
properties
|
|
91
|
+
</Label>
|
|
92
|
+
</FlexItem>
|
|
93
|
+
<FlexItem>
|
|
94
|
+
<Label variant="outline" color="blue">
|
|
95
|
+
label
|
|
96
|
+
</Label>
|
|
97
|
+
</FlexItem>
|
|
98
|
+
<FlexItem>
|
|
99
|
+
<Label variant="outline" color="blue">
|
|
100
|
+
label
|
|
101
|
+
</Label>
|
|
102
|
+
</FlexItem>
|
|
103
|
+
</Flex>
|
|
104
|
+
</FlexItem>
|
|
105
|
+
</Flex>
|
|
106
|
+
</DescriptionListDescription>
|
|
107
|
+
</DescriptionListGroup>
|
|
108
|
+
<DescriptionListGroup
|
|
109
|
+
style={{ '--pf-v6-c-description-list__group--RowGap': 'var(--pf-t--global--spacer--xs)' } as any}
|
|
110
|
+
>
|
|
111
|
+
<DescriptionListTerm>Response</DescriptionListTerm>
|
|
112
|
+
<DescriptionListDescription>
|
|
113
|
+
<ExpandableSection
|
|
114
|
+
variant={ExpandableSectionVariant.truncate}
|
|
115
|
+
toggleTextExpanded="show less of response"
|
|
116
|
+
toggleTextCollapsed="show more of response"
|
|
117
|
+
onToggle={onToggle}
|
|
118
|
+
isExpanded={isExpanded}
|
|
119
|
+
style={
|
|
120
|
+
{
|
|
121
|
+
'--pf-v6-c-expandable-section__content--Opacity': '1',
|
|
122
|
+
'--pf-v6-c-expandable-section__content--PaddingInlineStart': 0,
|
|
123
|
+
'--pf-v6-c-expandable-section__content--TranslateY': 0,
|
|
124
|
+
'--pf-v6-c-expandable-section--m-expand-top__content--TranslateY': 0
|
|
125
|
+
} as any
|
|
126
|
+
}
|
|
127
|
+
>
|
|
128
|
+
Descriptive text about the tool response, including completion status, details on the data that
|
|
129
|
+
was processed, or anything else relevant to the use case.
|
|
130
|
+
</ExpandableSection>
|
|
131
|
+
</DescriptionListDescription>
|
|
132
|
+
</DescriptionListGroup>
|
|
133
|
+
</DescriptionList>
|
|
134
|
+
</>
|
|
135
|
+
)
|
|
136
|
+
}}
|
|
137
|
+
/>
|
|
138
|
+
<Message
|
|
139
|
+
name="Bot"
|
|
140
|
+
role="bot"
|
|
141
|
+
avatar={patternflyAvatar}
|
|
142
|
+
content="This message has a tool response that is collapsed by default:"
|
|
143
|
+
toolResponse={{
|
|
144
|
+
isDefaultExpanded: false,
|
|
145
|
+
toggleContent: 'Tool response: toolName',
|
|
146
|
+
subheading: 'Thought for 3 seconds',
|
|
147
|
+
body: "Here's the summary for your toolName response:",
|
|
148
|
+
cardTitle: (
|
|
149
|
+
<Flex
|
|
150
|
+
alignItems={{ default: 'alignItemsCenter' }}
|
|
151
|
+
justifyContent={{ default: 'justifyContentSpaceBetween' }}
|
|
152
|
+
>
|
|
153
|
+
<FlexItem>
|
|
154
|
+
<Flex direction={{ default: 'column' }} gap={{ default: 'gapXs' }}>
|
|
155
|
+
<FlexItem grow={{ default: 'grow' }}>
|
|
156
|
+
<Flex gap={{ default: 'gapXs' }}>
|
|
157
|
+
<FlexItem>
|
|
158
|
+
<WrenchIcon style={{ color: 'var(--pf-t--global--icon--color--brand--default' }} />
|
|
159
|
+
</FlexItem>
|
|
160
|
+
<FlexItem>toolName</FlexItem>
|
|
161
|
+
</Flex>
|
|
162
|
+
</FlexItem>
|
|
163
|
+
<FlexItem>
|
|
164
|
+
<Flex gap={{ default: 'gapSm' }} style={{ fontSize: '12px', fontWeight: '400' }}>
|
|
165
|
+
<FlexItem>Execution time:</FlexItem>
|
|
166
|
+
<FlexItem>0.12 seconds</FlexItem>
|
|
167
|
+
</Flex>
|
|
168
|
+
</FlexItem>
|
|
169
|
+
</Flex>
|
|
170
|
+
</FlexItem>
|
|
171
|
+
<FlexItem>
|
|
172
|
+
<Button
|
|
173
|
+
variant="plain"
|
|
174
|
+
aria-label="Copy tool response to clipboard"
|
|
175
|
+
icon={<CopyIcon style={{ color: 'var(--pf-t--global--icon--color--subtle)' }} />}
|
|
176
|
+
></Button>
|
|
177
|
+
</FlexItem>
|
|
178
|
+
</Flex>
|
|
179
|
+
),
|
|
180
|
+
cardBody: (
|
|
181
|
+
<>
|
|
182
|
+
<DescriptionList
|
|
183
|
+
style={{ '--pf-v6-c-description-list--RowGap': 'var(--pf-t--global--spacer--md)' } as any}
|
|
184
|
+
aria-label="Tool response"
|
|
106
185
|
>
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
186
|
+
<DescriptionListGroup
|
|
187
|
+
style={{ '--pf-v6-c-description-list__group--RowGap': 'var(--pf-t--global--spacer--xs)' } as any}
|
|
188
|
+
>
|
|
189
|
+
<DescriptionListTerm>Parameters</DescriptionListTerm>
|
|
190
|
+
<DescriptionListDescription>
|
|
191
|
+
<Flex direction={{ default: 'column' }}>
|
|
192
|
+
<FlexItem>Optional description text for parameters.</FlexItem>
|
|
193
|
+
<FlexItem>
|
|
194
|
+
<Flex gap={{ default: 'gapSm' }}>
|
|
195
|
+
<FlexItem>
|
|
196
|
+
<Label variant="outline" color="blue">
|
|
197
|
+
type
|
|
198
|
+
</Label>
|
|
199
|
+
</FlexItem>
|
|
200
|
+
<FlexItem>
|
|
201
|
+
<Label variant="outline" color="blue">
|
|
202
|
+
properties
|
|
203
|
+
</Label>
|
|
204
|
+
</FlexItem>
|
|
205
|
+
<FlexItem>
|
|
206
|
+
<Label variant="outline" color="blue">
|
|
207
|
+
label
|
|
208
|
+
</Label>
|
|
209
|
+
</FlexItem>
|
|
210
|
+
<FlexItem>
|
|
211
|
+
<Label variant="outline" color="blue">
|
|
212
|
+
label
|
|
213
|
+
</Label>
|
|
214
|
+
</FlexItem>
|
|
215
|
+
</Flex>
|
|
216
|
+
</FlexItem>
|
|
217
|
+
</Flex>
|
|
218
|
+
</DescriptionListDescription>
|
|
219
|
+
</DescriptionListGroup>
|
|
220
|
+
<DescriptionListGroup
|
|
221
|
+
style={{ '--pf-v6-c-description-list__group--RowGap': 'var(--pf-t--global--spacer--xs)' } as any}
|
|
222
|
+
>
|
|
223
|
+
<DescriptionListTerm>Response</DescriptionListTerm>
|
|
224
|
+
<DescriptionListDescription>
|
|
225
|
+
<ExpandableSection
|
|
226
|
+
variant={ExpandableSectionVariant.truncate}
|
|
227
|
+
toggleTextExpanded="show less of response"
|
|
228
|
+
toggleTextCollapsed="show more of response"
|
|
229
|
+
onToggle={onToggle}
|
|
230
|
+
isExpanded={isExpanded}
|
|
231
|
+
style={
|
|
232
|
+
{
|
|
233
|
+
'--pf-v6-c-expandable-section__content--Opacity': '1',
|
|
234
|
+
'--pf-v6-c-expandable-section__content--PaddingInlineStart': 0,
|
|
235
|
+
'--pf-v6-c-expandable-section__content--TranslateY': 0,
|
|
236
|
+
'--pf-v6-c-expandable-section--m-expand-top__content--TranslateY': 0
|
|
237
|
+
} as any
|
|
238
|
+
}
|
|
239
|
+
>
|
|
240
|
+
Descriptive text about the tool response, including completion status, details on the data that
|
|
241
|
+
was processed, or anything else relevant to the use case.
|
|
242
|
+
</ExpandableSection>
|
|
243
|
+
</DescriptionListDescription>
|
|
244
|
+
</DescriptionListGroup>
|
|
245
|
+
</DescriptionList>
|
|
246
|
+
</>
|
|
247
|
+
)
|
|
248
|
+
}}
|
|
249
|
+
/>
|
|
250
|
+
</>
|
|
134
251
|
);
|
|
135
252
|
};
|
|
@@ -122,6 +122,24 @@ When `persistActionSelection` is `true`:
|
|
|
122
122
|
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
+
### Multiple messsage action groups
|
|
126
|
+
|
|
127
|
+
To maintain finer control over message action selection behavior, you can create groups of actions by passing an array of objects to the `actions` prop. This allows you to separate actions into conceptually or functionally different groups and implement different behavior for each group as needed. For example, you could separate feedback actions (thumbs up/down) form utility actions (copy and download), and have different selection behaviors for each group.
|
|
128
|
+
|
|
129
|
+
To provide flexibility for your use case, there are 2 approaches you can take to pass an array of objects to `actions`:
|
|
130
|
+
|
|
131
|
+
1. Pass an array of objects, where each object contains:
|
|
132
|
+
|
|
133
|
+
- `actions`: An `action` object containing the actions for that group (the same format as a single `action` object)
|
|
134
|
+
|
|
135
|
+
- `persistActionSelection` (optional): A boolean to control whether selections persists for this specific group
|
|
136
|
+
|
|
137
|
+
2. Pass an array of `action` objects (the same format as a single `action` object) and (optionally) a value for the `persistActionSelection` property that will apply to all groups.
|
|
138
|
+
|
|
139
|
+
```js file="./MessageWithMultipleActionGroups.tsx"
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
|
|
125
143
|
### Custom message actions
|
|
126
144
|
|
|
127
145
|
Beyond the standard message actions (good response, bad response, copy, share, or listen), you can add custom actions to a bot message by passing an `actions` object to the `<Message>` component. This object can contain the following customizations:
|
|
@@ -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 DeepThinking from './DeepThinking';
|
|
4
5
|
|
|
@@ -58,4 +59,64 @@ describe('DeepThinking', () => {
|
|
|
58
59
|
const subheadingContainer = container.querySelector('.pf-chatbot__tool-response-subheading');
|
|
59
60
|
expect(subheadingContainer).toBeFalsy();
|
|
60
61
|
});
|
|
62
|
+
|
|
63
|
+
it('should pass through cardBodyProps', () => {
|
|
64
|
+
render(
|
|
65
|
+
<DeepThinking {...defaultProps} body="Thinking content" cardBodyProps={{ className: 'custom-card-body-class' }} />
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const cardBody = screen.getByText('Thinking content').closest('.pf-v6-c-card__body');
|
|
69
|
+
expect(cardBody).toHaveClass('custom-card-body-class');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('Renders expanded by default', () => {
|
|
73
|
+
render(<DeepThinking {...defaultProps} body="Thinking content" />);
|
|
74
|
+
|
|
75
|
+
expect(screen.getByRole('button', { name: defaultProps.toggleContent })).toHaveAttribute('aria-expanded', 'true');
|
|
76
|
+
expect(screen.getByText('Thinking content')).toBeVisible();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('Renders collapsed when isDefaultExpanded is false', () => {
|
|
80
|
+
render(<DeepThinking isDefaultExpanded={false} {...defaultProps} body="Thinking content" />);
|
|
81
|
+
|
|
82
|
+
expect(screen.getByRole('button', { name: defaultProps.toggleContent })).toHaveAttribute('aria-expanded', 'false');
|
|
83
|
+
expect(screen.getByText('Thinking content')).not.toBeVisible();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('expandableSectionProps.isExpanded overrides isDefaultExpanded', () => {
|
|
87
|
+
render(
|
|
88
|
+
<DeepThinking
|
|
89
|
+
{...defaultProps}
|
|
90
|
+
isDefaultExpanded={false}
|
|
91
|
+
body="Thinking content"
|
|
92
|
+
expandableSectionProps={{ isExpanded: true }}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(screen.getByRole('button', { name: defaultProps.toggleContent })).toHaveAttribute('aria-expanded', 'true');
|
|
97
|
+
expect(screen.getByText('Thinking content')).toBeVisible();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('expandableSectionProps.onToggle overrides internal onToggle behavior', async () => {
|
|
101
|
+
const user = userEvent.setup();
|
|
102
|
+
const customOnToggle = jest.fn();
|
|
103
|
+
|
|
104
|
+
render(
|
|
105
|
+
<DeepThinking
|
|
106
|
+
{...defaultProps}
|
|
107
|
+
isDefaultExpanded={false}
|
|
108
|
+
body="Thinking content"
|
|
109
|
+
expandableSectionProps={{ onToggle: customOnToggle }}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const toggleButton = screen.getByRole('button', { name: defaultProps.toggleContent });
|
|
114
|
+
expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
|
|
115
|
+
|
|
116
|
+
await user.click(toggleButton);
|
|
117
|
+
|
|
118
|
+
expect(customOnToggle).toHaveBeenCalled();
|
|
119
|
+
expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
|
|
120
|
+
expect(screen.getByText('Thinking content')).not.toBeVisible();
|
|
121
|
+
});
|
|
61
122
|
});
|
|
@@ -14,6 +14,8 @@ import { useState, type FunctionComponent } from 'react';
|
|
|
14
14
|
export interface DeepThinkingProps {
|
|
15
15
|
/** Toggle content shown for expandable section */
|
|
16
16
|
toggleContent: React.ReactNode;
|
|
17
|
+
/** Flag indicating whether the expandable content is expanded by default. */
|
|
18
|
+
isDefaultExpanded?: boolean;
|
|
17
19
|
/** Additional props passed to expandable section */
|
|
18
20
|
expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
|
|
19
21
|
/** Subheading rendered inside expandable section */
|
|
@@ -32,9 +34,10 @@ export const DeepThinking: FunctionComponent<DeepThinkingProps> = ({
|
|
|
32
34
|
expandableSectionProps,
|
|
33
35
|
subheading,
|
|
34
36
|
toggleContent,
|
|
37
|
+
isDefaultExpanded = true,
|
|
35
38
|
cardBodyProps
|
|
36
39
|
}: DeepThinkingProps) => {
|
|
37
|
-
const [isExpanded, setIsExpanded] = useState(
|
|
40
|
+
const [isExpanded, setIsExpanded] = useState(isDefaultExpanded);
|
|
38
41
|
|
|
39
42
|
const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {
|
|
40
43
|
setIsExpanded(isExpanded);
|