@patternfly/chatbot 6.3.0-prerelease.11 → 6.3.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.
- package/dist/cjs/MessageBar/MessageBar.js +6 -6
- package/dist/cjs/MessageBar/MessageBar.test.js +20 -0
- package/dist/cjs/ResponseActions/ResponseActionButton.d.ts +2 -2
- package/dist/cjs/ResponseActions/ResponseActions.d.ts +4 -1
- package/dist/cjs/ResponseActions/ResponseActions.js +6 -6
- package/dist/cjs/ResponseActions/ResponseActions.test.js +16 -1
- package/dist/esm/MessageBar/MessageBar.js +6 -6
- package/dist/esm/MessageBar/MessageBar.test.js +20 -0
- package/dist/esm/ResponseActions/ResponseActionButton.d.ts +2 -2
- package/dist/esm/ResponseActions/ResponseActions.d.ts +4 -1
- package/dist/esm/ResponseActions/ResponseActions.js +6 -6
- package/dist/esm/ResponseActions/ResponseActions.test.js +16 -1
- package/package.json +1 -1
- package/src/MessageBar/MessageBar.test.tsx +45 -0
- package/src/MessageBar/MessageBar.tsx +5 -0
- package/src/ResponseActions/ResponseActionButton.tsx +2 -2
- package/src/ResponseActions/ResponseActions.test.tsx +18 -1
- package/src/ResponseActions/ResponseActions.tsx +10 -1
@@ -175,15 +175,15 @@ const MessageBar = (_a) => {
|
|
175
175
|
onChange && onChange({}, message);
|
176
176
|
};
|
177
177
|
const renderButtons = () => {
|
178
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
178
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
179
179
|
if (hasStopButton && handleStopButton) {
|
180
|
-
return (react_1.default.createElement(StopButton_1.default, Object.assign({ onClick: handleStopButton, tooltipContent: (_a = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _a === void 0 ? void 0 : _a.tooltipContent, isCompact: isCompact
|
180
|
+
return (react_1.default.createElement(StopButton_1.default, Object.assign({ onClick: handleStopButton, tooltipContent: (_a = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _a === void 0 ? void 0 : _a.tooltipContent, isCompact: isCompact, tooltipProps: (_b = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _b === void 0 ? void 0 : _b.tooltipProps }, (_c = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _c === void 0 ? void 0 : _c.props)));
|
181
181
|
}
|
182
182
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
183
|
-
attachMenuProps && (react_1.default.createElement(AttachButton_1.AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (
|
184
|
-
!attachMenuProps && hasAttachButton && (react_1.default.createElement(AttachButton_1.AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (
|
185
|
-
hasMicrophoneButton && (react_1.default.createElement(MicrophoneButton_1.default, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (
|
186
|
-
(alwayShowSendButton || message) && (react_1.default.createElement(SendButton_1.default, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (
|
183
|
+
attachMenuProps && (react_1.default.createElement(AttachButton_1.AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps }, (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.props))),
|
184
|
+
!attachMenuProps && hasAttachButton && (react_1.default.createElement(AttachButton_1.AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.tooltipContent, inputTestId: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.inputTestId, isCompact: isCompact, tooltipProps: (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.tooltipProps }, (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _k === void 0 ? void 0 : _k.props))),
|
185
|
+
hasMicrophoneButton && (react_1.default.createElement(MicrophoneButton_1.default, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.tooltipContent, language: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.language, isCompact: isCompact, tooltipProps: (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.tooltipProps }, (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _p === void 0 ? void 0 : _p.props))),
|
186
|
+
(alwayShowSendButton || message) && (react_1.default.createElement(SendButton_1.default, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipContent, isCompact: isCompact, tooltipProps: (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.tooltipProps }, (_s = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _s === void 0 ? void 0 : _s.props)))));
|
187
187
|
};
|
188
188
|
const messageBarContents = (react_1.default.createElement(react_1.default.Fragment, null,
|
189
189
|
react_1.default.createElement("div", { className: `pf-chatbot__message-bar-input ${isCompact ? 'pf-m-compact' : ''}` },
|
@@ -125,6 +125,11 @@ describe('Message bar', () => {
|
|
125
125
|
yield user_event_1.default.click(react_2.screen.getByRole('button', { name: 'Send' }));
|
126
126
|
expect(react_2.screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
|
127
127
|
}));
|
128
|
+
it('can handle buttonProps tooltipProps appropriately for send', () => {
|
129
|
+
(0, react_2.render)(react_1.default.createElement(MessageBar_1.MessageBar, { onSendMessage: jest.fn, alwayShowSendButton: true, buttonProps: { send: { tooltipProps: { isVisible: true } } } }));
|
130
|
+
// isVisible, so no need for click
|
131
|
+
expect(react_2.screen.getByRole('tooltip', { name: 'Send' })).toBeTruthy();
|
132
|
+
});
|
128
133
|
it('can handle buttonProps props appropriately for send', () => __awaiter(void 0, void 0, void 0, function* () {
|
129
134
|
(0, react_2.render)(react_1.default.createElement(MessageBar_1.MessageBar, { onSendMessage: jest.fn, alwayShowSendButton: true, buttonProps: { send: { props: { 'aria-label': 'Test' } } } }));
|
130
135
|
yield user_event_1.default.click(react_2.screen.getByRole('button', { name: 'Test' }));
|
@@ -189,6 +194,11 @@ describe('Message bar', () => {
|
|
189
194
|
yield user_event_1.default.click(react_2.screen.getByRole('button', { name: 'Attach' }));
|
190
195
|
expect(react_2.screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
|
191
196
|
}));
|
197
|
+
it('can handle buttonProps tooltipProps appropriately for attach', () => {
|
198
|
+
(0, react_2.render)(react_1.default.createElement(MessageBar_1.MessageBar, { onSendMessage: jest.fn, alwayShowSendButton: true, buttonProps: { attach: { tooltipProps: { isVisible: true } } } }));
|
199
|
+
// isVisible, so no need for click
|
200
|
+
expect(react_2.screen.getByRole('tooltip', { name: 'Attach' })).toBeTruthy();
|
201
|
+
});
|
192
202
|
it('can handle buttonProps props appropriately for attach', () => __awaiter(void 0, void 0, void 0, function* () {
|
193
203
|
(0, react_2.render)(react_1.default.createElement(MessageBar_1.MessageBar, { onSendMessage: jest.fn, hasAttachButton: true, buttonProps: { attach: { props: { 'aria-label': 'Test' } } } }));
|
194
204
|
yield user_event_1.default.click(react_2.screen.getByRole('button', { name: 'Test' }));
|
@@ -210,6 +220,11 @@ describe('Message bar', () => {
|
|
210
220
|
yield user_event_1.default.click(react_2.screen.getByRole('button', { name: 'Stop' }));
|
211
221
|
expect(react_2.screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
|
212
222
|
}));
|
223
|
+
it('can handle buttonProps tooltipProps appropriately for stop', () => {
|
224
|
+
(0, react_2.render)(react_1.default.createElement(MessageBar_1.MessageBar, { onSendMessage: jest.fn, hasStopButton: true, handleStopButton: jest.fn, buttonProps: { stop: { tooltipProps: { isVisible: true } } } }));
|
225
|
+
// isVisible, so no need for click
|
226
|
+
expect(react_2.screen.getByRole('tooltip', { name: 'Stop' })).toBeTruthy();
|
227
|
+
});
|
213
228
|
it('can handle buttonProps props appropriately for stop', () => __awaiter(void 0, void 0, void 0, function* () {
|
214
229
|
(0, react_2.render)(react_1.default.createElement(MessageBar_1.MessageBar, { onSendMessage: jest.fn, hasStopButton: true, handleStopButton: jest.fn, buttonProps: { stop: { props: { 'aria-label': 'Test' } } } }));
|
215
230
|
yield user_event_1.default.click(react_2.screen.getByRole('button', { name: 'Test' }));
|
@@ -242,6 +257,11 @@ describe('Message bar', () => {
|
|
242
257
|
const input = react_2.screen.getByRole('textbox', { name: /I am listening/i });
|
243
258
|
expect(input).toBeTruthy();
|
244
259
|
}));
|
260
|
+
it('can handle buttonProps tooltipProps appropriately for microphone', () => {
|
261
|
+
(0, react_2.render)(react_1.default.createElement(MessageBar_1.MessageBar, { onSendMessage: jest.fn, hasMicrophoneButton: true, buttonProps: { microphone: { tooltipProps: { isVisible: true } } } }));
|
262
|
+
// isVisible, so no need for click
|
263
|
+
expect(react_2.screen.getByRole('tooltip', { name: 'Use microphone' })).toBeTruthy();
|
264
|
+
});
|
245
265
|
it('can handle buttonProps props appropriately for microphone', () => __awaiter(void 0, void 0, void 0, function* () {
|
246
266
|
mockSpeechRecognition();
|
247
267
|
(0, react_2.render)(react_1.default.createElement(MessageBar_1.MessageBar, { onSendMessage: jest.fn, hasMicrophoneButton: true, buttonProps: { microphone: { props: { 'aria-label': 'Test' } } } }));
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { TooltipProps } from '@patternfly/react-core';
|
3
|
-
export interface ResponseActionButtonProps {
|
2
|
+
import { ButtonProps, TooltipProps } from '@patternfly/react-core';
|
3
|
+
export interface ResponseActionButtonProps extends ButtonProps {
|
4
4
|
/** Aria-label for the button. Defaults to the value of the tooltipContent if none provided */
|
5
5
|
ariaLabel?: string;
|
6
6
|
/** Aria-label for the button, shown when the button is clicked. Defaults to the value of ariaLabel or tooltipContent if not provided. */
|
@@ -26,9 +26,12 @@ export interface ActionProps extends Omit<ButtonProps, 'ref'> {
|
|
26
26
|
/** Id for content controlled by the button, such as the feedback form */
|
27
27
|
'aria-controls'?: string;
|
28
28
|
}
|
29
|
+
type ExtendedActionProps = ActionProps & {
|
30
|
+
[key: string]: any;
|
31
|
+
};
|
29
32
|
export interface ResponseActionProps {
|
30
33
|
/** Props for message actions, such as feedback (positive or negative), copy button, share, and listen */
|
31
|
-
actions: Record<string,
|
34
|
+
actions: Record<string, ExtendedActionProps | undefined> & {
|
32
35
|
positive?: ActionProps;
|
33
36
|
negative?: ActionProps;
|
34
37
|
copy?: ActionProps;
|
@@ -39,14 +39,14 @@ const ResponseActions = ({ actions }) => {
|
|
39
39
|
onClick && onClick(e);
|
40
40
|
};
|
41
41
|
return (react_1.default.createElement("div", { ref: responseActions, className: "pf-chatbot__response-actions" },
|
42
|
-
positive && (react_1.default.createElement(ResponseActionButton_1.default, { ariaLabel: (_a = positive.ariaLabel) !== null && _a !== void 0 ? _a : 'Good response', clickedAriaLabel: (_b = positive.ariaLabel) !== null && _b !== void 0 ? _b : 'Response recorded', onClick: (e) => handleClick(e, 'positive', positive.onClick), className: positive.className, isDisabled: positive.isDisabled, tooltipContent: (_c = positive.tooltipContent) !== null && _c !== void 0 ? _c : 'Good response', clickedTooltipContent: (_d = positive.clickedTooltipContent) !== null && _d !== void 0 ? _d : 'Response recorded', tooltipProps: positive.tooltipProps, icon: react_1.default.createElement(react_icons_1.OutlinedThumbsUpIcon, null), isClicked: activeButton === 'positive', ref: positive.ref, "aria-expanded": positive['aria-expanded'], "aria-controls": positive['aria-controls'] })),
|
43
|
-
negative && (react_1.default.createElement(ResponseActionButton_1.default, { ariaLabel: (_e = negative.ariaLabel) !== null && _e !== void 0 ? _e : 'Bad response', clickedAriaLabel: (_f = negative.ariaLabel) !== null && _f !== void 0 ? _f : 'Response recorded', onClick: (e) => handleClick(e, 'negative', negative.onClick), className: negative.className, isDisabled: negative.isDisabled, tooltipContent: (_g = negative.tooltipContent) !== null && _g !== void 0 ? _g : 'Bad response', clickedTooltipContent: (_h = negative.clickedTooltipContent) !== null && _h !== void 0 ? _h : 'Response recorded', tooltipProps: negative.tooltipProps, icon: react_1.default.createElement(react_icons_1.OutlinedThumbsDownIcon, null), isClicked: activeButton === 'negative', ref: negative.ref, "aria-expanded": negative['aria-expanded'], "aria-controls": negative['aria-controls'] })),
|
44
|
-
copy && (react_1.default.createElement(ResponseActionButton_1.default, { ariaLabel: (_j = copy.ariaLabel) !== null && _j !== void 0 ? _j : 'Copy', clickedAriaLabel: (_k = copy.ariaLabel) !== null && _k !== void 0 ? _k : 'Copied', onClick: (e) => handleClick(e, 'copy', copy.onClick), className: copy.className, isDisabled: copy.isDisabled, tooltipContent: (_l = copy.tooltipContent) !== null && _l !== void 0 ? _l : 'Copy', clickedTooltipContent: (_m = copy.clickedTooltipContent) !== null && _m !== void 0 ? _m : 'Copied', tooltipProps: copy.tooltipProps, icon: react_1.default.createElement(react_icons_1.OutlinedCopyIcon, null), isClicked: activeButton === 'copy', ref: copy.ref, "aria-expanded": copy['aria-expanded'], "aria-controls": copy['aria-controls'] })),
|
45
|
-
share && (react_1.default.createElement(ResponseActionButton_1.default, { ariaLabel: (_o = share.ariaLabel) !== null && _o !== void 0 ? _o : 'Share', clickedAriaLabel: (_p = share.ariaLabel) !== null && _p !== void 0 ? _p : 'Shared', onClick: (e) => handleClick(e, 'share', share.onClick), className: share.className, isDisabled: share.isDisabled, tooltipContent: (_q = share.tooltipContent) !== null && _q !== void 0 ? _q : 'Share', clickedTooltipContent: (_r = share.clickedTooltipContent) !== null && _r !== void 0 ? _r : 'Shared', tooltipProps: share.tooltipProps, icon: react_1.default.createElement(react_icons_1.ExternalLinkAltIcon, null), isClicked: activeButton === 'share', ref: share.ref, "aria-expanded": share['aria-expanded'], "aria-controls": share['aria-controls'] })),
|
46
|
-
listen && (react_1.default.createElement(ResponseActionButton_1.default, { ariaLabel: (_s = listen.ariaLabel) !== null && _s !== void 0 ? _s : 'Listen', clickedAriaLabel: (_t = listen.ariaLabel) !== null && _t !== void 0 ? _t : 'Listening', onClick: (e) => handleClick(e, 'listen', listen.onClick), className: listen.className, isDisabled: listen.isDisabled, tooltipContent: (_u = listen.tooltipContent) !== null && _u !== void 0 ? _u : 'Listen', clickedTooltipContent: (_v = listen.clickedTooltipContent) !== null && _v !== void 0 ? _v : 'Listening', tooltipProps: listen.tooltipProps, icon: react_1.default.createElement(react_icons_1.VolumeUpIcon, null), isClicked: activeButton === 'listen', ref: listen.ref, "aria-expanded": listen['aria-expanded'], "aria-controls": listen['aria-controls'] })),
|
42
|
+
positive && (react_1.default.createElement(ResponseActionButton_1.default, Object.assign({}, positive, { ariaLabel: (_a = positive.ariaLabel) !== null && _a !== void 0 ? _a : 'Good response', clickedAriaLabel: (_b = positive.ariaLabel) !== null && _b !== void 0 ? _b : 'Response recorded', onClick: (e) => handleClick(e, 'positive', positive.onClick), className: positive.className, isDisabled: positive.isDisabled, tooltipContent: (_c = positive.tooltipContent) !== null && _c !== void 0 ? _c : 'Good response', clickedTooltipContent: (_d = positive.clickedTooltipContent) !== null && _d !== void 0 ? _d : 'Response recorded', tooltipProps: positive.tooltipProps, icon: react_1.default.createElement(react_icons_1.OutlinedThumbsUpIcon, null), isClicked: activeButton === 'positive', ref: positive.ref, "aria-expanded": positive['aria-expanded'], "aria-controls": positive['aria-controls'] }))),
|
43
|
+
negative && (react_1.default.createElement(ResponseActionButton_1.default, Object.assign({}, negative, { ariaLabel: (_e = negative.ariaLabel) !== null && _e !== void 0 ? _e : 'Bad response', clickedAriaLabel: (_f = negative.ariaLabel) !== null && _f !== void 0 ? _f : 'Response recorded', onClick: (e) => handleClick(e, 'negative', negative.onClick), className: negative.className, isDisabled: negative.isDisabled, tooltipContent: (_g = negative.tooltipContent) !== null && _g !== void 0 ? _g : 'Bad response', clickedTooltipContent: (_h = negative.clickedTooltipContent) !== null && _h !== void 0 ? _h : 'Response recorded', tooltipProps: negative.tooltipProps, icon: react_1.default.createElement(react_icons_1.OutlinedThumbsDownIcon, null), isClicked: activeButton === 'negative', ref: negative.ref, "aria-expanded": negative['aria-expanded'], "aria-controls": negative['aria-controls'] }))),
|
44
|
+
copy && (react_1.default.createElement(ResponseActionButton_1.default, Object.assign({}, copy, { ariaLabel: (_j = copy.ariaLabel) !== null && _j !== void 0 ? _j : 'Copy', clickedAriaLabel: (_k = copy.ariaLabel) !== null && _k !== void 0 ? _k : 'Copied', onClick: (e) => handleClick(e, 'copy', copy.onClick), className: copy.className, isDisabled: copy.isDisabled, tooltipContent: (_l = copy.tooltipContent) !== null && _l !== void 0 ? _l : 'Copy', clickedTooltipContent: (_m = copy.clickedTooltipContent) !== null && _m !== void 0 ? _m : 'Copied', tooltipProps: copy.tooltipProps, icon: react_1.default.createElement(react_icons_1.OutlinedCopyIcon, null), isClicked: activeButton === 'copy', ref: copy.ref, "aria-expanded": copy['aria-expanded'], "aria-controls": copy['aria-controls'] }))),
|
45
|
+
share && (react_1.default.createElement(ResponseActionButton_1.default, Object.assign({}, share, { ariaLabel: (_o = share.ariaLabel) !== null && _o !== void 0 ? _o : 'Share', clickedAriaLabel: (_p = share.ariaLabel) !== null && _p !== void 0 ? _p : 'Shared', onClick: (e) => handleClick(e, 'share', share.onClick), className: share.className, isDisabled: share.isDisabled, tooltipContent: (_q = share.tooltipContent) !== null && _q !== void 0 ? _q : 'Share', clickedTooltipContent: (_r = share.clickedTooltipContent) !== null && _r !== void 0 ? _r : 'Shared', tooltipProps: share.tooltipProps, icon: react_1.default.createElement(react_icons_1.ExternalLinkAltIcon, null), isClicked: activeButton === 'share', ref: share.ref, "aria-expanded": share['aria-expanded'], "aria-controls": share['aria-controls'] }))),
|
46
|
+
listen && (react_1.default.createElement(ResponseActionButton_1.default, Object.assign({}, listen, { ariaLabel: (_s = listen.ariaLabel) !== null && _s !== void 0 ? _s : 'Listen', clickedAriaLabel: (_t = listen.ariaLabel) !== null && _t !== void 0 ? _t : 'Listening', onClick: (e) => handleClick(e, 'listen', listen.onClick), className: listen.className, isDisabled: listen.isDisabled, tooltipContent: (_u = listen.tooltipContent) !== null && _u !== void 0 ? _u : 'Listen', clickedTooltipContent: (_v = listen.clickedTooltipContent) !== null && _v !== void 0 ? _v : 'Listening', tooltipProps: listen.tooltipProps, icon: react_1.default.createElement(react_icons_1.VolumeUpIcon, null), isClicked: activeButton === 'listen', ref: listen.ref, "aria-expanded": listen['aria-expanded'], "aria-controls": listen['aria-controls'] }))),
|
47
47
|
Object.keys(additionalActions).map((action) => {
|
48
48
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
49
|
-
return (react_1.default.createElement(ResponseActionButton_1.default, { key: action, ariaLabel: (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.ariaLabel, clickedAriaLabel: (_b = additionalActions[action]) === null || _b === void 0 ? void 0 : _b.clickedAriaLabel, onClick: (e) => { var _a; return handleClick(e, action, (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.onClick); }, className: (_c = additionalActions[action]) === null || _c === void 0 ? void 0 : _c.className, isDisabled: (_d = additionalActions[action]) === null || _d === void 0 ? void 0 : _d.isDisabled, tooltipContent: (_e = additionalActions[action]) === null || _e === void 0 ? void 0 : _e.tooltipContent, tooltipProps: (_f = additionalActions[action]) === null || _f === void 0 ? void 0 : _f.tooltipProps, clickedTooltipContent: (_g = additionalActions[action]) === null || _g === void 0 ? void 0 : _g.clickedTooltipContent, icon: (_h = additionalActions[action]) === null || _h === void 0 ? void 0 : _h.icon, isClicked: activeButton === action, ref: (_j = additionalActions[action]) === null || _j === void 0 ? void 0 : _j.ref, "aria-expanded": (_k = additionalActions[action]) === null || _k === void 0 ? void 0 : _k['aria-expanded'], "aria-controls": (_l = additionalActions[action]) === null || _l === void 0 ? void 0 : _l['aria-controls'] }));
|
49
|
+
return (react_1.default.createElement(ResponseActionButton_1.default, Object.assign({}, additionalActions[action], { key: action, ariaLabel: (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.ariaLabel, clickedAriaLabel: (_b = additionalActions[action]) === null || _b === void 0 ? void 0 : _b.clickedAriaLabel, onClick: (e) => { var _a; return handleClick(e, action, (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.onClick); }, className: (_c = additionalActions[action]) === null || _c === void 0 ? void 0 : _c.className, isDisabled: (_d = additionalActions[action]) === null || _d === void 0 ? void 0 : _d.isDisabled, tooltipContent: (_e = additionalActions[action]) === null || _e === void 0 ? void 0 : _e.tooltipContent, tooltipProps: (_f = additionalActions[action]) === null || _f === void 0 ? void 0 : _f.tooltipProps, clickedTooltipContent: (_g = additionalActions[action]) === null || _g === void 0 ? void 0 : _g.clickedTooltipContent, icon: (_h = additionalActions[action]) === null || _h === void 0 ? void 0 : _h.icon, isClicked: activeButton === action, ref: (_j = additionalActions[action]) === null || _j === void 0 ? void 0 : _j.ref, "aria-expanded": (_k = additionalActions[action]) === null || _k === void 0 ? void 0 : _k['aria-expanded'], "aria-controls": (_l = additionalActions[action]) === null || _l === void 0 ? void 0 : _l['aria-controls'] })));
|
50
50
|
})));
|
51
51
|
};
|
52
52
|
exports.ResponseActions = ResponseActions;
|
@@ -52,6 +52,13 @@ const CUSTOM_ACTIONS = [
|
|
52
52
|
}
|
53
53
|
}
|
54
54
|
];
|
55
|
+
const ALL_ACTIONS_DATA_TEST = [
|
56
|
+
{ type: 'positive', label: 'Good response', dataTestId: 'positive' },
|
57
|
+
{ type: 'negative', label: 'Bad response', dataTestId: 'negative' },
|
58
|
+
{ type: 'copy', label: 'Copy', dataTestId: 'copy' },
|
59
|
+
{ type: 'share', label: 'Share', dataTestId: 'share' },
|
60
|
+
{ type: 'listen', label: 'Listen', dataTestId: 'listen' }
|
61
|
+
];
|
55
62
|
describe('ResponseActions', () => {
|
56
63
|
afterEach(() => {
|
57
64
|
jest.clearAllMocks();
|
@@ -161,6 +168,12 @@ describe('ResponseActions', () => {
|
|
161
168
|
expect(react_2.screen.getByRole('button', { name: label })).toHaveClass('test');
|
162
169
|
});
|
163
170
|
});
|
171
|
+
it('should be able to add custom attributes to buttons', () => {
|
172
|
+
ALL_ACTIONS_DATA_TEST.forEach(({ type, dataTestId }) => {
|
173
|
+
(0, react_2.render)(react_1.default.createElement(ResponseActions_1.default, { actions: { [type]: { onClick: jest.fn(), 'data-testid': dataTestId } } }));
|
174
|
+
expect(react_2.screen.getByTestId(dataTestId)).toBeTruthy();
|
175
|
+
});
|
176
|
+
});
|
164
177
|
it('should be able to add custom actions', () => {
|
165
178
|
CUSTOM_ACTIONS.forEach((action) => {
|
166
179
|
const key = Object.keys(action)[0];
|
@@ -170,10 +183,12 @@ describe('ResponseActions', () => {
|
|
170
183
|
onClick: action[key].onClick,
|
171
184
|
// doing this just because it's easier to test without a regex for the button name
|
172
185
|
ariaLabel: action[key].ariaLabel.toLowerCase(),
|
173
|
-
icon: action[key].icon
|
186
|
+
icon: action[key].icon,
|
187
|
+
'data-testid': action[key]
|
174
188
|
}
|
175
189
|
} }));
|
176
190
|
expect(react_2.screen.getByRole('button', { name: key })).toBeTruthy();
|
191
|
+
expect(react_2.screen.getByTestId(action[key])).toBeTruthy();
|
177
192
|
});
|
178
193
|
});
|
179
194
|
});
|
@@ -169,15 +169,15 @@ export const MessageBar = (_a) => {
|
|
169
169
|
onChange && onChange({}, message);
|
170
170
|
};
|
171
171
|
const renderButtons = () => {
|
172
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
172
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
173
173
|
if (hasStopButton && handleStopButton) {
|
174
|
-
return (React.createElement(StopButton, Object.assign({ onClick: handleStopButton, tooltipContent: (_a = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _a === void 0 ? void 0 : _a.tooltipContent, isCompact: isCompact
|
174
|
+
return (React.createElement(StopButton, Object.assign({ onClick: handleStopButton, tooltipContent: (_a = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _a === void 0 ? void 0 : _a.tooltipContent, isCompact: isCompact, tooltipProps: (_b = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _b === void 0 ? void 0 : _b.tooltipProps }, (_c = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.stop) === null || _c === void 0 ? void 0 : _c.props)));
|
175
175
|
}
|
176
176
|
return (React.createElement(React.Fragment, null,
|
177
|
-
attachMenuProps && (React.createElement(AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (
|
178
|
-
!attachMenuProps && hasAttachButton && (React.createElement(AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (
|
179
|
-
hasMicrophoneButton && (React.createElement(MicrophoneButton, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (
|
180
|
-
(alwayShowSendButton || message) && (React.createElement(SendButton, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (
|
177
|
+
attachMenuProps && (React.createElement(AttachButton, Object.assign({ ref: attachButtonRef, onClick: handleAttachMenuToggle, isDisabled: isListeningMessage, tooltipContent: (_d = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _d === void 0 ? void 0 : _d.tooltipContent, isCompact: isCompact, tooltipProps: (_e = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _e === void 0 ? void 0 : _e.tooltipProps }, (_f = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _f === void 0 ? void 0 : _f.props))),
|
178
|
+
!attachMenuProps && hasAttachButton && (React.createElement(AttachButton, Object.assign({ onAttachAccepted: handleAttach, isDisabled: isListeningMessage, tooltipContent: (_g = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _g === void 0 ? void 0 : _g.tooltipContent, inputTestId: (_h = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _h === void 0 ? void 0 : _h.inputTestId, isCompact: isCompact, tooltipProps: (_j = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _j === void 0 ? void 0 : _j.tooltipProps }, (_k = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.attach) === null || _k === void 0 ? void 0 : _k.props))),
|
179
|
+
hasMicrophoneButton && (React.createElement(MicrophoneButton, Object.assign({ isListening: isListeningMessage, onIsListeningChange: setIsListeningMessage, onSpeechRecognition: handleSpeechRecognition, tooltipContent: (_l = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _l === void 0 ? void 0 : _l.tooltipContent, language: (_m = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _m === void 0 ? void 0 : _m.language, isCompact: isCompact, tooltipProps: (_o = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _o === void 0 ? void 0 : _o.tooltipProps }, (_p = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.microphone) === null || _p === void 0 ? void 0 : _p.props))),
|
180
|
+
(alwayShowSendButton || message) && (React.createElement(SendButton, Object.assign({ value: message, onClick: () => handleSend(message), isDisabled: isSendButtonDisabled, tooltipContent: (_q = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _q === void 0 ? void 0 : _q.tooltipContent, isCompact: isCompact, tooltipProps: (_r = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _r === void 0 ? void 0 : _r.tooltipProps }, (_s = buttonProps === null || buttonProps === void 0 ? void 0 : buttonProps.send) === null || _s === void 0 ? void 0 : _s.props)))));
|
181
181
|
};
|
182
182
|
const messageBarContents = (React.createElement(React.Fragment, null,
|
183
183
|
React.createElement("div", { className: `pf-chatbot__message-bar-input ${isCompact ? 'pf-m-compact' : ''}` },
|
@@ -120,6 +120,11 @@ describe('Message bar', () => {
|
|
120
120
|
yield userEvent.click(screen.getByRole('button', { name: 'Send' }));
|
121
121
|
expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
|
122
122
|
}));
|
123
|
+
it('can handle buttonProps tooltipProps appropriately for send', () => {
|
124
|
+
render(React.createElement(MessageBar, { onSendMessage: jest.fn, alwayShowSendButton: true, buttonProps: { send: { tooltipProps: { isVisible: true } } } }));
|
125
|
+
// isVisible, so no need for click
|
126
|
+
expect(screen.getByRole('tooltip', { name: 'Send' })).toBeTruthy();
|
127
|
+
});
|
123
128
|
it('can handle buttonProps props appropriately for send', () => __awaiter(void 0, void 0, void 0, function* () {
|
124
129
|
render(React.createElement(MessageBar, { onSendMessage: jest.fn, alwayShowSendButton: true, buttonProps: { send: { props: { 'aria-label': 'Test' } } } }));
|
125
130
|
yield userEvent.click(screen.getByRole('button', { name: 'Test' }));
|
@@ -184,6 +189,11 @@ describe('Message bar', () => {
|
|
184
189
|
yield userEvent.click(screen.getByRole('button', { name: 'Attach' }));
|
185
190
|
expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
|
186
191
|
}));
|
192
|
+
it('can handle buttonProps tooltipProps appropriately for attach', () => {
|
193
|
+
render(React.createElement(MessageBar, { onSendMessage: jest.fn, alwayShowSendButton: true, buttonProps: { attach: { tooltipProps: { isVisible: true } } } }));
|
194
|
+
// isVisible, so no need for click
|
195
|
+
expect(screen.getByRole('tooltip', { name: 'Attach' })).toBeTruthy();
|
196
|
+
});
|
187
197
|
it('can handle buttonProps props appropriately for attach', () => __awaiter(void 0, void 0, void 0, function* () {
|
188
198
|
render(React.createElement(MessageBar, { onSendMessage: jest.fn, hasAttachButton: true, buttonProps: { attach: { props: { 'aria-label': 'Test' } } } }));
|
189
199
|
yield userEvent.click(screen.getByRole('button', { name: 'Test' }));
|
@@ -205,6 +215,11 @@ describe('Message bar', () => {
|
|
205
215
|
yield userEvent.click(screen.getByRole('button', { name: 'Stop' }));
|
206
216
|
expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
|
207
217
|
}));
|
218
|
+
it('can handle buttonProps tooltipProps appropriately for stop', () => {
|
219
|
+
render(React.createElement(MessageBar, { onSendMessage: jest.fn, hasStopButton: true, handleStopButton: jest.fn, buttonProps: { stop: { tooltipProps: { isVisible: true } } } }));
|
220
|
+
// isVisible, so no need for click
|
221
|
+
expect(screen.getByRole('tooltip', { name: 'Stop' })).toBeTruthy();
|
222
|
+
});
|
208
223
|
it('can handle buttonProps props appropriately for stop', () => __awaiter(void 0, void 0, void 0, function* () {
|
209
224
|
render(React.createElement(MessageBar, { onSendMessage: jest.fn, hasStopButton: true, handleStopButton: jest.fn, buttonProps: { stop: { props: { 'aria-label': 'Test' } } } }));
|
210
225
|
yield userEvent.click(screen.getByRole('button', { name: 'Test' }));
|
@@ -237,6 +252,11 @@ describe('Message bar', () => {
|
|
237
252
|
const input = screen.getByRole('textbox', { name: /I am listening/i });
|
238
253
|
expect(input).toBeTruthy();
|
239
254
|
}));
|
255
|
+
it('can handle buttonProps tooltipProps appropriately for microphone', () => {
|
256
|
+
render(React.createElement(MessageBar, { onSendMessage: jest.fn, hasMicrophoneButton: true, buttonProps: { microphone: { tooltipProps: { isVisible: true } } } }));
|
257
|
+
// isVisible, so no need for click
|
258
|
+
expect(screen.getByRole('tooltip', { name: 'Use microphone' })).toBeTruthy();
|
259
|
+
});
|
240
260
|
it('can handle buttonProps props appropriately for microphone', () => __awaiter(void 0, void 0, void 0, function* () {
|
241
261
|
mockSpeechRecognition();
|
242
262
|
render(React.createElement(MessageBar, { onSendMessage: jest.fn, hasMicrophoneButton: true, buttonProps: { microphone: { props: { 'aria-label': 'Test' } } } }));
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { TooltipProps } from '@patternfly/react-core';
|
3
|
-
export interface ResponseActionButtonProps {
|
2
|
+
import { ButtonProps, TooltipProps } from '@patternfly/react-core';
|
3
|
+
export interface ResponseActionButtonProps extends ButtonProps {
|
4
4
|
/** Aria-label for the button. Defaults to the value of the tooltipContent if none provided */
|
5
5
|
ariaLabel?: string;
|
6
6
|
/** Aria-label for the button, shown when the button is clicked. Defaults to the value of ariaLabel or tooltipContent if not provided. */
|
@@ -26,9 +26,12 @@ export interface ActionProps extends Omit<ButtonProps, 'ref'> {
|
|
26
26
|
/** Id for content controlled by the button, such as the feedback form */
|
27
27
|
'aria-controls'?: string;
|
28
28
|
}
|
29
|
+
type ExtendedActionProps = ActionProps & {
|
30
|
+
[key: string]: any;
|
31
|
+
};
|
29
32
|
export interface ResponseActionProps {
|
30
33
|
/** Props for message actions, such as feedback (positive or negative), copy button, share, and listen */
|
31
|
-
actions: Record<string,
|
34
|
+
actions: Record<string, ExtendedActionProps | undefined> & {
|
32
35
|
positive?: ActionProps;
|
33
36
|
negative?: ActionProps;
|
34
37
|
copy?: ActionProps;
|
@@ -33,14 +33,14 @@ export const ResponseActions = ({ actions }) => {
|
|
33
33
|
onClick && onClick(e);
|
34
34
|
};
|
35
35
|
return (React.createElement("div", { ref: responseActions, className: "pf-chatbot__response-actions" },
|
36
|
-
positive && (React.createElement(ResponseActionButton, { ariaLabel: (_a = positive.ariaLabel) !== null && _a !== void 0 ? _a : 'Good response', clickedAriaLabel: (_b = positive.ariaLabel) !== null && _b !== void 0 ? _b : 'Response recorded', onClick: (e) => handleClick(e, 'positive', positive.onClick), className: positive.className, isDisabled: positive.isDisabled, tooltipContent: (_c = positive.tooltipContent) !== null && _c !== void 0 ? _c : 'Good response', clickedTooltipContent: (_d = positive.clickedTooltipContent) !== null && _d !== void 0 ? _d : 'Response recorded', tooltipProps: positive.tooltipProps, icon: React.createElement(OutlinedThumbsUpIcon, null), isClicked: activeButton === 'positive', ref: positive.ref, "aria-expanded": positive['aria-expanded'], "aria-controls": positive['aria-controls'] })),
|
37
|
-
negative && (React.createElement(ResponseActionButton, { ariaLabel: (_e = negative.ariaLabel) !== null && _e !== void 0 ? _e : 'Bad response', clickedAriaLabel: (_f = negative.ariaLabel) !== null && _f !== void 0 ? _f : 'Response recorded', onClick: (e) => handleClick(e, 'negative', negative.onClick), className: negative.className, isDisabled: negative.isDisabled, tooltipContent: (_g = negative.tooltipContent) !== null && _g !== void 0 ? _g : 'Bad response', clickedTooltipContent: (_h = negative.clickedTooltipContent) !== null && _h !== void 0 ? _h : 'Response recorded', tooltipProps: negative.tooltipProps, icon: React.createElement(OutlinedThumbsDownIcon, null), isClicked: activeButton === 'negative', ref: negative.ref, "aria-expanded": negative['aria-expanded'], "aria-controls": negative['aria-controls'] })),
|
38
|
-
copy && (React.createElement(ResponseActionButton, { ariaLabel: (_j = copy.ariaLabel) !== null && _j !== void 0 ? _j : 'Copy', clickedAriaLabel: (_k = copy.ariaLabel) !== null && _k !== void 0 ? _k : 'Copied', onClick: (e) => handleClick(e, 'copy', copy.onClick), className: copy.className, isDisabled: copy.isDisabled, tooltipContent: (_l = copy.tooltipContent) !== null && _l !== void 0 ? _l : 'Copy', clickedTooltipContent: (_m = copy.clickedTooltipContent) !== null && _m !== void 0 ? _m : 'Copied', tooltipProps: copy.tooltipProps, icon: React.createElement(OutlinedCopyIcon, null), isClicked: activeButton === 'copy', ref: copy.ref, "aria-expanded": copy['aria-expanded'], "aria-controls": copy['aria-controls'] })),
|
39
|
-
share && (React.createElement(ResponseActionButton, { ariaLabel: (_o = share.ariaLabel) !== null && _o !== void 0 ? _o : 'Share', clickedAriaLabel: (_p = share.ariaLabel) !== null && _p !== void 0 ? _p : 'Shared', onClick: (e) => handleClick(e, 'share', share.onClick), className: share.className, isDisabled: share.isDisabled, tooltipContent: (_q = share.tooltipContent) !== null && _q !== void 0 ? _q : 'Share', clickedTooltipContent: (_r = share.clickedTooltipContent) !== null && _r !== void 0 ? _r : 'Shared', tooltipProps: share.tooltipProps, icon: React.createElement(ExternalLinkAltIcon, null), isClicked: activeButton === 'share', ref: share.ref, "aria-expanded": share['aria-expanded'], "aria-controls": share['aria-controls'] })),
|
40
|
-
listen && (React.createElement(ResponseActionButton, { ariaLabel: (_s = listen.ariaLabel) !== null && _s !== void 0 ? _s : 'Listen', clickedAriaLabel: (_t = listen.ariaLabel) !== null && _t !== void 0 ? _t : 'Listening', onClick: (e) => handleClick(e, 'listen', listen.onClick), className: listen.className, isDisabled: listen.isDisabled, tooltipContent: (_u = listen.tooltipContent) !== null && _u !== void 0 ? _u : 'Listen', clickedTooltipContent: (_v = listen.clickedTooltipContent) !== null && _v !== void 0 ? _v : 'Listening', tooltipProps: listen.tooltipProps, icon: React.createElement(VolumeUpIcon, null), isClicked: activeButton === 'listen', ref: listen.ref, "aria-expanded": listen['aria-expanded'], "aria-controls": listen['aria-controls'] })),
|
36
|
+
positive && (React.createElement(ResponseActionButton, Object.assign({}, positive, { ariaLabel: (_a = positive.ariaLabel) !== null && _a !== void 0 ? _a : 'Good response', clickedAriaLabel: (_b = positive.ariaLabel) !== null && _b !== void 0 ? _b : 'Response recorded', onClick: (e) => handleClick(e, 'positive', positive.onClick), className: positive.className, isDisabled: positive.isDisabled, tooltipContent: (_c = positive.tooltipContent) !== null && _c !== void 0 ? _c : 'Good response', clickedTooltipContent: (_d = positive.clickedTooltipContent) !== null && _d !== void 0 ? _d : 'Response recorded', tooltipProps: positive.tooltipProps, icon: React.createElement(OutlinedThumbsUpIcon, null), isClicked: activeButton === 'positive', ref: positive.ref, "aria-expanded": positive['aria-expanded'], "aria-controls": positive['aria-controls'] }))),
|
37
|
+
negative && (React.createElement(ResponseActionButton, Object.assign({}, negative, { ariaLabel: (_e = negative.ariaLabel) !== null && _e !== void 0 ? _e : 'Bad response', clickedAriaLabel: (_f = negative.ariaLabel) !== null && _f !== void 0 ? _f : 'Response recorded', onClick: (e) => handleClick(e, 'negative', negative.onClick), className: negative.className, isDisabled: negative.isDisabled, tooltipContent: (_g = negative.tooltipContent) !== null && _g !== void 0 ? _g : 'Bad response', clickedTooltipContent: (_h = negative.clickedTooltipContent) !== null && _h !== void 0 ? _h : 'Response recorded', tooltipProps: negative.tooltipProps, icon: React.createElement(OutlinedThumbsDownIcon, null), isClicked: activeButton === 'negative', ref: negative.ref, "aria-expanded": negative['aria-expanded'], "aria-controls": negative['aria-controls'] }))),
|
38
|
+
copy && (React.createElement(ResponseActionButton, Object.assign({}, copy, { ariaLabel: (_j = copy.ariaLabel) !== null && _j !== void 0 ? _j : 'Copy', clickedAriaLabel: (_k = copy.ariaLabel) !== null && _k !== void 0 ? _k : 'Copied', onClick: (e) => handleClick(e, 'copy', copy.onClick), className: copy.className, isDisabled: copy.isDisabled, tooltipContent: (_l = copy.tooltipContent) !== null && _l !== void 0 ? _l : 'Copy', clickedTooltipContent: (_m = copy.clickedTooltipContent) !== null && _m !== void 0 ? _m : 'Copied', tooltipProps: copy.tooltipProps, icon: React.createElement(OutlinedCopyIcon, null), isClicked: activeButton === 'copy', ref: copy.ref, "aria-expanded": copy['aria-expanded'], "aria-controls": copy['aria-controls'] }))),
|
39
|
+
share && (React.createElement(ResponseActionButton, Object.assign({}, share, { ariaLabel: (_o = share.ariaLabel) !== null && _o !== void 0 ? _o : 'Share', clickedAriaLabel: (_p = share.ariaLabel) !== null && _p !== void 0 ? _p : 'Shared', onClick: (e) => handleClick(e, 'share', share.onClick), className: share.className, isDisabled: share.isDisabled, tooltipContent: (_q = share.tooltipContent) !== null && _q !== void 0 ? _q : 'Share', clickedTooltipContent: (_r = share.clickedTooltipContent) !== null && _r !== void 0 ? _r : 'Shared', tooltipProps: share.tooltipProps, icon: React.createElement(ExternalLinkAltIcon, null), isClicked: activeButton === 'share', ref: share.ref, "aria-expanded": share['aria-expanded'], "aria-controls": share['aria-controls'] }))),
|
40
|
+
listen && (React.createElement(ResponseActionButton, Object.assign({}, listen, { ariaLabel: (_s = listen.ariaLabel) !== null && _s !== void 0 ? _s : 'Listen', clickedAriaLabel: (_t = listen.ariaLabel) !== null && _t !== void 0 ? _t : 'Listening', onClick: (e) => handleClick(e, 'listen', listen.onClick), className: listen.className, isDisabled: listen.isDisabled, tooltipContent: (_u = listen.tooltipContent) !== null && _u !== void 0 ? _u : 'Listen', clickedTooltipContent: (_v = listen.clickedTooltipContent) !== null && _v !== void 0 ? _v : 'Listening', tooltipProps: listen.tooltipProps, icon: React.createElement(VolumeUpIcon, null), isClicked: activeButton === 'listen', ref: listen.ref, "aria-expanded": listen['aria-expanded'], "aria-controls": listen['aria-controls'] }))),
|
41
41
|
Object.keys(additionalActions).map((action) => {
|
42
42
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
43
|
-
return (React.createElement(ResponseActionButton, { key: action, ariaLabel: (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.ariaLabel, clickedAriaLabel: (_b = additionalActions[action]) === null || _b === void 0 ? void 0 : _b.clickedAriaLabel, onClick: (e) => { var _a; return handleClick(e, action, (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.onClick); }, className: (_c = additionalActions[action]) === null || _c === void 0 ? void 0 : _c.className, isDisabled: (_d = additionalActions[action]) === null || _d === void 0 ? void 0 : _d.isDisabled, tooltipContent: (_e = additionalActions[action]) === null || _e === void 0 ? void 0 : _e.tooltipContent, tooltipProps: (_f = additionalActions[action]) === null || _f === void 0 ? void 0 : _f.tooltipProps, clickedTooltipContent: (_g = additionalActions[action]) === null || _g === void 0 ? void 0 : _g.clickedTooltipContent, icon: (_h = additionalActions[action]) === null || _h === void 0 ? void 0 : _h.icon, isClicked: activeButton === action, ref: (_j = additionalActions[action]) === null || _j === void 0 ? void 0 : _j.ref, "aria-expanded": (_k = additionalActions[action]) === null || _k === void 0 ? void 0 : _k['aria-expanded'], "aria-controls": (_l = additionalActions[action]) === null || _l === void 0 ? void 0 : _l['aria-controls'] }));
|
43
|
+
return (React.createElement(ResponseActionButton, Object.assign({}, additionalActions[action], { key: action, ariaLabel: (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.ariaLabel, clickedAriaLabel: (_b = additionalActions[action]) === null || _b === void 0 ? void 0 : _b.clickedAriaLabel, onClick: (e) => { var _a; return handleClick(e, action, (_a = additionalActions[action]) === null || _a === void 0 ? void 0 : _a.onClick); }, className: (_c = additionalActions[action]) === null || _c === void 0 ? void 0 : _c.className, isDisabled: (_d = additionalActions[action]) === null || _d === void 0 ? void 0 : _d.isDisabled, tooltipContent: (_e = additionalActions[action]) === null || _e === void 0 ? void 0 : _e.tooltipContent, tooltipProps: (_f = additionalActions[action]) === null || _f === void 0 ? void 0 : _f.tooltipProps, clickedTooltipContent: (_g = additionalActions[action]) === null || _g === void 0 ? void 0 : _g.clickedTooltipContent, icon: (_h = additionalActions[action]) === null || _h === void 0 ? void 0 : _h.icon, isClicked: activeButton === action, ref: (_j = additionalActions[action]) === null || _j === void 0 ? void 0 : _j.ref, "aria-expanded": (_k = additionalActions[action]) === null || _k === void 0 ? void 0 : _k['aria-expanded'], "aria-controls": (_l = additionalActions[action]) === null || _l === void 0 ? void 0 : _l['aria-controls'] })));
|
44
44
|
})));
|
45
45
|
};
|
46
46
|
export default ResponseActions;
|
@@ -47,6 +47,13 @@ const CUSTOM_ACTIONS = [
|
|
47
47
|
}
|
48
48
|
}
|
49
49
|
];
|
50
|
+
const ALL_ACTIONS_DATA_TEST = [
|
51
|
+
{ type: 'positive', label: 'Good response', dataTestId: 'positive' },
|
52
|
+
{ type: 'negative', label: 'Bad response', dataTestId: 'negative' },
|
53
|
+
{ type: 'copy', label: 'Copy', dataTestId: 'copy' },
|
54
|
+
{ type: 'share', label: 'Share', dataTestId: 'share' },
|
55
|
+
{ type: 'listen', label: 'Listen', dataTestId: 'listen' }
|
56
|
+
];
|
50
57
|
describe('ResponseActions', () => {
|
51
58
|
afterEach(() => {
|
52
59
|
jest.clearAllMocks();
|
@@ -156,6 +163,12 @@ describe('ResponseActions', () => {
|
|
156
163
|
expect(screen.getByRole('button', { name: label })).toHaveClass('test');
|
157
164
|
});
|
158
165
|
});
|
166
|
+
it('should be able to add custom attributes to buttons', () => {
|
167
|
+
ALL_ACTIONS_DATA_TEST.forEach(({ type, dataTestId }) => {
|
168
|
+
render(React.createElement(ResponseActions, { actions: { [type]: { onClick: jest.fn(), 'data-testid': dataTestId } } }));
|
169
|
+
expect(screen.getByTestId(dataTestId)).toBeTruthy();
|
170
|
+
});
|
171
|
+
});
|
159
172
|
it('should be able to add custom actions', () => {
|
160
173
|
CUSTOM_ACTIONS.forEach((action) => {
|
161
174
|
const key = Object.keys(action)[0];
|
@@ -165,10 +178,12 @@ describe('ResponseActions', () => {
|
|
165
178
|
onClick: action[key].onClick,
|
166
179
|
// doing this just because it's easier to test without a regex for the button name
|
167
180
|
ariaLabel: action[key].ariaLabel.toLowerCase(),
|
168
|
-
icon: action[key].icon
|
181
|
+
icon: action[key].icon,
|
182
|
+
'data-testid': action[key]
|
169
183
|
}
|
170
184
|
} }));
|
171
185
|
expect(screen.getByRole('button', { name: key })).toBeTruthy();
|
186
|
+
expect(screen.getByTestId(action[key])).toBeTruthy();
|
172
187
|
});
|
173
188
|
});
|
174
189
|
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@patternfly/chatbot",
|
3
|
-
"version": "6.3.0-prerelease.
|
3
|
+
"version": "6.3.0-prerelease.13",
|
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",
|
@@ -148,6 +148,17 @@ describe('Message bar', () => {
|
|
148
148
|
await userEvent.click(screen.getByRole('button', { name: 'Send' }));
|
149
149
|
expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
|
150
150
|
});
|
151
|
+
it('can handle buttonProps tooltipProps appropriately for send', () => {
|
152
|
+
render(
|
153
|
+
<MessageBar
|
154
|
+
onSendMessage={jest.fn}
|
155
|
+
alwayShowSendButton
|
156
|
+
buttonProps={{ send: { tooltipProps: { isVisible: true } } }}
|
157
|
+
/>
|
158
|
+
);
|
159
|
+
// isVisible, so no need for click
|
160
|
+
expect(screen.getByRole('tooltip', { name: 'Send' })).toBeTruthy();
|
161
|
+
});
|
151
162
|
it('can handle buttonProps props appropriately for send', async () => {
|
152
163
|
render(
|
153
164
|
<MessageBar
|
@@ -236,6 +247,17 @@ describe('Message bar', () => {
|
|
236
247
|
await userEvent.click(screen.getByRole('button', { name: 'Attach' }));
|
237
248
|
expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
|
238
249
|
});
|
250
|
+
it('can handle buttonProps tooltipProps appropriately for attach', () => {
|
251
|
+
render(
|
252
|
+
<MessageBar
|
253
|
+
onSendMessage={jest.fn}
|
254
|
+
alwayShowSendButton
|
255
|
+
buttonProps={{ attach: { tooltipProps: { isVisible: true } } }}
|
256
|
+
/>
|
257
|
+
);
|
258
|
+
// isVisible, so no need for click
|
259
|
+
expect(screen.getByRole('tooltip', { name: 'Attach' })).toBeTruthy();
|
260
|
+
});
|
239
261
|
it('can handle buttonProps props appropriately for attach', async () => {
|
240
262
|
render(
|
241
263
|
<MessageBar
|
@@ -271,6 +293,18 @@ describe('Message bar', () => {
|
|
271
293
|
await userEvent.click(screen.getByRole('button', { name: 'Stop' }));
|
272
294
|
expect(screen.getByRole('tooltip', { name: 'Test' })).toBeTruthy();
|
273
295
|
});
|
296
|
+
it('can handle buttonProps tooltipProps appropriately for stop', () => {
|
297
|
+
render(
|
298
|
+
<MessageBar
|
299
|
+
onSendMessage={jest.fn}
|
300
|
+
hasStopButton
|
301
|
+
handleStopButton={jest.fn}
|
302
|
+
buttonProps={{ stop: { tooltipProps: { isVisible: true } } }}
|
303
|
+
/>
|
304
|
+
);
|
305
|
+
// isVisible, so no need for click
|
306
|
+
expect(screen.getByRole('tooltip', { name: 'Stop' })).toBeTruthy();
|
307
|
+
});
|
274
308
|
it('can handle buttonProps props appropriately for stop', async () => {
|
275
309
|
render(
|
276
310
|
<MessageBar
|
@@ -317,6 +351,17 @@ describe('Message bar', () => {
|
|
317
351
|
const input = screen.getByRole('textbox', { name: /I am listening/i });
|
318
352
|
expect(input).toBeTruthy();
|
319
353
|
});
|
354
|
+
it('can handle buttonProps tooltipProps appropriately for microphone', () => {
|
355
|
+
render(
|
356
|
+
<MessageBar
|
357
|
+
onSendMessage={jest.fn}
|
358
|
+
hasMicrophoneButton
|
359
|
+
buttonProps={{ microphone: { tooltipProps: { isVisible: true } } }}
|
360
|
+
/>
|
361
|
+
);
|
362
|
+
// isVisible, so no need for click
|
363
|
+
expect(screen.getByRole('tooltip', { name: 'Use microphone' })).toBeTruthy();
|
364
|
+
});
|
320
365
|
it('can handle buttonProps props appropriately for microphone', async () => {
|
321
366
|
mockSpeechRecognition();
|
322
367
|
render(
|
@@ -279,6 +279,7 @@ export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
|
|
279
279
|
onClick={handleStopButton}
|
280
280
|
tooltipContent={buttonProps?.stop?.tooltipContent}
|
281
281
|
isCompact={isCompact}
|
282
|
+
tooltipProps={buttonProps?.stop?.tooltipProps}
|
282
283
|
{...buttonProps?.stop?.props}
|
283
284
|
/>
|
284
285
|
);
|
@@ -292,6 +293,7 @@ export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
|
|
292
293
|
isDisabled={isListeningMessage}
|
293
294
|
tooltipContent={buttonProps?.attach?.tooltipContent}
|
294
295
|
isCompact={isCompact}
|
296
|
+
tooltipProps={buttonProps?.attach?.tooltipProps}
|
295
297
|
{...buttonProps?.attach?.props}
|
296
298
|
/>
|
297
299
|
)}
|
@@ -302,6 +304,7 @@ export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
|
|
302
304
|
tooltipContent={buttonProps?.attach?.tooltipContent}
|
303
305
|
inputTestId={buttonProps?.attach?.inputTestId}
|
304
306
|
isCompact={isCompact}
|
307
|
+
tooltipProps={buttonProps?.attach?.tooltipProps}
|
305
308
|
{...buttonProps?.attach?.props}
|
306
309
|
/>
|
307
310
|
)}
|
@@ -313,6 +316,7 @@ export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
|
|
313
316
|
tooltipContent={buttonProps?.microphone?.tooltipContent}
|
314
317
|
language={buttonProps?.microphone?.language}
|
315
318
|
isCompact={isCompact}
|
319
|
+
tooltipProps={buttonProps?.microphone?.tooltipProps}
|
316
320
|
{...buttonProps?.microphone?.props}
|
317
321
|
/>
|
318
322
|
)}
|
@@ -323,6 +327,7 @@ export const MessageBar: React.FunctionComponent<MessageBarProps> = ({
|
|
323
327
|
isDisabled={isSendButtonDisabled}
|
324
328
|
tooltipContent={buttonProps?.send?.tooltipContent}
|
325
329
|
isCompact={isCompact}
|
330
|
+
tooltipProps={buttonProps?.send?.tooltipProps}
|
326
331
|
{...buttonProps?.send?.props}
|
327
332
|
/>
|
328
333
|
)}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { Button, Icon, Tooltip, TooltipProps } from '@patternfly/react-core';
|
2
|
+
import { Button, ButtonProps, Icon, Tooltip, TooltipProps } from '@patternfly/react-core';
|
3
3
|
|
4
|
-
export interface ResponseActionButtonProps {
|
4
|
+
export interface ResponseActionButtonProps extends ButtonProps {
|
5
5
|
/** Aria-label for the button. Defaults to the value of the tooltipContent if none provided */
|
6
6
|
ariaLabel?: string;
|
7
7
|
/** Aria-label for the button, shown when the button is clicked. Defaults to the value of ariaLabel or tooltipContent if not provided. */
|
@@ -41,6 +41,14 @@ const CUSTOM_ACTIONS = [
|
|
41
41
|
}
|
42
42
|
];
|
43
43
|
|
44
|
+
const ALL_ACTIONS_DATA_TEST = [
|
45
|
+
{ type: 'positive', label: 'Good response', dataTestId: 'positive' },
|
46
|
+
{ type: 'negative', label: 'Bad response', dataTestId: 'negative' },
|
47
|
+
{ type: 'copy', label: 'Copy', dataTestId: 'copy' },
|
48
|
+
{ type: 'share', label: 'Share', dataTestId: 'share' },
|
49
|
+
{ type: 'listen', label: 'Listen', dataTestId: 'listen' }
|
50
|
+
];
|
51
|
+
|
44
52
|
describe('ResponseActions', () => {
|
45
53
|
afterEach(() => {
|
46
54
|
jest.clearAllMocks();
|
@@ -181,6 +189,13 @@ describe('ResponseActions', () => {
|
|
181
189
|
});
|
182
190
|
});
|
183
191
|
|
192
|
+
it('should be able to add custom attributes to buttons', () => {
|
193
|
+
ALL_ACTIONS_DATA_TEST.forEach(({ type, dataTestId }) => {
|
194
|
+
render(<ResponseActions actions={{ [type]: { onClick: jest.fn(), 'data-testid': dataTestId } }} />);
|
195
|
+
expect(screen.getByTestId(dataTestId)).toBeTruthy();
|
196
|
+
});
|
197
|
+
});
|
198
|
+
|
184
199
|
it('should be able to add custom actions', () => {
|
185
200
|
CUSTOM_ACTIONS.forEach((action) => {
|
186
201
|
const key = Object.keys(action)[0];
|
@@ -192,12 +207,14 @@ describe('ResponseActions', () => {
|
|
192
207
|
onClick: action[key].onClick,
|
193
208
|
// doing this just because it's easier to test without a regex for the button name
|
194
209
|
ariaLabel: action[key].ariaLabel.toLowerCase(),
|
195
|
-
icon: action[key].icon
|
210
|
+
icon: action[key].icon,
|
211
|
+
'data-testid': action[key]
|
196
212
|
}
|
197
213
|
}}
|
198
214
|
/>
|
199
215
|
);
|
200
216
|
expect(screen.getByRole('button', { name: key })).toBeTruthy();
|
217
|
+
expect(screen.getByTestId(action[key])).toBeTruthy();
|
201
218
|
});
|
202
219
|
});
|
203
220
|
});
|
@@ -36,9 +36,12 @@ export interface ActionProps extends Omit<ButtonProps, 'ref'> {
|
|
36
36
|
'aria-controls'?: string;
|
37
37
|
}
|
38
38
|
|
39
|
+
type ExtendedActionProps = ActionProps & {
|
40
|
+
[key: string]: any;
|
41
|
+
};
|
39
42
|
export interface ResponseActionProps {
|
40
43
|
/** Props for message actions, such as feedback (positive or negative), copy button, share, and listen */
|
41
|
-
actions: Record<string,
|
44
|
+
actions: Record<string, ExtendedActionProps | undefined> & {
|
42
45
|
positive?: ActionProps;
|
43
46
|
negative?: ActionProps;
|
44
47
|
copy?: ActionProps;
|
@@ -78,6 +81,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
|
|
78
81
|
<div ref={responseActions} className="pf-chatbot__response-actions">
|
79
82
|
{positive && (
|
80
83
|
<ResponseActionButton
|
84
|
+
{...positive}
|
81
85
|
ariaLabel={positive.ariaLabel ?? 'Good response'}
|
82
86
|
clickedAriaLabel={positive.ariaLabel ?? 'Response recorded'}
|
83
87
|
onClick={(e) => handleClick(e, 'positive', positive.onClick)}
|
@@ -95,6 +99,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
|
|
95
99
|
)}
|
96
100
|
{negative && (
|
97
101
|
<ResponseActionButton
|
102
|
+
{...negative}
|
98
103
|
ariaLabel={negative.ariaLabel ?? 'Bad response'}
|
99
104
|
clickedAriaLabel={negative.ariaLabel ?? 'Response recorded'}
|
100
105
|
onClick={(e) => handleClick(e, 'negative', negative.onClick)}
|
@@ -112,6 +117,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
|
|
112
117
|
)}
|
113
118
|
{copy && (
|
114
119
|
<ResponseActionButton
|
120
|
+
{...copy}
|
115
121
|
ariaLabel={copy.ariaLabel ?? 'Copy'}
|
116
122
|
clickedAriaLabel={copy.ariaLabel ?? 'Copied'}
|
117
123
|
onClick={(e) => handleClick(e, 'copy', copy.onClick)}
|
@@ -129,6 +135,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
|
|
129
135
|
)}
|
130
136
|
{share && (
|
131
137
|
<ResponseActionButton
|
138
|
+
{...share}
|
132
139
|
ariaLabel={share.ariaLabel ?? 'Share'}
|
133
140
|
clickedAriaLabel={share.ariaLabel ?? 'Shared'}
|
134
141
|
onClick={(e) => handleClick(e, 'share', share.onClick)}
|
@@ -146,6 +153,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
|
|
146
153
|
)}
|
147
154
|
{listen && (
|
148
155
|
<ResponseActionButton
|
156
|
+
{...listen}
|
149
157
|
ariaLabel={listen.ariaLabel ?? 'Listen'}
|
150
158
|
clickedAriaLabel={listen.ariaLabel ?? 'Listening'}
|
151
159
|
onClick={(e) => handleClick(e, 'listen', listen.onClick)}
|
@@ -163,6 +171,7 @@ export const ResponseActions: React.FunctionComponent<ResponseActionProps> = ({
|
|
163
171
|
)}
|
164
172
|
{Object.keys(additionalActions).map((action) => (
|
165
173
|
<ResponseActionButton
|
174
|
+
{...additionalActions[action]}
|
166
175
|
key={action}
|
167
176
|
ariaLabel={additionalActions[action]?.ariaLabel}
|
168
177
|
clickedAriaLabel={additionalActions[action]?.clickedAriaLabel}
|