@patternfly/chatbot 6.4.0-prerelease.20 → 6.4.0-prerelease.21

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 (59) hide show
  1. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +1 -1
  2. package/dist/cjs/FileDetails/FileDetails.d.ts +22 -3
  3. package/dist/cjs/FileDetails/FileDetails.js +27 -912
  4. package/dist/cjs/FileDetails/FileDetails.test.js +16 -0
  5. package/dist/cjs/FileDetailsLabel/FileDetailsLabel.d.ts +8 -2
  6. package/dist/cjs/FileDetailsLabel/FileDetailsLabel.js +14 -2
  7. package/dist/cjs/FileDetailsLabel/FileDetailsLabel.test.js +19 -1
  8. package/dist/cjs/ImagePreview/ImagePreview.d.ts +53 -0
  9. package/dist/cjs/ImagePreview/ImagePreview.js +47 -0
  10. package/dist/cjs/ImagePreview/ImagePreview.test.d.ts +1 -0
  11. package/dist/cjs/ImagePreview/ImagePreview.test.js +225 -0
  12. package/dist/cjs/ImagePreview/index.d.ts +2 -0
  13. package/dist/cjs/ImagePreview/index.js +23 -0
  14. package/dist/cjs/MessageBox/MessageBox.js +1 -1
  15. package/dist/cjs/index.d.ts +2 -0
  16. package/dist/cjs/index.js +4 -1
  17. package/dist/css/main.css +75 -19
  18. package/dist/css/main.css.map +1 -1
  19. package/dist/dynamic/ImagePreview/package.json +1 -0
  20. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +1 -1
  21. package/dist/esm/FileDetails/FileDetails.d.ts +22 -3
  22. package/dist/esm/FileDetails/FileDetails.js +27 -912
  23. package/dist/esm/FileDetails/FileDetails.test.js +16 -0
  24. package/dist/esm/FileDetailsLabel/FileDetailsLabel.d.ts +8 -2
  25. package/dist/esm/FileDetailsLabel/FileDetailsLabel.js +14 -2
  26. package/dist/esm/FileDetailsLabel/FileDetailsLabel.test.js +19 -1
  27. package/dist/esm/ImagePreview/ImagePreview.d.ts +53 -0
  28. package/dist/esm/ImagePreview/ImagePreview.js +42 -0
  29. package/dist/esm/ImagePreview/ImagePreview.test.d.ts +1 -0
  30. package/dist/esm/ImagePreview/ImagePreview.test.js +220 -0
  31. package/dist/esm/ImagePreview/index.d.ts +2 -0
  32. package/dist/esm/ImagePreview/index.js +2 -0
  33. package/dist/esm/MessageBox/MessageBox.js +1 -1
  34. package/dist/esm/index.d.ts +2 -0
  35. package/dist/esm/index.js +2 -0
  36. package/dist/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +1 -1
  38. package/patternfly-docs/content/extensions/chatbot/examples/Messages/AttachmentEdit.tsx +1 -1
  39. package/patternfly-docs/content/extensions/chatbot/examples/Messages/ImagePreview.tsx +53 -0
  40. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +11 -1
  41. package/patternfly-docs/content/extensions/chatbot/examples/Messages/PreviewAttachment.tsx +1 -1
  42. package/patternfly-docs/content/extensions/chatbot/examples/Messages/file-preview.svg +9 -0
  43. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +0 -12
  44. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +1 -1
  45. package/src/FileDetails/FileDetails.scss +10 -0
  46. package/src/FileDetails/FileDetails.test.tsx +16 -0
  47. package/src/FileDetails/FileDetails.tsx +89 -32
  48. package/src/FileDetails/__snapshots__/FileDetails.test.tsx.snap +25 -16
  49. package/src/FileDetailsLabel/FileDetailsLabel.test.tsx +21 -1
  50. package/src/FileDetailsLabel/FileDetailsLabel.tsx +16 -3
  51. package/src/FileDetailsLabel/__snapshots__/FileDetailsLabel.test.tsx.snap +25 -16
  52. package/src/ImagePreview/ImagePreview.scss +61 -0
  53. package/src/ImagePreview/ImagePreview.test.tsx +253 -0
  54. package/src/ImagePreview/ImagePreview.tsx +200 -0
  55. package/src/ImagePreview/index.ts +3 -0
  56. package/src/MessageBox/MessageBox.scss +0 -12
  57. package/src/MessageBox/MessageBox.tsx +1 -1
  58. package/src/index.ts +3 -0
  59. package/src/main.scss +13 -0
@@ -10,6 +10,7 @@ describe('FileDetails', () => {
10
10
  it('should render file details correctly if an extension we support is passed in', () => {
11
11
  render(_jsx(FileDetails, { fileName: "test.txt", languageTestId: "language" }));
12
12
  expect(screen.getByText('test')).toBeTruthy();
13
+ expect(screen.queryByText('test.txt')).toBeFalsy();
13
14
  expect(screen.getByText('TEXT')).toBeTruthy();
14
15
  expect(screen.getByTestId('language')).toBeTruthy();
15
16
  });
@@ -18,4 +19,19 @@ describe('FileDetails', () => {
18
19
  expect(screen.getByText('test')).toBeTruthy();
19
20
  expect(screen.queryByTestId('language')).toBeFalsy();
20
21
  });
22
+ it('should support image formats by rendering extension differently', () => {
23
+ render(_jsx(FileDetails, { fileName: "test.svg", languageTestId: "language" }));
24
+ expect(screen.getByText('test')).toBeTruthy();
25
+ expect(screen.queryByText('test.svg')).toBeFalsy();
26
+ expect(screen.queryByTestId('language')).toBeFalsy();
27
+ });
28
+ it('should handle truncation differently', () => {
29
+ render(_jsx(FileDetails, { fileName: "test.svg", languageTestId: "language", hasTruncation: false }));
30
+ expect(screen.getByText('test.svg')).toBeTruthy();
31
+ expect(screen.queryByTestId('language')).toBeFalsy();
32
+ });
33
+ it('should include file size if prop passed in', () => {
34
+ render(_jsx(FileDetails, { fileName: "test.joke", languageTestId: "language", fileSize: "100MB" }));
35
+ expect(screen.getByText('100MB')).toBeTruthy();
36
+ });
21
37
  });
@@ -1,5 +1,5 @@
1
1
  import { PropsWithChildren } from 'react';
2
- interface FileDetailsLabelProps {
2
+ export interface FileDetailsLabelProps {
3
3
  /** Name of file, including extension */
4
4
  fileName: string;
5
5
  /** Unique id of file */
@@ -16,6 +16,12 @@ interface FileDetailsLabelProps {
16
16
  languageTestId?: string;
17
17
  /** Custom test id for the loading spinner in the component */
18
18
  spinnerTestId?: string;
19
+ /** File size */
20
+ fileSize?: string;
21
+ /** Whether to truncate file name */
22
+ hasTruncation?: boolean;
23
+ /** Icon used for close button */
24
+ closeButtonIcon?: React.ReactNode;
19
25
  }
20
- export declare const FileDetailsLabel: ({ fileName, fileId, isLoading, onClick, onClose, closeButtonAriaLabel, languageTestId, spinnerTestId }: PropsWithChildren<FileDetailsLabelProps>) => import("react/jsx-runtime").JSX.Element;
26
+ export declare const FileDetailsLabel: ({ fileName, fileId, isLoading, onClick, onClose, closeButtonAriaLabel, languageTestId, spinnerTestId, fileSize, hasTruncation, closeButtonIcon, ...props }: PropsWithChildren<FileDetailsLabelProps>) => import("react/jsx-runtime").JSX.Element;
21
27
  export default FileDetailsLabel;
@@ -1,12 +1,24 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
1
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
13
  import { Button, Label } from '@patternfly/react-core';
3
14
  import FileDetails from '../FileDetails';
4
15
  import { Spinner } from '@patternfly/react-core';
5
16
  import { TimesIcon } from '@patternfly/react-icons';
6
- export const FileDetailsLabel = ({ fileName, fileId, isLoading, onClick, onClose, closeButtonAriaLabel, languageTestId, spinnerTestId }) => {
17
+ export const FileDetailsLabel = (_a) => {
18
+ var { fileName, fileId, isLoading, onClick, onClose, closeButtonAriaLabel, languageTestId, spinnerTestId, fileSize, hasTruncation = true, closeButtonIcon = _jsx(TimesIcon, {}) } = _a, props = __rest(_a, ["fileName", "fileId", "isLoading", "onClick", "onClose", "closeButtonAriaLabel", "languageTestId", "spinnerTestId", "fileSize", "hasTruncation", "closeButtonIcon"]);
7
19
  const handleClose = (event) => {
8
20
  onClose && onClose(event, fileName, fileId);
9
21
  };
10
- return (_jsx(Label, Object.assign({ className: "pf-chatbot__file-label" }, (onClose && { onClose: (event) => onClose(event, fileName, fileId) }), { closeBtn: _jsx(Button, { type: "button", variant: "plain", "aria-label": closeButtonAriaLabel !== null && closeButtonAriaLabel !== void 0 ? closeButtonAriaLabel : `Close ${fileName}`, icon: _jsx(TimesIcon, {}), onClick: handleClose }) }, (onClick && { onClick: (event) => onClick(event, fileName, fileId) }), { children: _jsxs("div", { className: "pf-chatbot__file-label-contents", children: [_jsx(FileDetails, { className: isLoading ? 'pf-chatbot__file-label-loading' : undefined, fileName: fileName, languageTestId: languageTestId }), isLoading && _jsx(Spinner, { "data-testid": spinnerTestId, size: "sm" })] }) })));
22
+ return (_jsx(Label, Object.assign({ className: "pf-chatbot__file-label" }, (onClose && { onClose: (event) => onClose(event, fileName, fileId) }), { closeBtn: _jsx(Button, { type: "button", variant: "plain", "aria-label": closeButtonAriaLabel !== null && closeButtonAriaLabel !== void 0 ? closeButtonAriaLabel : `Close ${fileName}`, icon: closeButtonIcon, onClick: handleClose }) }, (onClick && { onClick: (event) => onClick(event, fileName, fileId) }), props, { children: _jsxs("div", { className: "pf-chatbot__file-label-contents", children: [_jsx(FileDetails, { className: isLoading ? 'pf-chatbot__file-label-loading' : undefined, fileName: fileName, languageTestId: languageTestId, fileSize: fileSize, hasTruncation: hasTruncation }), isLoading && _jsx(Spinner, { "data-testid": spinnerTestId, size: "sm" })] }) })));
11
23
  };
12
24
  export default FileDetailsLabel;
@@ -12,6 +12,7 @@ import { render, screen } from '@testing-library/react';
12
12
  import '@testing-library/jest-dom';
13
13
  import FileDetailsLabel from './FileDetailsLabel';
14
14
  import userEvent from '@testing-library/user-event';
15
+ import { BellIcon } from '@patternfly/react-icons';
15
16
  describe('FileDetailsLabel', () => {
16
17
  it('should render file details label', () => {
17
18
  const { container } = render(_jsx(FileDetailsLabel, { fileName: "test.txt" }));
@@ -27,6 +28,19 @@ describe('FileDetailsLabel', () => {
27
28
  expect(screen.getByText('test')).toBeTruthy();
28
29
  expect(screen.queryByTestId('language')).toBeFalsy();
29
30
  });
31
+ it('should pass file size down', () => {
32
+ render(_jsx(FileDetailsLabel, { fileName: "test.svg", fileSize: "100MB" }));
33
+ expect(screen.getByText('100MB')).toBeTruthy();
34
+ });
35
+ it('should pass truncation prop down as true by default', () => {
36
+ render(_jsx(FileDetailsLabel, { fileName: "test.svg" }));
37
+ expect(screen.getByText('test')).toBeTruthy();
38
+ expect(screen.queryByText('test.svg')).toBeFalsy();
39
+ });
40
+ it('should pass truncation prop down when false', () => {
41
+ render(_jsx(FileDetailsLabel, { fileName: "test.svg", hasTruncation: false }));
42
+ expect(screen.getByText('test.svg')).toBeTruthy();
43
+ });
30
44
  it('should not show spinner by default', () => {
31
45
  render(_jsx(FileDetailsLabel, { fileName: "test.txt", spinnerTestId: "spinner" }));
32
46
  expect(screen.queryByTestId('spinner')).toBeFalsy();
@@ -51,6 +65,10 @@ describe('FileDetailsLabel', () => {
51
65
  }));
52
66
  it('should use closeButtonAriaLabel prop appropriately', () => {
53
67
  render(_jsx(FileDetailsLabel, { fileName: "test.txt", onClose: jest.fn(), closeButtonAriaLabel: "Delete file" }));
54
- screen.getByRole('button', { name: /Delete file/i });
68
+ expect(screen.getByRole('button', { name: /Delete file/i })).toBeTruthy();
69
+ });
70
+ it('should support custom close icon', () => {
71
+ render(_jsx(FileDetailsLabel, { fileName: "test.txt", onClose: jest.fn(), closeButtonIcon: _jsx(BellIcon, { "data-testid": "bell" }) }));
72
+ expect(screen.getByTestId('bell')).toBeTruthy();
55
73
  });
56
74
  });
@@ -0,0 +1,53 @@
1
+ import { ModalBodyProps, ModalHeaderProps } from '@patternfly/react-core';
2
+ import { type FunctionComponent } from 'react';
3
+ import { ChatbotDisplayMode } from '../Chatbot';
4
+ import { ChatbotModalProps } from '../ChatbotModal';
5
+ import { FileDetailsLabelProps } from '../FileDetailsLabel';
6
+ export interface ImagePreviewProps extends Omit<ChatbotModalProps, 'children'> {
7
+ /** Class applied to modal */
8
+ className?: string;
9
+ /** Function that handles modal toggle */
10
+ handleModalToggle: (event: React.MouseEvent | MouseEvent | KeyboardEvent) => void;
11
+ /** Whether modal is open */
12
+ isModalOpen: boolean;
13
+ /** Title of modal */
14
+ title?: string;
15
+ /** Display mode for the Chatbot parent; this influences the styles applied */
16
+ displayMode?: ChatbotDisplayMode;
17
+ /** Sets modal to compact styling. */
18
+ isCompact?: boolean;
19
+ /** Additional props passed to modal header */
20
+ modalHeaderProps?: ModalHeaderProps;
21
+ /** Additional props passed to modal body */
22
+ modalBodyProps?: ModalBodyProps;
23
+ /** Images displayed in modal */
24
+ images: {
25
+ fileName: string;
26
+ fileSize?: string;
27
+ image: React.ReactNode;
28
+ }[];
29
+ /** Flag indicating if the pagination is disabled. */
30
+ isDisabled?: boolean;
31
+ /** Accessible label for the pagination component. */
32
+ paginationAriaLabel?: string;
33
+ /** Accessible label for the button which moves to the next page. */
34
+ toNextPageAriaLabel?: string;
35
+ /** Accessible label for the button which moves to the previous page. */
36
+ toPreviousPageAriaLabel?: string;
37
+ /** Function called when user clicks to navigate to next page. */
38
+ onNextClick?: (event: React.SyntheticEvent<HTMLButtonElement>, page: number) => void;
39
+ /** Function called when user clicks to navigate to previous page. */
40
+ onPreviousClick?: (event: React.SyntheticEvent<HTMLButtonElement>, page: number) => void;
41
+ /** Function called when page is changed. */
42
+ onSetPage?: (event: React.MouseEvent | React.KeyboardEvent | MouseEvent, newPage: number) => void;
43
+ /** Callback function for when file details label close button is clicked */
44
+ onCloseFileDetailsLabel?: (event: React.MouseEvent, fileName: string, fileId?: string | number) => void;
45
+ /** Props passed to file details label */
46
+ fileDetailsLabelProps?: Omit<FileDetailsLabelProps, 'fileName'>;
47
+ /** Text shown in navigation */
48
+ paginationContent?: string;
49
+ /** Navigation progress announced to assistive devices. Should state the current page/image. */
50
+ screenreaderText?: string;
51
+ }
52
+ declare const ImagePreview: FunctionComponent<ImagePreviewProps>;
53
+ export default ImagePreview;
@@ -0,0 +1,42 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { Button, ButtonVariant, Icon, ModalBody, ModalFooter, ModalHeader, Stack, StackItem } from '@patternfly/react-core';
14
+ import { useState, useEffect } from 'react';
15
+ import { ChatbotDisplayMode } from '../Chatbot';
16
+ import ChatbotModal from '../ChatbotModal';
17
+ import FileDetailsLabel from '../FileDetailsLabel';
18
+ import { TrashIcon } from '@patternfly/react-icons';
19
+ const ImagePreview = (_a) => {
20
+ var { isModalOpen, displayMode = ChatbotDisplayMode.default, isCompact, className, handleModalToggle, title = 'Preview images', modalHeaderProps, modalBodyProps, images, isDisabled, onSetPage, onPreviousClick, toNextPageAriaLabel = 'Go to next image', toPreviousPageAriaLabel = 'Go to previous image', onNextClick, paginationAriaLabel, onCloseFileDetailsLabel, fileDetailsLabelProps, paginationContent, screenreaderText } = _a, props = __rest(_a, ["isModalOpen", "displayMode", "isCompact", "className", "handleModalToggle", "title", "modalHeaderProps", "modalBodyProps", "images", "isDisabled", "onSetPage", "onPreviousClick", "toNextPageAriaLabel", "toPreviousPageAriaLabel", "onNextClick", "paginationAriaLabel", "onCloseFileDetailsLabel", "fileDetailsLabelProps", "paginationContent", "screenreaderText"]);
21
+ const [page, setPage] = useState(1);
22
+ const paginationText = paginationContent || `${page}/${images.length}`;
23
+ useEffect(() => {
24
+ if (images.length === 0 || page > images.length) {
25
+ setPage(1);
26
+ }
27
+ }, [images.length, page]);
28
+ const handleNewPage = (_evt, newPage) => {
29
+ setPage(newPage);
30
+ onSetPage && onSetPage(_evt, newPage);
31
+ };
32
+ return (_jsxs(ChatbotModal, Object.assign({ isOpen: isModalOpen, className: `pf-chatbot__image-preview-modal pf-chatbot__image-preview-modal--${displayMode} ${isCompact ? 'pf-m-compact' : ''} ${className ? className : ''}`, displayMode: displayMode, onClose: handleModalToggle, isCompact: isCompact }, props, { children: [_jsx(ModalHeader, Object.assign({ title: title }, modalHeaderProps)), _jsx(ModalBody, Object.assign({ className: "pf-chatbot__image-preview-body" }, modalBodyProps, { children: images.length > 0 && images[page - 1] && (_jsxs(Stack, { hasGutter: true, className: "pf-chatbot__image-preview-stack", children: [_jsx(StackItem, { children: _jsx(FileDetailsLabel, Object.assign({ fileName: images[page - 1].fileName, fileSize: images[page - 1].fileSize, hasTruncation: false, onClose: onCloseFileDetailsLabel, closeButtonIcon: _jsx(TrashIcon, {}) }, fileDetailsLabelProps)) }), _jsx(StackItem, { children: _jsx("div", { className: "pf-chatbot__image-preview-body", children: images[page - 1].image }) })] })) })), images.length > 1 && (_jsx(ModalFooter, { className: "pf-chatbot__image-preview-footer", children: _jsxs("nav", { className: `pf-chatbot__image-preview-footer-buttons`, "aria-label": paginationAriaLabel, children: [_jsx(Button, { variant: ButtonVariant.plain, isDisabled: isDisabled || page === 1, "data-action": "previous", onClick: (event) => {
33
+ const newPage = page > 1 ? page - 1 : 1;
34
+ handleNewPage(event, newPage);
35
+ onPreviousClick && onPreviousClick(event, newPage);
36
+ }, "aria-label": toPreviousPageAriaLabel, children: _jsx(Icon, { iconSize: "lg", children: _jsx("svg", { className: "pf-v6-svg", viewBox: "0 0 280 500", fill: "currentColor", "aria-hidden": "true", role: "img", width: "1em", height: "1em", children: _jsx("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" }) }) }) }), _jsx("span", { children: paginationText }), _jsx("div", { className: "pf-chatbot-m-hidden", "aria-live": "polite", children: screenreaderText !== null && screenreaderText !== void 0 ? screenreaderText : `Image ${page} of ${images.length}` }), _jsx(Button, { variant: ButtonVariant.plain, isDisabled: isDisabled || page === images.length, "aria-label": toNextPageAriaLabel, "data-action": "next", onClick: (event) => {
37
+ const newPage = page + 1 <= images.length ? page + 1 : images.length;
38
+ handleNewPage(event, newPage);
39
+ onNextClick && onNextClick(event, newPage);
40
+ }, children: _jsx(Icon, { isInline: true, iconSize: "lg", children: _jsx("svg", { className: "pf-v6-svg", viewBox: "0 0 180 500", fill: "currentColor", "aria-hidden": "true", role: "img", width: "1em", height: "1em", children: _jsx("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" }) }) }) })] }) }))] })));
41
+ };
42
+ export default ImagePreview;
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1,220 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import ImagePreview from './ImagePreview';
5
+ import { ChatbotDisplayMode } from '../Chatbot';
6
+ const mockImages = [
7
+ {
8
+ fileName: 'image1.jpg',
9
+ fileSize: '2.5 MB',
10
+ image: _jsx("img", { src: "", alt: "Test image 1" })
11
+ },
12
+ {
13
+ fileName: 'image2.png',
14
+ fileSize: '1.8 MB',
15
+ image: _jsx("img", { src: "", alt: "Test image 2" })
16
+ },
17
+ {
18
+ fileName: 'image3.gif',
19
+ image: _jsx("img", { src: "", alt: "Test image 3" })
20
+ }
21
+ ];
22
+ const defaultProps = {
23
+ isModalOpen: true,
24
+ handleModalToggle: jest.fn(),
25
+ images: mockImages
26
+ };
27
+ describe('ImagePreview', () => {
28
+ beforeEach(() => {
29
+ jest.clearAllMocks();
30
+ });
31
+ it('renders modal when isModalOpen is true', () => {
32
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps)));
33
+ expect(screen.getByRole('dialog')).toBeInTheDocument();
34
+ });
35
+ it('does not render modal when isModalOpen is false', () => {
36
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { isModalOpen: false })));
37
+ expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
38
+ });
39
+ it('displays custom title when provided', () => {
40
+ const customTitle = 'Custom image preview';
41
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { title: customTitle })));
42
+ expect(screen.getByRole('heading', { name: customTitle })).toBeInTheDocument();
43
+ });
44
+ it('displays default title when no title provided', () => {
45
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps)));
46
+ expect(screen.getByRole('heading', { name: /Preview images/i })).toBeInTheDocument();
47
+ });
48
+ it('calls handleModalToggle when modal is closed', () => {
49
+ const mockHandleToggle = jest.fn();
50
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { handleModalToggle: mockHandleToggle })));
51
+ const closeButton = screen.getByRole('button', { name: /close/i });
52
+ fireEvent.click(closeButton);
53
+ expect(mockHandleToggle).toHaveBeenCalledTimes(1);
54
+ });
55
+ it('displays first image by default', () => {
56
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps)));
57
+ expect(screen.getByText('image1.jpg')).toBeInTheDocument();
58
+ expect(screen.getByText('2.5 MB')).toBeInTheDocument();
59
+ expect(screen.getByAltText('Test image 1')).toBeInTheDocument();
60
+ });
61
+ it('displays page counter correctly', () => {
62
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps)));
63
+ expect(screen.getByText('1/3')).toBeInTheDocument();
64
+ });
65
+ it('navigates to next image when next button is clicked', () => {
66
+ const mockOnNextClick = jest.fn();
67
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { onNextClick: mockOnNextClick })));
68
+ const nextButton = screen.getByRole('button', { name: /Go to next image/i });
69
+ fireEvent.click(nextButton);
70
+ expect(mockOnNextClick).toHaveBeenCalled();
71
+ expect(screen.getByText('2/3')).toBeInTheDocument();
72
+ expect(screen.getByText('image2.png')).toBeInTheDocument();
73
+ });
74
+ it('navigates to previous image when previous button is clicked', () => {
75
+ const mockOnPreviousClick = jest.fn();
76
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { onPreviousClick: mockOnPreviousClick })));
77
+ // First go to page 2
78
+ const nextButton = screen.getByRole('button', { name: /Go to next image/i });
79
+ fireEvent.click(nextButton);
80
+ // Then go back to page 1
81
+ const previousButton = screen.getByRole('button', { name: /Go to previous image/i });
82
+ fireEvent.click(previousButton);
83
+ expect(mockOnPreviousClick).toHaveBeenCalled();
84
+ expect(screen.getByText('1/3')).toBeInTheDocument();
85
+ });
86
+ it('calls onSetPage when page changes', () => {
87
+ const mockOnSetPage = jest.fn();
88
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { onSetPage: mockOnSetPage })));
89
+ const nextButton = screen.getByRole('button', { name: /Go to next image/i });
90
+ fireEvent.click(nextButton);
91
+ expect(mockOnSetPage).toHaveBeenCalledWith(expect.any(Object), 2);
92
+ });
93
+ it('disables previous button on first page', () => {
94
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps)));
95
+ const previousButton = screen.getByRole('button', { name: /Go to previous image/i });
96
+ expect(previousButton).toBeDisabled();
97
+ });
98
+ it('disables next button on last page', () => {
99
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps)));
100
+ // Navigate to last page
101
+ const nextButton = screen.getByRole('button', { name: /Go to next image/i });
102
+ fireEvent.click(nextButton); // page 2
103
+ fireEvent.click(nextButton); // page 3
104
+ expect(nextButton).toBeDisabled();
105
+ });
106
+ it('disables both navigation buttons when isDisabled is true', () => {
107
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { isDisabled: true })));
108
+ const previousButton = screen.getByRole('button', { name: /Go to previous image/i });
109
+ const nextButton = screen.getByRole('button', { name: /Go to next image/i });
110
+ expect(previousButton).toBeDisabled();
111
+ expect(nextButton).toBeDisabled();
112
+ });
113
+ it('uses custom aria labels for pagination', () => {
114
+ const customLabels = {
115
+ paginationAriaLabel: 'Custom pagination',
116
+ toPreviousPageAriaLabel: 'Go to previous image',
117
+ toNextPageAriaLabel: 'Go to next image'
118
+ };
119
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, customLabels)));
120
+ expect(screen.getByRole('navigation', { name: 'Custom pagination' })).toBeInTheDocument();
121
+ expect(screen.getByRole('button', { name: 'Go to previous image' })).toBeInTheDocument();
122
+ expect(screen.getByRole('button', { name: 'Go to next image' })).toBeInTheDocument();
123
+ });
124
+ it('renders with compact mode when isCompact is true', () => {
125
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { isCompact: true })));
126
+ const modal = screen.getByRole('dialog');
127
+ expect(modal).toHaveClass('pf-m-compact');
128
+ });
129
+ it('applies custom className when provided', () => {
130
+ const customClassName = 'custom-image-preview';
131
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { className: customClassName })));
132
+ const modal = screen.getByRole('dialog');
133
+ expect(modal).toHaveClass(customClassName);
134
+ });
135
+ it('applies display mode class correctly', () => {
136
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { displayMode: ChatbotDisplayMode.embedded })));
137
+ const modal = screen.getByRole('dialog');
138
+ expect(modal).toHaveClass('pf-chatbot__image-preview-modal--embedded');
139
+ });
140
+ it('passes additional props to ChatbotModal', () => {
141
+ const modalClass = 'custom-modal-class';
142
+ const additionalProps = {
143
+ 'data-testid': 'modal',
144
+ className: modalClass
145
+ };
146
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, additionalProps)));
147
+ const modal = screen.getByTestId('modal');
148
+ expect(modal).toBeInTheDocument();
149
+ expect(modal).toBeInTheDocument();
150
+ expect(modal).toHaveClass(modalClass);
151
+ });
152
+ it('passes modalHeaderProps correctly', () => {
153
+ const headerClass = 'custom-modal-header-class';
154
+ const headerProps = {
155
+ 'data-testid': 'header',
156
+ className: headerClass
157
+ };
158
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { modalHeaderProps: headerProps })));
159
+ expect(screen.getByTestId('header')).toBeInTheDocument();
160
+ expect(screen.getByTestId('header')).toHaveClass(headerClass);
161
+ });
162
+ it('passes modalBodyProps correctly', () => {
163
+ const bodyClass = 'custom-modal-body-class';
164
+ const bodyProps = {
165
+ 'data-testid': 'body',
166
+ className: bodyClass
167
+ };
168
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { modalBodyProps: bodyProps })));
169
+ expect(screen.getByTestId('body')).toBeInTheDocument();
170
+ expect(screen.getByTestId('body')).toHaveClass(bodyClass);
171
+ });
172
+ it('handles single image without pagination', () => {
173
+ const singleImage = [mockImages[0]];
174
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { images: singleImage })));
175
+ expect(screen.queryByText('1/1')).not.toBeInTheDocument();
176
+ expect(screen.queryByRole('button', { name: /Go to previous image/i })).not.toBeInTheDocument();
177
+ expect(screen.queryByRole('button', { name: /Go to next image/i })).not.toBeInTheDocument();
178
+ });
179
+ it('calls onCloseFileDetailsLabel when file details close button is clicked', () => {
180
+ const mockOnClose = jest.fn();
181
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { onCloseFileDetailsLabel: mockOnClose })));
182
+ const closeButton = screen.getByRole('button', { name: /Close image1.jpg/i });
183
+ fireEvent.click(closeButton);
184
+ expect(mockOnClose).toHaveBeenCalled();
185
+ });
186
+ it('passes fileDetailsLabelProps correctly to FileDetailsLabel', () => {
187
+ const customFileDetailsProps = {
188
+ 'data-testid': 'custom-file-details'
189
+ };
190
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { fileDetailsLabelProps: customFileDetailsProps })));
191
+ expect(screen.getByTestId('custom-file-details')).toBeInTheDocument();
192
+ });
193
+ it('displays file details for current page when navigating', () => {
194
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps)));
195
+ // Initially shows first image details
196
+ expect(screen.getByText('image1.jpg')).toBeInTheDocument();
197
+ expect(screen.getByText('2.5 MB')).toBeInTheDocument();
198
+ // Navigate to second page
199
+ const nextButton = screen.getByRole('button', { name: /Go to next image/i });
200
+ fireEvent.click(nextButton);
201
+ // Should now show second image details
202
+ expect(screen.getByText('image2.png')).toBeInTheDocument();
203
+ expect(screen.getByText('1.8 MB')).toBeInTheDocument();
204
+ // Navigate to third page
205
+ fireEvent.click(nextButton);
206
+ // Should now show third image details (no file size)
207
+ expect(screen.getByText('image3.gif')).toBeInTheDocument();
208
+ expect(screen.queryByText(/MB/)).not.toBeInTheDocument();
209
+ });
210
+ it('sets hasTruncation to false on FileDetailsLabel', () => {
211
+ const longFileName = 'very-long-filename-that-would-normally-be-truncated-in-other-contexts.jpg';
212
+ const imageWithLongName = {
213
+ fileName: longFileName,
214
+ fileSize: '1.0 MB',
215
+ image: _jsx("img", { src: "", alt: "Test image with long name" })
216
+ };
217
+ render(_jsx(ImagePreview, Object.assign({}, defaultProps, { images: [imageWithLongName] })));
218
+ expect(screen.getByText(longFileName)).toBeInTheDocument();
219
+ });
220
+ });
@@ -0,0 +1,2 @@
1
+ export { default } from './ImagePreview';
2
+ export * from './ImagePreview';
@@ -0,0 +1,2 @@
1
+ export { default } from './ImagePreview';
2
+ export * from './ImagePreview';
@@ -200,6 +200,6 @@ export const MessageBox = forwardRef((_a, ref) => {
200
200
  onTouchMove,
201
201
  onTouchEnd
202
202
  };
203
- return (_jsxs(_Fragment, { children: [_jsx(JumpButton, { position: "top", isHidden: isOverflowing && atTop, onClick: scrollToTop, jumpButtonProps: jumpButtonTopProps, jumpButtonTooltipProps: jumpButtonTopTooltipProps }), _jsxs("div", Object.assign({ role: "region", tabIndex: 0, "aria-label": ariaLabel, className: `pf-chatbot__messagebox ${position === 'bottom' ? 'pf-chatbot__messagebox--bottom' : ''} ${className !== null && className !== void 0 ? className : ''}`, ref: messageBoxRef }, props, (enableSmartScroll ? Object.assign({}, smartScrollHandlers) : {}), { children: [children, _jsx("div", { className: "pf-chatbot__messagebox-announcement", "aria-live": "polite", children: announcement })] })), _jsx(JumpButton, { position: "bottom", isHidden: isOverflowing && atBottom, onClick: () => scrollToBottom({ resumeSmartScroll: true }), jumpButtonProps: jumpButtonBottomProps, jumpButtonTooltipProps: jumpButtonBottomTooltipProps })] }));
203
+ return (_jsxs(_Fragment, { children: [_jsx(JumpButton, { position: "top", isHidden: isOverflowing && atTop, onClick: scrollToTop, jumpButtonProps: jumpButtonTopProps, jumpButtonTooltipProps: jumpButtonTopTooltipProps }), _jsxs("div", Object.assign({ role: "region", tabIndex: 0, "aria-label": ariaLabel, className: `pf-chatbot__messagebox ${position === 'bottom' ? 'pf-chatbot__messagebox--bottom' : ''} ${className !== null && className !== void 0 ? className : ''}`, ref: messageBoxRef }, props, (enableSmartScroll ? Object.assign({}, smartScrollHandlers) : {}), { children: [children, _jsx("div", { className: "pf-chatbot__messagebox-announcement pf-chatbot-m-hidden", "aria-live": "polite", children: announcement })] })), _jsx(JumpButton, { position: "bottom", isHidden: isOverflowing && atBottom, onClick: () => scrollToBottom({ resumeSmartScroll: true }), jumpButtonProps: jumpButtonBottomProps, jumpButtonTooltipProps: jumpButtonBottomTooltipProps })] }));
204
204
  });
205
205
  export default MessageBox;
@@ -36,6 +36,8 @@ export { default as FileDropZone } from './FileDropZone';
36
36
  export * from './FileDropZone';
37
37
  export { default as FilePreview } from './FilePreview';
38
38
  export * from './FilePreview';
39
+ export { default as ImagePreview } from './ImagePreview';
40
+ export * from './ImagePreview';
39
41
  export { default as LoadingMessage } from './LoadingMessage';
40
42
  export * from './LoadingMessage';
41
43
  export { default as Message } from './Message';
package/dist/esm/index.js CHANGED
@@ -37,6 +37,8 @@ export { default as FileDropZone } from './FileDropZone';
37
37
  export * from './FileDropZone';
38
38
  export { default as FilePreview } from './FilePreview';
39
39
  export * from './FilePreview';
40
+ export { default as ImagePreview } from './ImagePreview';
41
+ export * from './ImagePreview';
40
42
  export { default as LoadingMessage } from './LoadingMessage';
41
43
  export * from './LoadingMessage';
42
44
  export { default as Message } from './Message';
@@ -1 +1 @@
1
- {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/SuperscriptMessage/SuperscriptMessage.tsx","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
1
+ {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/ImagePreview/ImagePreview.test.tsx","../src/ImagePreview/ImagePreview.tsx","../src/ImagePreview/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/SuperscriptMessage/SuperscriptMessage.tsx","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/chatbot",
3
- "version": "6.4.0-prerelease.20",
3
+ "version": "6.4.0-prerelease.21",
4
4
  "description": "This library provides React components based on PatternFly 6 that can be used to build chatbots.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -19,7 +19,7 @@ export const AttachmentEditModalExample: FunctionComponent = () => {
19
19
  id="modal-compact-edit"
20
20
  name="modal-compact-edit"
21
21
  ></Checkbox>
22
- <Button onClick={handleModalToggle}>Launch modal</Button>
22
+ <Button onClick={handleModalToggle}>Launch attachment edit modal</Button>
23
23
  <AttachmentEdit
24
24
  code="I am a code snippet"
25
25
  fileName="test.yaml"
@@ -0,0 +1,53 @@
1
+ import { useState, FunctionComponent, MouseEvent as ReactMouseEvent } from 'react';
2
+ import { Button, Checkbox } from '@patternfly/react-core';
3
+ import ImagePreview from '@patternfly/chatbot/dist/dynamic/ImagePreview';
4
+ import filePreview from './file-preview.svg';
5
+
6
+ export const AttachmentEditModalExample: FunctionComponent = () => {
7
+ const [isModalOpen, setIsModalOpen] = useState(false);
8
+ const [isCompact, setIsCompact] = useState(false);
9
+ const [hasNav, setHasNav] = useState(false);
10
+
11
+ const handleModalToggle = (_event: ReactMouseEvent | MouseEvent | KeyboardEvent) => {
12
+ setIsModalOpen(!isModalOpen);
13
+ };
14
+
15
+ return (
16
+ <>
17
+ <Checkbox
18
+ label="Show multiple images"
19
+ isChecked={hasNav}
20
+ onChange={() => setHasNav(!hasNav)}
21
+ id="modal-compact-image-has-nav"
22
+ name="modal-compact-image-has-nav"
23
+ ></Checkbox>
24
+ <Checkbox
25
+ label="Show compact version"
26
+ isChecked={isCompact}
27
+ onChange={() => setIsCompact(!isCompact)}
28
+ id="modal-compact-image-preview"
29
+ name="modal-compact-image-preview"
30
+ ></Checkbox>
31
+ <Button onClick={handleModalToggle}>Launch image preview modal</Button>
32
+ <ImagePreview
33
+ isModalOpen={isModalOpen}
34
+ handleModalToggle={handleModalToggle}
35
+ isCompact={isCompact}
36
+ onCloseFileDetailsLabel={() => {
37
+ // eslint-disable-next-line no-console
38
+ console.log('Clicked close button');
39
+ }}
40
+ images={
41
+ hasNav
42
+ ? /* eslint-disable indent */
43
+ [
44
+ { fileName: 'image1.png', fileSize: '134KB', image: <img src={filePreview} alt="Preview one" /> },
45
+ { fileName: 'image2.png', fileSize: '134KB', image: <img src={filePreview} alt="Preview two" /> }
46
+ ]
47
+ : [{ fileName: 'image.png', fileSize: '134KB', image: <img src={filePreview} alt="One" /> }]
48
+ /* eslint-enable indent */
49
+ }
50
+ ></ImagePreview>
51
+ </>
52
+ );
53
+ };