@patternfly/chatbot 6.4.0-prerelease.22 → 6.4.0-prerelease.24

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 (41) hide show
  1. package/dist/cjs/SourcesCard/SourcesCard.js +6 -30
  2. package/dist/cjs/SourcesCard/SourcesCard.test.js +2 -211
  3. package/dist/cjs/SourcesCardBase/SourcesCardBase.d.ts +57 -0
  4. package/dist/cjs/SourcesCardBase/SourcesCardBase.js +49 -0
  5. package/dist/cjs/SourcesCardBase/SourcesCardBase.test.d.ts +1 -0
  6. package/dist/cjs/SourcesCardBase/SourcesCardBase.test.js +171 -0
  7. package/dist/cjs/SourcesCardBase/index.d.ts +2 -0
  8. package/dist/cjs/SourcesCardBase/index.js +23 -0
  9. package/dist/cjs/ToolResponse/ToolResponse.d.ts +2 -2
  10. package/dist/cjs/ToolResponse/ToolResponse.js +1 -1
  11. package/dist/cjs/ToolResponse/ToolResponse.test.js +24 -0
  12. package/dist/cjs/index.d.ts +2 -0
  13. package/dist/cjs/index.js +4 -1
  14. package/dist/css/main.css +4 -7
  15. package/dist/css/main.css.map +1 -1
  16. package/dist/dynamic/SourcesCardBase/package.json +1 -0
  17. package/dist/esm/SourcesCard/SourcesCard.js +4 -31
  18. package/dist/esm/SourcesCard/SourcesCard.test.js +3 -212
  19. package/dist/esm/SourcesCardBase/SourcesCardBase.d.ts +57 -0
  20. package/dist/esm/SourcesCardBase/SourcesCardBase.js +47 -0
  21. package/dist/esm/SourcesCardBase/SourcesCardBase.test.d.ts +1 -0
  22. package/dist/esm/SourcesCardBase/SourcesCardBase.test.js +166 -0
  23. package/dist/esm/SourcesCardBase/index.d.ts +2 -0
  24. package/dist/esm/SourcesCardBase/index.js +2 -0
  25. package/dist/esm/ToolResponse/ToolResponse.d.ts +2 -2
  26. package/dist/esm/ToolResponse/ToolResponse.js +1 -1
  27. package/dist/esm/ToolResponse/ToolResponse.test.js +24 -0
  28. package/dist/esm/index.d.ts +2 -0
  29. package/dist/esm/index.js +2 -0
  30. package/dist/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +2 -2
  32. package/src/SourcesCard/SourcesCard.scss +4 -1
  33. package/src/SourcesCard/SourcesCard.test.tsx +2 -327
  34. package/src/SourcesCard/SourcesCard.tsx +8 -171
  35. package/src/SourcesCardBase/SourcesCardBase.test.tsx +236 -0
  36. package/src/SourcesCardBase/SourcesCardBase.tsx +242 -0
  37. package/src/SourcesCardBase/index.ts +3 -0
  38. package/src/ToolResponse/ToolResponse.test.tsx +30 -0
  39. package/src/ToolResponse/ToolResponse.tsx +9 -7
  40. package/src/index.ts +6 -3
  41. package/src/main.scss +0 -5
@@ -1,42 +1,15 @@
1
1
  import { render, screen } from '@testing-library/react';
2
- import userEvent from '@testing-library/user-event';
3
2
  import '@testing-library/jest-dom';
4
3
  import SourcesCard from './SourcesCard';
5
4
 
6
5
  describe('SourcesCard', () => {
7
- it('should render card correctly if one source with only a link is passed in', () => {
8
- render(<SourcesCard sources={[{ link: '' }]} />);
9
- expect(screen.getByText('1 source')).toBeTruthy();
10
- expect(screen.getByText('Source 1')).toBeTruthy();
11
- // no buttons or navigation when there is only 1 source
12
- expect(screen.queryByRole('button')).toBeFalsy();
13
- expect(screen.queryByText('1/1')).toBeFalsy();
14
- });
15
-
16
- it('should render card correctly if one source with a title is passed in', () => {
6
+ it('should render sources correctly if one source is passed in', () => {
17
7
  render(<SourcesCard sources={[{ title: 'How to make an apple pie', link: '' }]} />);
18
8
  expect(screen.getByText('1 source')).toBeTruthy();
19
9
  expect(screen.getByText('How to make an apple pie')).toBeTruthy();
20
10
  });
21
11
 
22
- it('should render card correctly if one source with a body is passed in', () => {
23
- render(<SourcesCard sources={[{ link: '', body: 'To make an apple pie, you must first...' }]} />);
24
- expect(screen.getByText('1 source')).toBeTruthy();
25
- expect(screen.getByText('To make an apple pie, you must first...')).toBeTruthy();
26
- });
27
-
28
- it('should render card correctly if one source with a title and body is passed in', () => {
29
- render(
30
- <SourcesCard
31
- sources={[{ title: 'How to make an apple pie', link: '', body: 'To make an apple pie, you must first...' }]}
32
- />
33
- );
34
- expect(screen.getByText('1 source')).toBeTruthy();
35
- expect(screen.getByText('How to make an apple pie')).toBeTruthy();
36
- expect(screen.getByText('To make an apple pie, you must first...')).toBeTruthy();
37
- });
38
-
39
- it('should render multiple cards correctly', () => {
12
+ it('should render sources correctly when there is more than one', () => {
40
13
  render(
41
14
  <SourcesCard
42
15
  sources={[
@@ -51,302 +24,4 @@ describe('SourcesCard', () => {
51
24
  screen.getByRole('button', { name: /Go to previous page/i });
52
25
  screen.getByRole('button', { name: /Go to next page/i });
53
26
  });
54
-
55
- it('should navigate between cards correctly', async () => {
56
- render(
57
- <SourcesCard
58
- sources={[
59
- { title: 'How to make an apple pie', link: '' },
60
- { title: 'How to make cookies', link: '' }
61
- ]}
62
- />
63
- );
64
- expect(screen.getByText('How to make an apple pie')).toBeTruthy();
65
- expect(screen.getByText('1/2')).toBeTruthy();
66
- expect(screen.getByRole('button', { name: /Go to previous page/i })).toBeDisabled();
67
- await userEvent.click(screen.getByRole('button', { name: /Go to next page/i }));
68
- expect(screen.queryByText('How to make an apple pie')).toBeFalsy();
69
- expect(screen.getByText('How to make cookies')).toBeTruthy();
70
- expect(screen.getByText('2/2')).toBeTruthy();
71
- expect(screen.getByRole('button', { name: /Go to previous page/i })).toBeEnabled();
72
- expect(screen.getByRole('button', { name: /Go to next page/i })).toBeDisabled();
73
- });
74
-
75
- it('should apply className appropriately', () => {
76
- render(
77
- <SourcesCard
78
- sources={[
79
- { title: 'How to make an apple pie', link: '' },
80
- { title: 'How to make cookies', link: '' }
81
- ]}
82
- className="test"
83
- />
84
- );
85
- const element = screen.getByRole('navigation');
86
- expect(element).toHaveClass('test');
87
- });
88
-
89
- it('should disable pagination appropriately', () => {
90
- render(
91
- <SourcesCard
92
- sources={[
93
- { title: 'How to make an apple pie', link: '' },
94
- { title: 'How to make cookies', link: '' }
95
- ]}
96
- isDisabled
97
- />
98
- );
99
- expect(screen.getByRole('button', { name: /Go to previous page/i })).toBeDisabled();
100
- expect(screen.getByRole('button', { name: /Go to next page/i })).toBeDisabled();
101
- });
102
-
103
- it('should render navigation aria label appropriately', () => {
104
- render(
105
- <SourcesCard
106
- sources={[
107
- { title: 'How to make an apple pie', link: '' },
108
- { title: 'How to make cookies', link: '' }
109
- ]}
110
- />
111
- );
112
- expect(screen.getByRole('navigation', { name: /Pagination/i })).toBeTruthy();
113
- });
114
-
115
- it('should change paginationAriaLabel appropriately', () => {
116
- render(
117
- <SourcesCard
118
- sources={[
119
- { title: 'How to make an apple pie', link: '' },
120
- { title: 'How to make cookies', link: '' }
121
- ]}
122
- paginationAriaLabel="Navegación"
123
- />
124
- );
125
- expect(screen.getByRole('navigation', { name: /Navegación/i })).toBeTruthy();
126
- });
127
-
128
- it('should change sourceWord appropriately', () => {
129
- render(<SourcesCard sources={[{ title: 'How to make an apple pie', link: '' }]} sourceWord={'fuente'} />);
130
- expect(screen.getByText('1 fuente')).toBeTruthy();
131
- });
132
-
133
- it('should sourceWordPlural appropriately', () => {
134
- render(
135
- <SourcesCard
136
- sources={[
137
- { title: 'How to make an apple pie', link: '' },
138
- { title: 'How to make cookies', link: '' }
139
- ]}
140
- sourceWordPlural={'fuentes'}
141
- />
142
- );
143
- expect(screen.getByText('2 fuentes')).toBeTruthy();
144
- });
145
-
146
- it('should change toNextPageAriaLabel appropriately', () => {
147
- render(
148
- <SourcesCard
149
- sources={[
150
- { title: 'How to make an apple pie', link: '' },
151
- { title: 'How to make cookies', link: '' }
152
- ]}
153
- toNextPageAriaLabel="Pase a la siguiente página"
154
- />
155
- );
156
- expect(screen.getByRole('button', { name: /Pase a la siguiente página/i })).toBeTruthy();
157
- });
158
-
159
- it('should change toPreviousPageAriaLabel appropriately', () => {
160
- render(
161
- <SourcesCard
162
- sources={[
163
- { title: 'How to make an apple pie', link: '' },
164
- { title: 'How to make cookies', link: '' }
165
- ]}
166
- toPreviousPageAriaLabel="Presione para regresar a la página anterior"
167
- />
168
- );
169
- expect(screen.getByRole('button', { name: /Presione para regresar a la página anterior/i })).toBeTruthy();
170
- });
171
-
172
- it('should call onNextClick appropriately', async () => {
173
- const spy = jest.fn();
174
- render(
175
- <SourcesCard
176
- sources={[
177
- { title: 'How to make an apple pie', link: '' },
178
- { title: 'How to make cookies', link: '' }
179
- ]}
180
- onNextClick={spy}
181
- />
182
- );
183
- await userEvent.click(screen.getByRole('button', { name: /Go to next page/i }));
184
- expect(spy).toHaveBeenCalled();
185
- });
186
-
187
- it('should call onPreviousClick appropriately', async () => {
188
- const spy = jest.fn();
189
- render(
190
- <SourcesCard
191
- sources={[
192
- { title: 'How to make an apple pie', link: '' },
193
- { title: 'How to make cookies', link: '' }
194
- ]}
195
- onPreviousClick={spy}
196
- />
197
- );
198
- await userEvent.click(screen.getByRole('button', { name: /Go to next page/i }));
199
- await userEvent.click(screen.getByRole('button', { name: /Go to previous page/i }));
200
- expect(spy).toHaveBeenCalled();
201
- });
202
-
203
- it('should call onSetPage appropriately', async () => {
204
- const spy = jest.fn();
205
- render(
206
- <SourcesCard
207
- sources={[
208
- { title: 'How to make an apple pie', link: '' },
209
- { title: 'How to make cookies', link: '' }
210
- ]}
211
- onSetPage={spy}
212
- />
213
- );
214
- await userEvent.click(screen.getByRole('button', { name: /Go to next page/i }));
215
- expect(spy).toHaveBeenCalledTimes(1);
216
- await userEvent.click(screen.getByRole('button', { name: /Go to previous page/i }));
217
- expect(spy).toHaveBeenCalledTimes(2);
218
- });
219
-
220
- it('should handle showMore appropriately', async () => {
221
- render(
222
- <SourcesCard
223
- sources={[
224
- {
225
- title: 'Getting started with Red Hat OpenShift',
226
- link: '#',
227
- body: 'Red Hat OpenShift on IBM Cloud is a managed offering to create your own cluster of compute hosts where you can deploy and manage containerized apps on IBM Cloud ...',
228
- hasShowMore: true
229
- },
230
- {
231
- title: 'Azure Red Hat OpenShift documentation',
232
- link: '#',
233
- body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure ...'
234
- },
235
- {
236
- title: 'OKD Documentation: Home',
237
- link: '#',
238
- body: 'OKD is a distribution of Kubernetes optimized for continuous application development and multi-tenant deployment. OKD also serves as the upstream code base upon ...'
239
- }
240
- ]}
241
- />
242
- );
243
- expect(screen.getByRole('region')).toHaveAttribute('class', 'pf-v6-c-expandable-section__content');
244
- });
245
-
246
- it('should call onClick appropriately', async () => {
247
- const spy = jest.fn();
248
- render(<SourcesCard sources={[{ title: 'How to make an apple pie', link: '', onClick: spy }]} />);
249
- await userEvent.click(screen.getByRole('link', { name: /How to make an apple pie/i }));
250
- expect(spy).toHaveBeenCalled();
251
- });
252
-
253
- it('should apply titleProps appropriately', () => {
254
- render(
255
- <SourcesCard sources={[{ title: 'How to make an apple pie', link: '', titleProps: { className: 'test' } }]} />
256
- );
257
- expect(screen.getByRole('link', { name: /How to make an apple pie/i })).toHaveClass('test');
258
- });
259
-
260
- it('should apply cardTitleProps appropriately', () => {
261
- render(
262
- <SourcesCard
263
- cardTitleProps={{ 'data-testid': 'card-title', className: 'test' } as any}
264
- sources={[{ title: 'How to make an apple pie', link: '' }]}
265
- />
266
- );
267
- expect(screen.getByTestId('card-title')).toHaveClass('test');
268
- });
269
-
270
- it('should apply cardBodyProps appropriately', () => {
271
- render(
272
- <SourcesCard
273
- cardBodyProps={
274
- { 'data-testid': 'card-body', body: 'To make an apple pie, you must first...', className: 'test' } as any
275
- }
276
- sources={[{ title: 'How to make an apple pie', link: '', body: 'To make an apple pie, you must first...' }]}
277
- />
278
- );
279
- expect(screen.getByTestId('card-body')).toHaveClass('test');
280
- });
281
-
282
- it('should apply cardFooterProps appropriately', () => {
283
- render(
284
- <SourcesCard
285
- cardFooterProps={{ 'data-testid': 'card-footer', className: 'test' } as any}
286
- sources={[
287
- { title: 'How to make an apple pie', link: '' },
288
- { title: 'How to make cookies', link: '' }
289
- ]}
290
- />
291
- );
292
- expect(screen.getByTestId('card-footer')).toHaveClass('test');
293
- });
294
-
295
- it('should apply truncateProps appropriately', () => {
296
- render(
297
- <SourcesCard
298
- sources={[
299
- {
300
- title: 'How to make an apple pie',
301
- link: '',
302
- truncateProps: { 'data-testid': 'card-truncate', className: 'test' } as any
303
- }
304
- ]}
305
- />
306
- );
307
- expect(screen.getByTestId('card-truncate')).toHaveClass('test');
308
- });
309
-
310
- it('should apply custom footer appropriately when there is one source', () => {
311
- render(
312
- <SourcesCard sources={[{ title: 'How to make an apple pie', link: '', footer: <>I am a custom footer</> }]} />
313
- );
314
- expect(screen.getByText('I am a custom footer'));
315
- expect(screen.queryByText('1/1')).toBeFalsy();
316
- });
317
-
318
- it('should apply custom footer appropriately when are multiple sources', () => {
319
- render(
320
- <SourcesCard
321
- sources={[
322
- { title: 'How to make an apple pie', link: '', footer: <>I am a custom footer</> },
323
- { title: 'How to bake bread', link: '' }
324
- ]}
325
- />
326
- );
327
- expect(screen.getByText('I am a custom footer'));
328
- // does not show navigation bar
329
- expect(screen.queryByText('1/2')).toBeFalsy();
330
- });
331
-
332
- it('should apply footer props to custom footer appropriately', () => {
333
- render(
334
- <SourcesCard
335
- cardFooterProps={{ 'data-testid': 'card-footer', className: 'test' } as any}
336
- sources={[{ title: 'How to make an apple pie', link: '', footer: <>I am a custom footer</> }]}
337
- />
338
- );
339
- expect(screen.getByText('I am a custom footer'));
340
- expect(screen.getByTestId('card-footer')).toHaveClass('test');
341
- });
342
-
343
- it('should apply subtitle appropriately', () => {
344
- render(
345
- <SourcesCard
346
- sources={[{ title: 'How to make an apple pie', link: '', subtitle: 'You must first create the universe' }]}
347
- />
348
- );
349
- expect(screen.getByText('How to make an apple pie'));
350
- expect(screen.getByText('You must first create the universe'));
351
- });
352
27
  });
@@ -1,29 +1,18 @@
1
1
  // ============================================================================
2
2
  // Chatbot Main - Messages - Sources Card
3
3
  // ============================================================================
4
- import type { FunctionComponent, MouseEvent as ReactMouseEvent, KeyboardEvent as ReactKeyboardEvent } from 'react';
5
- import { useState } from 'react';
4
+ import type { FunctionComponent } from 'react';
6
5
  // Import PatternFly components
7
6
  import {
8
- Button,
9
7
  ButtonProps,
10
- ButtonVariant,
11
- Card,
12
- CardBody,
13
8
  CardBodyProps,
14
- CardFooter,
15
9
  CardFooterProps,
16
10
  CardProps,
17
- CardTitle,
18
11
  CardTitleProps,
19
- ExpandableSection,
20
- ExpandableSectionVariant,
21
- Icon,
22
12
  pluralize,
23
- Truncate,
24
13
  TruncateProps
25
14
  } from '@patternfly/react-core';
26
- import { ExternalLinkSquareAltIcon } from '@patternfly/react-icons';
15
+ import SourcesCardBase from '../SourcesCardBase';
27
16
 
28
17
  export interface SourcesCardProps extends CardProps {
29
18
  /** Additional classes for the pagination navigation container. */
@@ -84,167 +73,15 @@ export interface SourcesCardProps extends CardProps {
84
73
  }
85
74
 
86
75
  const SourcesCard: FunctionComponent<SourcesCardProps> = ({
87
- className,
88
- isDisabled,
89
- paginationAriaLabel = 'Pagination',
90
76
  sources,
91
77
  sourceWord = 'source',
92
78
  sourceWordPlural = 'sources',
93
- toNextPageAriaLabel = 'Go to next page',
94
- toPreviousPageAriaLabel = 'Go to previous page',
95
- onNextClick,
96
- onPreviousClick,
97
- onSetPage,
98
- showMoreWords = 'show more',
99
- showLessWords = 'show less',
100
- isCompact,
101
- cardTitleProps,
102
- cardBodyProps,
103
- cardFooterProps,
104
79
  ...props
105
- }: SourcesCardProps) => {
106
- const [page, setPage] = useState(1);
107
- const [isExpanded, setIsExpanded] = useState(false);
108
-
109
- const onToggle = (_event: ReactMouseEvent, isExpanded: boolean) => {
110
- setIsExpanded(isExpanded);
111
- };
112
-
113
- const handleNewPage = (_evt: ReactMouseEvent | ReactKeyboardEvent | MouseEvent, newPage: number) => {
114
- setPage(newPage);
115
- onSetPage && onSetPage(_evt, newPage);
116
- };
117
-
118
- const renderTitle = (title?: string, truncateProps?: TruncateProps) => {
119
- if (title) {
120
- return <Truncate content={title} {...truncateProps} />;
121
- }
122
- return `Source ${page}`;
123
- };
124
-
125
- return (
126
- <div className="pf-chatbot__source">
127
- <span>{pluralize(sources.length, sourceWord, sourceWordPlural)}</span>
128
- <Card isCompact={isCompact} className="pf-chatbot__sources-card" {...props}>
129
- <CardTitle className="pf-chatbot__sources-card-title" {...cardTitleProps}>
130
- <div className="pf-chatbot__sources-card-title-container">
131
- <Button
132
- component="a"
133
- variant={ButtonVariant.link}
134
- href={sources[page - 1].link}
135
- icon={sources[page - 1].isExternal ? <ExternalLinkSquareAltIcon /> : undefined}
136
- iconPosition="end"
137
- isInline
138
- rel={sources[page - 1].isExternal ? 'noreferrer' : undefined}
139
- target={sources[page - 1].isExternal ? '_blank' : undefined}
140
- onClick={sources[page - 1].onClick ?? undefined}
141
- {...sources[page - 1].titleProps}
142
- >
143
- {renderTitle(sources[page - 1].title, sources[page - 1].truncateProps)}
144
- </Button>
145
- {sources[page - 1].subtitle && (
146
- <span className="pf-chatbot__sources-card-subtitle">{sources[page - 1].subtitle}</span>
147
- )}
148
- </div>
149
- </CardTitle>
150
- {sources[page - 1].body && (
151
- <CardBody
152
- className={`pf-chatbot__sources-card-body ${sources[page - 1].footer ? 'pf-chatbot__compact-sources-card-body' : undefined}`}
153
- {...cardBodyProps}
154
- >
155
- {sources[page - 1].hasShowMore ? (
156
- // prevents extra VO announcements of button text - parent Message has aria-live
157
- <div aria-live="off">
158
- <ExpandableSection
159
- variant={ExpandableSectionVariant.truncate}
160
- toggleText={isExpanded ? showLessWords : showMoreWords}
161
- onToggle={onToggle}
162
- isExpanded={isExpanded}
163
- truncateMaxLines={2}
164
- >
165
- {sources[page - 1].body}
166
- </ExpandableSection>
167
- </div>
168
- ) : (
169
- <div className="pf-chatbot__sources-card-body-text">{sources[page - 1].body}</div>
170
- )}
171
- </CardBody>
172
- )}
173
- {sources[page - 1].footer ? (
174
- <CardFooter className="pf-chatbot__sources-card-footer" {...cardFooterProps}>
175
- {sources[page - 1].footer}
176
- </CardFooter>
177
- ) : (
178
- sources.length > 1 && (
179
- <CardFooter className="pf-chatbot__sources-card-footer-container" {...cardFooterProps}>
180
- <div className="pf-chatbot__sources-card-footer">
181
- <nav
182
- className={`pf-chatbot__sources-card-footer-buttons ${className}`}
183
- aria-label={paginationAriaLabel}
184
- >
185
- <Button
186
- variant={ButtonVariant.plain}
187
- isDisabled={isDisabled || page === 1}
188
- data-action="previous"
189
- onClick={(event) => {
190
- const newPage = page >= 1 ? page - 1 : 1;
191
- onPreviousClick && onPreviousClick(event, newPage);
192
- handleNewPage(event, newPage);
193
- }}
194
- aria-label={toPreviousPageAriaLabel}
195
- >
196
- <Icon iconSize="lg">
197
- {/* these are inline because the viewBox that works in a round icon is different than the PatternFly default */}
198
- <svg
199
- className="pf-v6-svg"
200
- viewBox="0 0 280 500"
201
- fill="currentColor"
202
- aria-hidden="true"
203
- role="img"
204
- width="1em"
205
- height="1em"
206
- >
207
- <path d="M31.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L127.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L201.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34z"></path>
208
- </svg>
209
- </Icon>
210
- </Button>
211
- <span aria-hidden="true">
212
- {page}/{sources.length}
213
- </span>
214
- <Button
215
- variant={ButtonVariant.plain}
216
- isDisabled={isDisabled || page === sources.length}
217
- aria-label={toNextPageAriaLabel}
218
- data-action="next"
219
- onClick={(event) => {
220
- const newPage = page + 1 <= sources.length ? page + 1 : sources.length;
221
- onNextClick && onNextClick(event, newPage);
222
- handleNewPage(event, newPage);
223
- }}
224
- >
225
- <Icon isInline iconSize="lg">
226
- {/* these are inline because the viewBox that works in a round icon is different than the PatternFly default */}
227
- <svg
228
- className="pf-v6-svg"
229
- viewBox="0 0 180 500"
230
- fill="currentColor"
231
- aria-hidden="true"
232
- role="img"
233
- width="1em"
234
- height="1em"
235
- >
236
- <path d="M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z"></path>
237
- </svg>
238
- </Icon>
239
- </Button>
240
- </nav>
241
- </div>
242
- </CardFooter>
243
- )
244
- )}
245
- </Card>
246
- </div>
247
- );
248
- };
80
+ }: SourcesCardProps) => (
81
+ <div className="pf-chatbot__source">
82
+ <span>{pluralize(sources.length, sourceWord, sourceWordPlural)}</span>
83
+ <SourcesCardBase sources={sources} {...props} />
84
+ </div>
85
+ );
249
86
 
250
87
  export default SourcesCard;