@patternfly/chatbot 2.2.0-prerelease.11 → 2.2.0-prerelease.13

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 (93) hide show
  1. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +3 -1
  2. package/dist/cjs/ChatbotHeader/ChatbotHeaderCloseButton.js +3 -1
  3. package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.js +3 -1
  4. package/dist/cjs/ChatbotHeader/ChatbotHeaderOptionsDropdown.js +3 -1
  5. package/dist/cjs/ChatbotHeader/ChatbotHeaderSelectorDropdown.js +3 -1
  6. package/dist/cjs/ChatbotToggle/ChatbotToggle.js +3 -1
  7. package/dist/cjs/Message/Message.d.ts +12 -1
  8. package/dist/cjs/Message/Message.js +11 -6
  9. package/dist/cjs/Message/QuickResponse/QuickResponse.d.ts +3 -1
  10. package/dist/cjs/Message/QuickResponse/QuickResponse.js +2 -1
  11. package/dist/cjs/Message/UserFeedback/CloseButton.d.ts +10 -0
  12. package/dist/cjs/Message/UserFeedback/CloseButton.js +14 -0
  13. package/dist/cjs/Message/UserFeedback/UserFeedback.d.ts +39 -0
  14. package/dist/cjs/Message/UserFeedback/UserFeedback.js +55 -0
  15. package/dist/cjs/Message/UserFeedback/UserFeedback.test.d.ts +1 -0
  16. package/dist/cjs/Message/UserFeedback/UserFeedback.test.js +146 -0
  17. package/dist/cjs/Message/UserFeedback/UserFeedbackComplete.d.ts +42 -0
  18. package/dist/cjs/Message/UserFeedback/UserFeedbackComplete.js +117 -0
  19. package/dist/cjs/Message/UserFeedback/UserFeedbackComplete.test.d.ts +1 -0
  20. package/dist/cjs/Message/UserFeedback/UserFeedbackComplete.test.js +249 -0
  21. package/dist/cjs/MessageBar/AttachButton.js +3 -1
  22. package/dist/cjs/MessageBar/SendButton.js +3 -1
  23. package/dist/cjs/MessageBar/StopButton.js +3 -1
  24. package/dist/cjs/ResponseActions/ResponseActionButton.d.ts +4 -1
  25. package/dist/cjs/ResponseActions/ResponseActionButton.js +21 -6
  26. package/dist/cjs/ResponseActions/ResponseActions.d.ts +8 -2
  27. package/dist/cjs/ResponseActions/ResponseActions.js +7 -7
  28. package/dist/css/main.css +69 -11
  29. package/dist/css/main.css.map +1 -1
  30. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +3 -1
  31. package/dist/esm/ChatbotHeader/ChatbotHeaderCloseButton.js +3 -1
  32. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +3 -1
  33. package/dist/esm/ChatbotHeader/ChatbotHeaderOptionsDropdown.js +3 -1
  34. package/dist/esm/ChatbotHeader/ChatbotHeaderSelectorDropdown.js +3 -1
  35. package/dist/esm/ChatbotToggle/ChatbotToggle.js +3 -1
  36. package/dist/esm/Message/Message.d.ts +12 -1
  37. package/dist/esm/Message/Message.js +8 -3
  38. package/dist/esm/Message/QuickResponse/QuickResponse.d.ts +3 -1
  39. package/dist/esm/Message/QuickResponse/QuickResponse.js +2 -1
  40. package/dist/esm/Message/UserFeedback/CloseButton.d.ts +10 -0
  41. package/dist/esm/Message/UserFeedback/CloseButton.js +9 -0
  42. package/dist/esm/Message/UserFeedback/UserFeedback.d.ts +39 -0
  43. package/dist/esm/Message/UserFeedback/UserFeedback.js +50 -0
  44. package/dist/esm/Message/UserFeedback/UserFeedback.test.d.ts +1 -0
  45. package/dist/esm/Message/UserFeedback/UserFeedback.test.js +141 -0
  46. package/dist/esm/Message/UserFeedback/UserFeedbackComplete.d.ts +42 -0
  47. package/dist/esm/Message/UserFeedback/UserFeedbackComplete.js +112 -0
  48. package/dist/esm/Message/UserFeedback/UserFeedbackComplete.test.d.ts +1 -0
  49. package/dist/esm/Message/UserFeedback/UserFeedbackComplete.test.js +244 -0
  50. package/dist/esm/MessageBar/AttachButton.js +3 -1
  51. package/dist/esm/MessageBar/SendButton.js +3 -1
  52. package/dist/esm/MessageBar/StopButton.js +3 -1
  53. package/dist/esm/ResponseActions/ResponseActionButton.d.ts +4 -1
  54. package/dist/esm/ResponseActions/ResponseActionButton.js +18 -3
  55. package/dist/esm/ResponseActions/ResponseActions.d.ts +8 -2
  56. package/dist/esm/ResponseActions/ResponseActions.js +7 -7
  57. package/dist/tsconfig.tsbuildinfo +1 -1
  58. package/package.json +1 -1
  59. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithFeedback.tsx +71 -0
  60. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithFeedbackTimeout.tsx +27 -0
  61. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +37 -7
  62. package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +3 -6
  63. package/patternfly-docs/content/extensions/chatbot/examples/demos/AttachmentDemos.md +14 -0
  64. package/patternfly-docs/content/extensions/chatbot/examples/demos/Feedback.tsx +104 -0
  65. package/src/AttachMenu/AttachMenu.scss +1 -1
  66. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +7 -1
  67. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +8 -1
  68. package/src/ChatbotHeader/ChatbotHeaderCloseButton.tsx +7 -1
  69. package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +7 -1
  70. package/src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx +8 -1
  71. package/src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx +8 -1
  72. package/src/ChatbotModal/ChatbotModal.scss +1 -1
  73. package/src/ChatbotToggle/ChatbotToggle.tsx +6 -1
  74. package/src/CodeModal/CodeModal.scss +1 -1
  75. package/src/FileDetails/FileDetails.scss +1 -1
  76. package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +1 -1
  77. package/src/Message/Message.scss +1 -1
  78. package/src/Message/Message.tsx +24 -2
  79. package/src/Message/QuickResponse/QuickResponse.tsx +6 -2
  80. package/src/Message/UserFeedback/CloseButton.tsx +21 -0
  81. package/src/Message/UserFeedback/UserFeedback.scss +53 -0
  82. package/src/Message/UserFeedback/UserFeedback.test.tsx +257 -0
  83. package/src/Message/UserFeedback/UserFeedback.tsx +132 -0
  84. package/src/Message/UserFeedback/UserFeedbackComplete.test.tsx +255 -0
  85. package/src/Message/UserFeedback/UserFeedbackComplete.tsx +211 -0
  86. package/src/MessageBar/AttachButton.tsx +2 -0
  87. package/src/MessageBar/SendButton.tsx +2 -0
  88. package/src/MessageBar/StopButton.tsx +2 -0
  89. package/src/ResponseActions/ResponseActionButton.tsx +14 -2
  90. package/src/ResponseActions/ResponseActions.tsx +26 -2
  91. package/src/Settings/Settings.scss +2 -2
  92. package/src/SourceDetailsMenuItem/SourceDetailsMenuItem.scss +1 -1
  93. package/src/main.scss +1 -0
@@ -13,7 +13,9 @@ const react_core_1 = require("@patternfly/react-core");
13
13
  const ellipsis_v_icon_1 = __importDefault(require("@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon"));
14
14
  const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, onSelect, label }) => {
15
15
  const [isOpen, setIsOpen] = react_1.default.useState(false);
16
- const toggle = (toggleRef) => (react_1.default.createElement(react_core_1.Tooltip, { className: "pf-chatbot__tooltip", content: label !== null && label !== void 0 ? label : 'Conversation options', position: "bottom" },
16
+ const toggle = (toggleRef) => (react_1.default.createElement(react_core_1.Tooltip, { className: "pf-chatbot__tooltip", content: label !== null && label !== void 0 ? label : 'Conversation options', position: "bottom",
17
+ // prevents VO announcements of both aria label and tooltip
18
+ aria: "none" },
17
19
  react_1.default.createElement(react_core_1.MenuToggle, { className: "pf-chatbot__history-actions", variant: "plain", "aria-label": label !== null && label !== void 0 ? label : 'Conversation options', ref: toggleRef, isExpanded: isOpen, onClick: () => setIsOpen(!isOpen), role: "menuitem" },
18
20
  react_1.default.createElement(ellipsis_v_icon_1.default, null))));
19
21
  return (react_1.default.createElement(react_core_1.Dropdown, { className: `pf-chatbot__selections ${menuClassName !== null && menuClassName !== void 0 ? menuClassName : ''}`, isOpen: isOpen, onSelect: (props) => {
@@ -8,7 +8,9 @@ const react_1 = __importDefault(require("react"));
8
8
  const react_core_1 = require("@patternfly/react-core");
9
9
  const react_icons_1 = require("@patternfly/react-icons");
10
10
  const ChatbotHeaderCloseButtonBase = ({ className, onClick, tooltipProps, menuAriaLabel = 'Close', innerRef, tooltipContent = 'Close' }) => (react_1.default.createElement("div", { className: `pf-chatbot__menu ${className}` },
11
- react_1.default.createElement(react_core_1.Tooltip, Object.assign({ content: tooltipContent, position: "bottom" }, tooltipProps),
11
+ react_1.default.createElement(react_core_1.Tooltip, Object.assign({ content: tooltipContent, position: "bottom",
12
+ // prevents VO announcements of both aria label and tooltip
13
+ aria: "none" }, tooltipProps),
12
14
  react_1.default.createElement(react_core_1.Button, { className: "pf-chatbot__button--toggle-menu", variant: "plain", onClick: onClick, "aria-label": menuAriaLabel, ref: innerRef, icon: react_1.default.createElement(react_core_1.Icon, { size: "xl", isInline: true },
13
15
  react_1.default.createElement(react_icons_1.CloseIcon, null)) }))));
14
16
  exports.ChatbotHeaderCloseButton = react_1.default.forwardRef((props, ref) => (react_1.default.createElement(ChatbotHeaderCloseButtonBase, Object.assign({ innerRef: ref }, props))));
@@ -8,7 +8,9 @@ const react_1 = __importDefault(require("react"));
8
8
  const react_core_1 = require("@patternfly/react-core");
9
9
  const bars_icon_1 = __importDefault(require("@patternfly/react-icons/dist/esm/icons/bars-icon"));
10
10
  const ChatbotHeaderMenuBase = ({ className, onMenuToggle, tooltipProps, menuAriaLabel = 'Toggle menu', innerRef, tooltipContent = 'Menu' }) => (react_1.default.createElement("div", { className: `pf-chatbot__menu ${className}` },
11
- react_1.default.createElement(react_core_1.Tooltip, Object.assign({ content: tooltipContent, position: "bottom" }, tooltipProps),
11
+ react_1.default.createElement(react_core_1.Tooltip, Object.assign({ content: tooltipContent, position: "bottom",
12
+ // prevents VO announcements of both aria label and tooltip
13
+ aria: "none" }, tooltipProps),
12
14
  react_1.default.createElement(react_core_1.Button, { className: "pf-chatbot__button--toggle-menu", variant: "plain", onClick: onMenuToggle, "aria-label": menuAriaLabel, ref: innerRef, icon: react_1.default.createElement(react_core_1.Icon, { size: "xl", isInline: true },
13
15
  react_1.default.createElement(bars_icon_1.default, null)) }))));
14
16
  exports.ChatbotHeaderMenu = react_1.default.forwardRef((props, ref) => (react_1.default.createElement(ChatbotHeaderMenuBase, Object.assign({ innerRef: ref }, props))));
@@ -21,7 +21,9 @@ const ellipsis_v_icon_1 = __importDefault(require("@patternfly/react-icons/dist/
21
21
  const ChatbotHeaderOptionsDropdown = (_a) => {
22
22
  var { className, children, onSelect, tooltipProps, menuToggleAriaLabel = 'Chatbot options' } = _a, props = __rest(_a, ["className", "children", "onSelect", "tooltipProps", "menuToggleAriaLabel"]);
23
23
  const [isOptionsMenuOpen, setIsOptionsMenuOpen] = react_1.default.useState(false);
24
- const toggle = (toggleRef) => (react_1.default.createElement(react_core_1.Tooltip, Object.assign({ className: "pf-chatbot__tooltip", content: "Chatbot options", position: "bottom" }, tooltipProps),
24
+ const toggle = (toggleRef) => (react_1.default.createElement(react_core_1.Tooltip, Object.assign({ className: "pf-chatbot__tooltip", content: "Chatbot options", position: "bottom",
25
+ // prevents VO announcements of both aria label and tooltip
26
+ aria: "none" }, tooltipProps),
25
27
  react_1.default.createElement(react_core_1.MenuToggle, { className: "pf-chatbot__button--toggle-options", variant: "plain", "aria-label": menuToggleAriaLabel, ref: toggleRef, icon: react_1.default.createElement(react_core_1.Icon, { iconSize: "xl", isInline: true },
26
28
  react_1.default.createElement(ellipsis_v_icon_1.default, null)), isExpanded: isOptionsMenuOpen, onClick: () => setIsOptionsMenuOpen(!isOptionsMenuOpen) })));
27
29
  return (react_1.default.createElement(react_core_1.Dropdown, Object.assign({ className: `pf-chatbot__options ${className !== null && className !== void 0 ? className : ''}`, isOpen: isOptionsMenuOpen, onSelect: (e, value) => {
@@ -21,7 +21,9 @@ const ChatbotHeaderSelectorDropdown = (_a) => {
21
21
  var { value, className, children, onSelect, tooltipProps, tooltipContent = 'Chatbot selector', menuToggleAriaLabel } = _a, props = __rest(_a, ["value", "className", "children", "onSelect", "tooltipProps", "tooltipContent", "menuToggleAriaLabel"]);
22
22
  const [isOptionsMenuOpen, setIsOptionsMenuOpen] = react_1.default.useState(false);
23
23
  const [defaultAriaLabel, setDefaultAriaLabel] = react_1.default.useState('Chatbot selector');
24
- const toggle = (toggleRef) => (react_1.default.createElement(react_core_1.Tooltip, Object.assign({ className: "pf-chatbot__tooltip", content: tooltipContent, position: "bottom" }, tooltipProps),
24
+ const toggle = (toggleRef) => (react_1.default.createElement(react_core_1.Tooltip, Object.assign({ className: "pf-chatbot__tooltip", content: tooltipContent, position: "bottom",
25
+ // prevents VO announcements of both aria label and tooltip
26
+ aria: "none" }, tooltipProps),
25
27
  react_1.default.createElement(react_core_1.MenuToggle, { variant: "secondary", "aria-label": menuToggleAriaLabel !== null && menuToggleAriaLabel !== void 0 ? menuToggleAriaLabel : defaultAriaLabel, ref: toggleRef, isExpanded: isOptionsMenuOpen, onClick: () => setIsOptionsMenuOpen(!isOptionsMenuOpen) }, value)));
26
28
  return (react_1.default.createElement(react_core_1.Dropdown, Object.assign({ className: `pf-chatbot__selections ${className !== null && className !== void 0 ? className : ''}`, isOpen: isOptionsMenuOpen, onSelect: (e, value) => {
27
29
  onSelect && onSelect(e, value);
@@ -28,7 +28,9 @@ const ChatbotToggleBase = (_a) => {
28
28
  // Configure icon
29
29
  const closedIcon = ClosedToggleIcon ? react_1.default.createElement(ClosedToggleIcon, null) : react_1.default.createElement(ChatIcon, null);
30
30
  const icon = isChatbotVisible ? react_1.default.createElement(angle_down_icon_1.default, { "data-testid": openIconTestId }) : closedIcon;
31
- return (react_1.default.createElement(react_core_1.Tooltip, Object.assign({ content: tooltipLabel }, tooltipProps),
31
+ return (react_1.default.createElement(react_core_1.Tooltip, Object.assign({ content: tooltipLabel,
32
+ // prevents VO announcements of both aria label and tooltip
33
+ aria: "none" }, tooltipProps),
32
34
  react_1.default.createElement(react_core_1.Button, Object.assign({ className: `pf-chatbot__button ${isChatbotVisible ? 'pf-chatbot__button--active' : ''} ${isRound ? 'pf-chatbot__button--round' : ''} ${className ? className : ''}`, variant: "plain", "aria-label": toggleButtonLabel || `${tooltipLabel} toggle`, onClick: onToggleChatbot, "aria-expanded": isChatbotVisible, icon: react_1.default.createElement(react_core_1.Icon, { isInline: true }, icon), ref: innerRef }, props))));
33
35
  };
34
36
  const ChatbotToggle = react_1.default.forwardRef((props, ref) => (react_1.default.createElement(ChatbotToggleBase, Object.assign({ innerRef: ref }, props))));
@@ -4,6 +4,8 @@ import { ActionProps } from '../ResponseActions/ResponseActions';
4
4
  import { SourcesCardProps } from '../SourcesCard';
5
5
  import { QuickStart, QuickstartAction } from './QuickStarts/types';
6
6
  import QuickResponse from './QuickResponse/QuickResponse';
7
+ import { UserFeedbackProps } from './UserFeedback/UserFeedback';
8
+ import { UserFeedbackCompleteProps } from './UserFeedback/UserFeedbackComplete';
7
9
  export interface MessageAttachment {
8
10
  /** Name of file attached to the message */
9
11
  name: string;
@@ -57,6 +59,10 @@ export interface MessageProps extends Omit<React.HTMLProps<HTMLDivElement>, 'rol
57
59
  quickResponses?: QuickResponse[];
58
60
  /** Props for quick responses container */
59
61
  quickResponseContainerProps?: Omit<LabelGroupProps, 'ref'>;
62
+ /** Props for user feedback card */
63
+ userFeedbackForm?: Omit<UserFeedbackProps, 'ref'>;
64
+ /** Props for user feedback response */
65
+ userFeedbackComplete?: Omit<UserFeedbackCompleteProps, 'ref'>;
60
66
  /** Whether avatar is round */
61
67
  hasRoundAvatar?: boolean;
62
68
  /** Any additional props applied to the avatar, for additional customization */
@@ -74,6 +80,11 @@ export interface MessageProps extends Omit<React.HTMLProps<HTMLDivElement>, 'rol
74
80
  onClick?: () => void;
75
81
  action?: QuickstartAction;
76
82
  };
83
+ /** Turns the container into a live region so that changes to content within the Message, such as appending a feedback card, are reliably announced to assistive technology. */
84
+ isLiveRegion?: boolean;
85
+ /** Ref applied to message */
86
+ innerRef?: React.Ref<HTMLDivElement>;
77
87
  }
78
- export declare const Message: React.FunctionComponent<MessageProps>;
88
+ export declare const MessageBase: React.FunctionComponent<MessageProps>;
89
+ declare const Message: React.ForwardRefExoticComponent<Omit<MessageProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
79
90
  export default Message;
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.Message = void 0;
20
+ exports.MessageBase = void 0;
21
21
  const react_1 = __importDefault(require("react"));
22
22
  const react_markdown_1 = __importDefault(require("react-markdown"));
23
23
  const remark_gfm_1 = __importDefault(require("remark-gfm"));
@@ -33,8 +33,10 @@ const UnorderedListMessage_1 = __importDefault(require("./ListMessage/UnorderedL
33
33
  const OrderedListMessage_1 = __importDefault(require("./ListMessage/OrderedListMessage"));
34
34
  const QuickStartTile_1 = __importDefault(require("./QuickStarts/QuickStartTile"));
35
35
  const QuickResponse_1 = __importDefault(require("./QuickResponse/QuickResponse"));
36
- const Message = (_a) => {
37
- var { role, content, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps, quickStarts } = _a, props = __rest(_a, ["role", "content", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps", "quickStarts"]);
36
+ const UserFeedback_1 = __importDefault(require("./UserFeedback/UserFeedback"));
37
+ const UserFeedbackComplete_1 = __importDefault(require("./UserFeedback/UserFeedbackComplete"));
38
+ const MessageBase = (_a) => {
39
+ var { role, content, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps, quickStarts, userFeedbackForm, userFeedbackComplete, isLiveRegion = true, innerRef } = _a, props = __rest(_a, ["role", "content", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps", "quickStarts", "userFeedbackForm", "userFeedbackComplete", "isLiveRegion", "innerRef"]);
38
40
  let avatarClassName;
39
41
  if (avatarProps && 'className' in avatarProps) {
40
42
  const { className } = avatarProps, rest = __rest(avatarProps, ["className"]);
@@ -44,7 +46,7 @@ const Message = (_a) => {
44
46
  // Keep timestamps consistent between Timestamp component and aria-label
45
47
  const date = new Date();
46
48
  const dateString = timestamp !== null && timestamp !== void 0 ? timestamp : `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
47
- return (react_1.default.createElement("section", Object.assign({ "aria-label": `Message from ${role} - ${dateString}`, className: `pf-chatbot__message pf-chatbot__message--${role}` }, props),
49
+ return (react_1.default.createElement("section", Object.assign({ "aria-label": `Message from ${role} - ${dateString}`, className: `pf-chatbot__message pf-chatbot__message--${role}`, "aria-live": isLiveRegion ? 'polite' : undefined, "aria-atomic": isLiveRegion ? false : undefined, ref: innerRef }, props),
48
50
  react_1.default.createElement(react_core_1.Avatar, Object.assign({ className: `pf-chatbot__message-avatar ${hasRoundAvatar ? 'pf-chatbot__message-avatar--round' : ''} ${avatarClassName ? avatarClassName : ''}`, src: avatar, alt: "" }, avatarProps)),
49
51
  react_1.default.createElement("div", { className: "pf-chatbot__message-contents" },
50
52
  react_1.default.createElement("div", { className: "pf-chatbot__message-meta" },
@@ -64,6 +66,8 @@ const Message = (_a) => {
64
66
  !isLoading && sources && react_1.default.createElement(SourcesCard_1.default, Object.assign({}, sources)),
65
67
  quickStarts && quickStarts.quickStart && (react_1.default.createElement(QuickStartTile_1.default, { quickStart: quickStarts.quickStart, onSelectQuickStart: quickStarts.onSelectQuickStart, minuteWord: quickStarts.minuteWord, minuteWordPlural: quickStarts.minuteWordPlural, prerequisiteWord: quickStarts.prerequisiteWord, prerequisiteWordPlural: quickStarts.prerequisiteWordPlural, quickStartButtonAriaLabel: quickStarts.quickStartButtonAriaLabel })),
66
68
  !isLoading && actions && react_1.default.createElement(ResponseActions_1.default, { actions: actions }),
69
+ userFeedbackForm && react_1.default.createElement(UserFeedback_1.default, Object.assign({}, userFeedbackForm, { timestamp: dateString })),
70
+ userFeedbackComplete && react_1.default.createElement(UserFeedbackComplete_1.default, Object.assign({}, userFeedbackComplete, { timestamp: dateString })),
67
71
  !isLoading && quickResponses && (react_1.default.createElement(QuickResponse_1.default, { quickResponses: quickResponses, quickResponseContainerProps: quickResponseContainerProps }))),
68
72
  attachments && (react_1.default.createElement("div", { className: "pf-chatbot__message-attachments-container" }, attachments.map((attachment) => {
69
73
  var _a;
@@ -71,5 +75,6 @@ const Message = (_a) => {
71
75
  react_1.default.createElement(FileDetailsLabel_1.default, { fileName: attachment.name, fileId: attachment.id, onClose: attachment.onClose, onClick: attachment.onClick, isLoading: attachment.isLoading, closeButtonAriaLabel: attachment.closeButtonAriaLabel, languageTestId: attachment.languageTestId, spinnerTestId: attachment.spinnerTestId })));
72
76
  })))))));
73
77
  };
74
- exports.Message = Message;
75
- exports.default = exports.Message;
78
+ exports.MessageBase = MessageBase;
79
+ const Message = react_1.default.forwardRef((props, ref) => (react_1.default.createElement(exports.MessageBase, Object.assign({ innerRef: ref }, props))));
80
+ exports.default = Message;
@@ -3,13 +3,15 @@ import { LabelGroupProps, LabelProps } from '@patternfly/react-core';
3
3
  export interface QuickResponse extends Omit<LabelProps, 'children'> {
4
4
  content: string;
5
5
  id: string;
6
- onClick: () => void;
6
+ onClick?: () => void;
7
7
  }
8
8
  export interface QuickResponseProps {
9
9
  /** Props for quick responses */
10
10
  quickResponses: QuickResponse[];
11
11
  /** Props for quick responses container */
12
12
  quickResponseContainerProps?: Omit<LabelGroupProps, 'ref'>;
13
+ /** Callback when a response is clicked; used in feedback cards */
14
+ onSelect?: (id: string) => void;
13
15
  }
14
16
  export declare const QuickResponse: React.FunctionComponent<QuickResponseProps>;
15
17
  export default QuickResponse;
@@ -18,11 +18,12 @@ exports.QuickResponse = void 0;
18
18
  const react_1 = __importDefault(require("react"));
19
19
  const react_core_1 = require("@patternfly/react-core");
20
20
  const react_icons_1 = require("@patternfly/react-icons");
21
- const QuickResponse = ({ quickResponses, quickResponseContainerProps = { numLabels: 5 } }) => {
21
+ const QuickResponse = ({ quickResponses, quickResponseContainerProps = { numLabels: 5 }, onSelect }) => {
22
22
  const [selectedQuickResponse, setSelectedQuickResponse] = react_1.default.useState();
23
23
  const handleQuickResponseClick = (id, onClick) => {
24
24
  setSelectedQuickResponse(id);
25
25
  onClick && onClick();
26
+ onSelect && onSelect(id);
26
27
  };
27
28
  return (react_1.default.createElement(react_core_1.LabelGroup, Object.assign({ className: `pf-chatbot__message-quick-response ${quickResponseContainerProps === null || quickResponseContainerProps === void 0 ? void 0 : quickResponseContainerProps.className}` }, quickResponseContainerProps), quickResponses.map((_a) => {
28
29
  var { id, onClick, content, className } = _a, props = __rest(_a, ["id", "onClick", "content", "className"]);
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { ButtonProps } from '@patternfly/react-core';
3
+ export interface CloseButtonProps extends ButtonProps {
4
+ /** Callback function for when close button is clicked */
5
+ onClose?: () => void;
6
+ /** Aria-label for button */
7
+ ariaLabel?: string;
8
+ }
9
+ declare const CloseButton: React.FunctionComponent<CloseButtonProps>;
10
+ export default CloseButton;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // ============================================================================
7
+ // Chatbot Main - Messages - Close Button
8
+ // ============================================================================
9
+ const react_1 = __importDefault(require("react"));
10
+ // Import PatternFly components
11
+ const react_core_1 = require("@patternfly/react-core");
12
+ const react_icons_1 = require("@patternfly/react-icons");
13
+ const CloseButton = ({ onClose, ariaLabel }) => (react_1.default.createElement(react_core_1.Button, { variant: "plain", onClick: onClose, icon: react_1.default.createElement(react_icons_1.CloseIcon, null), "aria-label": ariaLabel }));
14
+ exports.default = CloseButton;
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { CardProps, LabelGroupProps, OUIAProps } from '@patternfly/react-core';
3
+ import QuickResponse from '../QuickResponse/QuickResponse';
4
+ export interface UserFeedbackProps extends Omit<CardProps, 'onSubmit'>, OUIAProps {
5
+ /** Additional classes for the pagination navigation container. */
6
+ className?: string;
7
+ /** Quick responses a user can select */
8
+ quickResponses?: QuickResponse[];
9
+ /** Props for quick responses container */
10
+ quickResponseContainerProps?: Omit<LabelGroupProps, 'ref'>;
11
+ /** Whether form includes text area */
12
+ hasTextArea?: boolean;
13
+ /** Placeholder of text area */
14
+ textAreaPlaceholder?: string;
15
+ /** Aria label for text area */
16
+ textAreaAriaLabel?: string;
17
+ /** Callback function for when text area changes */
18
+ onTextAreaChange?: (event: React.ChangeEvent<HTMLTextAreaElement>, value: string) => void;
19
+ /** Callback function for when form is submitted */
20
+ onSubmit: (selectedResponse?: string, additionalFeedback?: string) => void;
21
+ /** Callback function for when close button is clicked */
22
+ onClose: () => void;
23
+ /** Aria label for close button */
24
+ closeButtonAriaLabel?: string;
25
+ /** Label for the English word "Submit." */
26
+ submitWord?: string;
27
+ /** Label for the English word "Cancel." */
28
+ cancelWord?: string;
29
+ /** Uniquely identifies the card. */
30
+ id?: string;
31
+ /** The heading level to use, default is h1 */
32
+ headingLevel?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
33
+ /** Whether to focus card on load */
34
+ focusOnLoad?: boolean;
35
+ /** Timestamp passed in by Message for more context in aria announcements */
36
+ timestamp?: string;
37
+ }
38
+ declare const UserFeedback: React.FunctionComponent<UserFeedbackProps>;
39
+ export default UserFeedback;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ // ============================================================================
18
+ // Chatbot Main - Messages - Feedback Card
19
+ // ============================================================================
20
+ const react_1 = __importDefault(require("react"));
21
+ // Import PatternFly components
22
+ const react_core_1 = require("@patternfly/react-core");
23
+ const QuickResponse_1 = __importDefault(require("../QuickResponse/QuickResponse"));
24
+ const CloseButton_1 = __importDefault(require("./CloseButton"));
25
+ const UserFeedback = (_a) => {
26
+ var { className, timestamp, title = 'Why did you choose this rating?', hasTextArea, textAreaAriaLabel = `Provide optional additional feedback for message received at ${timestamp}`, textAreaPlaceholder = 'Provide optional additional feedback', onTextAreaChange, submitWord = 'Submit', quickResponses, quickResponseContainerProps = { 'aria-label': `Quick feedback for message received at ${timestamp}` }, onSubmit, onClose, closeButtonAriaLabel = `Close feedback for message received at ${timestamp}`, id, headingLevel: HeadingLevel = 'h1', focusOnLoad = true, cancelWord = 'Cancel' } = _a, props = __rest(_a, ["className", "timestamp", "title", "hasTextArea", "textAreaAriaLabel", "textAreaPlaceholder", "onTextAreaChange", "submitWord", "quickResponses", "quickResponseContainerProps", "onSubmit", "onClose", "closeButtonAriaLabel", "id", "headingLevel", "focusOnLoad", "cancelWord"]);
27
+ const [selectedResponse, setSelectedResponse] = react_1.default.useState();
28
+ const [value, setValue] = react_1.default.useState('');
29
+ const divRef = react_1.default.useRef(null);
30
+ react_1.default.useEffect(() => {
31
+ var _a;
32
+ if (focusOnLoad) {
33
+ (_a = divRef.current) === null || _a === void 0 ? void 0 : _a.focus();
34
+ }
35
+ }, []);
36
+ return (
37
+ /* card does not have ref forwarding; hence wrapper div */
38
+ react_1.default.createElement("div", { ref: divRef, id: id, tabIndex: 0, "aria-label": title },
39
+ react_1.default.createElement(react_core_1.Card, Object.assign({ className: `pf-chatbot__feedback-card ${className ? className : ''}` }, props),
40
+ react_1.default.createElement(react_core_1.CardHeader, { actions: {
41
+ actions: react_1.default.createElement(CloseButton_1.default, { onClose: onClose, ariaLabel: closeButtonAriaLabel })
42
+ } },
43
+ react_1.default.createElement(HeadingLevel, { className: "pf-chatbot__feedback-card-title" }, title)),
44
+ react_1.default.createElement(react_core_1.CardBody, null,
45
+ react_1.default.createElement(react_core_1.Form, { className: "pf-chatbot__feedback-card-form" },
46
+ quickResponses && (react_1.default.createElement(QuickResponse_1.default, { quickResponses: quickResponses, quickResponseContainerProps: quickResponseContainerProps, onSelect: (id) => setSelectedResponse(id) })),
47
+ hasTextArea && (react_1.default.createElement(react_core_1.TextArea, { value: value, onChange: (_event, value) => {
48
+ setValue(value);
49
+ onTextAreaChange && onTextAreaChange(_event, value);
50
+ }, placeholder: textAreaPlaceholder, "aria-label": textAreaAriaLabel, resizeOrientation: "vertical" })),
51
+ react_1.default.createElement(react_core_1.ActionGroup, null,
52
+ react_1.default.createElement(react_core_1.Button, { onClick: () => onSubmit(selectedResponse, value) }, submitWord),
53
+ react_1.default.createElement(react_core_1.Button, { variant: "link", onClick: onClose }, cancelWord)))))));
54
+ };
55
+ exports.default = UserFeedback;
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const react_1 = __importDefault(require("react"));
16
+ const react_2 = require("@testing-library/react");
17
+ require("@testing-library/jest-dom");
18
+ const user_event_1 = __importDefault(require("@testing-library/user-event"));
19
+ const UserFeedback_1 = __importDefault(require("./UserFeedback"));
20
+ const MOCK_RESPONSES = [
21
+ { id: '1', content: 'Helpful information', onClick: () => alert('Clicked helpful information') },
22
+ { id: '2', content: 'Easy to understand', onClick: () => alert('Clicked easy to understand') },
23
+ { id: '3', content: 'Resolved my issue', onClick: () => alert('Clicked resolved my issue') }
24
+ ];
25
+ describe('UserFeedback', () => {
26
+ it('should render correctly', () => {
27
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, timestamp: "12/12/12" }));
28
+ expect(react_2.screen.getByRole('heading', { name: /Why did you choose this rating?/i })).toBeTruthy();
29
+ expect(react_2.screen.getByRole('list', { name: 'Quick feedback for message received at 12/12/12' })).toBeTruthy();
30
+ expect(react_2.screen.getByRole('button', { name: /Helpful information/i })).toBeTruthy();
31
+ expect(react_2.screen.getByRole('button', { name: /Easy to understand/i })).toBeTruthy();
32
+ expect(react_2.screen.getByRole('button', { name: /Resolved my issue/i })).toBeTruthy();
33
+ expect(react_2.screen.getByRole('button', { name: /Submit/i })).toBeTruthy();
34
+ expect(react_2.screen.getByRole('button', { name: 'Close feedback for message received at 12/12/12' })).toBeTruthy();
35
+ expect(react_2.screen.getByRole('button', { name: /Cancel/i })).toBeTruthy();
36
+ expect(react_2.screen.queryByRole('textbox', { name: /Provide optional additional feedback/i })).toBeFalsy();
37
+ });
38
+ it('should render different title correctly', () => {
39
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, title: "Thanks! Why?" }));
40
+ expect(react_2.screen.getByText('Thanks! Why?')).toBeTruthy();
41
+ });
42
+ it('should render different submit button text correctly', () => {
43
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, submitWord: "Give feedback" }));
44
+ expect(react_2.screen.getByRole('button', { name: /Give feedback/i })).toBeTruthy();
45
+ });
46
+ it('should render text area correctly', () => {
47
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, hasTextArea: true }));
48
+ expect(react_2.screen.getByRole('textbox', { name: /Provide optional additional feedback/i })).toBeTruthy();
49
+ });
50
+ it('should call onTextAreaChange correctly', () => __awaiter(void 0, void 0, void 0, function* () {
51
+ const spy = jest.fn();
52
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, hasTextArea: true, onTextAreaChange: spy }));
53
+ const textbox = react_2.screen.getByRole('textbox', { name: /Provide optional additional feedback/i });
54
+ yield user_event_1.default.type(textbox, 'test');
55
+ expect(spy).toHaveBeenCalledTimes(4);
56
+ }));
57
+ it('should render different placeholder correctly', () => {
58
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, hasTextArea: true, textAreaPlaceholder: "Provide any other information" }));
59
+ expect(react_2.screen.getByRole('textbox', { name: /Provide optional additional feedback/i })).toHaveAttribute('placeholder', 'Provide any other information');
60
+ });
61
+ it('should render different text area label correctly', () => {
62
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, hasTextArea: true, textAreaAriaLabel: "Provide more details" }));
63
+ expect(react_2.screen.getByRole('textbox', { name: /Provide more details/i })).toBeTruthy();
64
+ });
65
+ it('should handle onClose correctly when close button is clicked', () => __awaiter(void 0, void 0, void 0, function* () {
66
+ const spy = jest.fn();
67
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, onClose: spy, timestamp: "12/12/12" }));
68
+ const closeButton = react_2.screen.getByRole('button', { name: 'Close feedback for message received at 12/12/12' });
69
+ expect(closeButton).toBeTruthy();
70
+ yield user_event_1.default.click(closeButton);
71
+ expect(spy).toHaveBeenCalledTimes(1);
72
+ }));
73
+ it('should be able to change close button aria label', () => {
74
+ const spy = jest.fn();
75
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, onClose: spy, closeButtonAriaLabel: "Ima button" }));
76
+ expect(react_2.screen.getByRole('button', { name: /Ima button/i })).toBeTruthy();
77
+ });
78
+ it('should handle onClose correctly when cancel button is clicked', () => __awaiter(void 0, void 0, void 0, function* () {
79
+ const spy = jest.fn();
80
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, onClose: spy, timestamp: "12/12/12" }));
81
+ const cancelButton = react_2.screen.getByRole('button', { name: 'Cancel' });
82
+ expect(cancelButton).toBeTruthy();
83
+ yield user_event_1.default.click(cancelButton);
84
+ expect(spy).toHaveBeenCalledTimes(1);
85
+ }));
86
+ it('should change cancel word correctly', () => {
87
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, onClose: jest.fn, cancelWord: "Exit", timestamp: "12/12/12" }));
88
+ expect(react_2.screen.getByRole('button', { name: 'Exit' })).toBeTruthy();
89
+ });
90
+ it('should handle className', () => __awaiter(void 0, void 0, void 0, function* () {
91
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, className: "test", "data-testid": "card" }));
92
+ expect(react_2.screen.getByTestId('card')).toHaveClass('test');
93
+ }));
94
+ it('should apply id', () => __awaiter(void 0, void 0, void 0, function* () {
95
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, id: "test", "data-testid": "card" }));
96
+ expect(react_2.screen.getByTestId('card').parentElement).toHaveAttribute('id', 'test');
97
+ }));
98
+ it('should handle submit correctly when nothing is selected', () => __awaiter(void 0, void 0, void 0, function* () {
99
+ const spy = jest.fn();
100
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: spy, quickResponses: MOCK_RESPONSES }));
101
+ yield user_event_1.default.click(react_2.screen.getByRole('button', { name: /Submit/i }));
102
+ expect(spy).toHaveBeenCalledTimes(1);
103
+ expect(spy).toHaveBeenCalledWith(undefined, '');
104
+ }));
105
+ it('should handle submit correctly when item is selected', () => __awaiter(void 0, void 0, void 0, function* () {
106
+ const spy = jest.fn();
107
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: spy, quickResponses: MOCK_RESPONSES }));
108
+ yield user_event_1.default.click(react_2.screen.getByRole('button', { name: /Easy to understand/i }));
109
+ yield user_event_1.default.click(react_2.screen.getByRole('button', { name: /Submit/i }));
110
+ expect(spy).toHaveBeenCalledTimes(1);
111
+ expect(spy).toHaveBeenCalledWith('2', '');
112
+ }));
113
+ it('should handle submit correctly when there is just text input', () => __awaiter(void 0, void 0, void 0, function* () {
114
+ const spy = jest.fn();
115
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: spy, quickResponses: MOCK_RESPONSES, hasTextArea: true }));
116
+ yield user_event_1.default.type(react_2.screen.getByRole('textbox', { name: /Provide optional additional feedback/i }), 'What a great experience!');
117
+ yield user_event_1.default.click(react_2.screen.getByRole('button', { name: /Submit/i }));
118
+ expect(spy).toHaveBeenCalledTimes(1);
119
+ expect(spy).toHaveBeenCalledWith(undefined, 'What a great experience!');
120
+ }));
121
+ it('should handle submit correctly when item is selected and there is text input', () => __awaiter(void 0, void 0, void 0, function* () {
122
+ const spy = jest.fn();
123
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: spy, quickResponses: MOCK_RESPONSES, hasTextArea: true }));
124
+ yield user_event_1.default.click(react_2.screen.getByRole('button', { name: /Easy to understand/i }));
125
+ yield user_event_1.default.type(react_2.screen.getByRole('textbox', { name: /Provide optional additional feedback/i }), 'What a great experience!');
126
+ yield user_event_1.default.click(react_2.screen.getByRole('button', { name: /Submit/i }));
127
+ expect(spy).toHaveBeenCalledTimes(1);
128
+ expect(spy).toHaveBeenCalledWith('2', 'What a great experience!');
129
+ }));
130
+ it('should default title heading level to h1', () => {
131
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES }));
132
+ expect(react_2.screen.getByRole('heading', { level: 1, name: /Why did you choose this rating?/i })).toBeTruthy();
133
+ });
134
+ it('should be able to change title heading level', () => {
135
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, headingLevel: "h6" }));
136
+ expect(react_2.screen.getByRole('heading', { level: 6, name: /Why did you choose this rating?/i })).toBeTruthy();
137
+ });
138
+ it('should focus on load by default', () => {
139
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, "data-testid": "card" }));
140
+ expect(react_2.screen.getByTestId('card').parentElement).toHaveFocus();
141
+ });
142
+ it('should not focus on load if focusOnLoad = false', () => {
143
+ (0, react_2.render)(react_1.default.createElement(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, "data-testid": "card", focusOnLoad: false }));
144
+ expect(react_2.screen.getByTestId('card').parentElement).not.toHaveFocus();
145
+ });
146
+ });
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { CardProps, OUIAProps } from '@patternfly/react-core';
3
+ export interface UserFeedbackCompleteProps extends Omit<CardProps, 'ref'>, OUIAProps {
4
+ /** Additional classes for the pagination navigation container. */
5
+ className?: string;
6
+ /** Substitute for the English phrase "Thank you". */
7
+ title?: string;
8
+ /** Substitute for the English phrase "You have successfully sent your feedback! Thank you for responding." */
9
+ body?: string | React.ReactNode;
10
+ /** Callback function for when close button is clicked */
11
+ onClose?: () => void;
12
+ /** Aria label for close button */
13
+ closeButtonAriaLabel?: string;
14
+ /** Function to be executed on timeout. Relevant when the timeout prop is set. */
15
+ onTimeout?: () => void;
16
+ /** If set to true, the timeout is 8000 milliseconds. If a number is provided, card will
17
+ * be dismissed after that amount of time in milliseconds.
18
+ */
19
+ timeout?: number | boolean;
20
+ /** If the user hovers over the card and `timeout` expires, this is how long to wait
21
+ * before finally dismissing the alert.
22
+ */
23
+ timeoutAnimation?: number;
24
+ /** Callback for when mouse hovers over card */
25
+ onMouseEnter?: (e: React.MouseEvent<HTMLDivElement>) => void;
26
+ /** Callback for when mouse stops hovering over card */
27
+ onMouseLeave?: (e: React.MouseEvent<HTMLDivElement>) => void;
28
+ /** Value to overwrite the randomly generated data-ouia-component-id.*/
29
+ ouiaId?: number | string;
30
+ /** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */
31
+ ouiaSafe?: boolean;
32
+ /** Flag to indicate if the card is in a live region. */
33
+ isLiveRegion?: boolean;
34
+ /** Uniquely identifies the completion card. */
35
+ id?: string;
36
+ /** Whether to focus card on load */
37
+ focusOnLoad?: boolean;
38
+ /** Timestamp passed in by Message for more context in aria announcements */
39
+ timestamp?: string;
40
+ }
41
+ declare const UserFeedbackComplete: React.FunctionComponent<UserFeedbackCompleteProps>;
42
+ export default UserFeedbackComplete;