@patternfly/chatbot 6.3.0-prerelease.23 → 6.3.0-prerelease.25
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/ResponseActions/ResponseActions.js +27 -2
- package/dist/cjs/ResponseActions/ResponseActions.test.js +60 -0
- package/dist/css/main.css +6 -8
- package/dist/css/main.css.map +1 -1
- package/dist/esm/ResponseActions/ResponseActions.js +27 -2
- package/dist/esm/ResponseActions/ResponseActions.test.js +60 -0
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithClickedResponseActions.tsx +25 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithCustomResponseActions.tsx +1 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +17 -0
- package/src/Message/TextMessage/TextMessage.scss +2 -5
- package/src/ResponseActions/ResponseActions.test.tsx +98 -1
- package/src/ResponseActions/ResponseActions.tsx +31 -2
@@ -23,11 +23,35 @@ const ResponseActionButton_1 = __importDefault(require("./ResponseActionButton")
|
|
23
23
|
const ResponseActions = ({ actions }) => {
|
24
24
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
|
25
25
|
const [activeButton, setActiveButton] = (0, react_2.useState)();
|
26
|
+
const [clickStatePersisted, setClickStatePersisted] = (0, react_2.useState)(false);
|
27
|
+
(0, react_2.useEffect)(() => {
|
28
|
+
// Define the order of precedence for checking initial `isClicked`
|
29
|
+
const actionPrecedence = ['positive', 'negative', 'copy', 'share', 'download', 'listen'];
|
30
|
+
let initialActive;
|
31
|
+
// Check predefined actions first based on precedence
|
32
|
+
for (const actionName of actionPrecedence) {
|
33
|
+
const actionProp = actions[actionName];
|
34
|
+
if (actionProp === null || actionProp === void 0 ? void 0 : actionProp.isClicked) {
|
35
|
+
initialActive = actionName;
|
36
|
+
break;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
// If no predefined action was initially clicked, check additionalActions
|
40
|
+
if (!initialActive) {
|
41
|
+
const clickedActionName = Object.keys(additionalActions).find((actionName) => { var _a; return !actionPrecedence.includes(actionName) && ((_a = additionalActions[actionName]) === null || _a === void 0 ? void 0 : _a.isClicked); });
|
42
|
+
initialActive = clickedActionName;
|
43
|
+
}
|
44
|
+
if (initialActive) {
|
45
|
+
// Click state is explicitly controlled by consumer.
|
46
|
+
setClickStatePersisted(true);
|
47
|
+
}
|
48
|
+
setActiveButton(initialActive);
|
49
|
+
}, [actions]);
|
26
50
|
const { positive, negative, copy, share, download, listen } = actions, additionalActions = __rest(actions, ["positive", "negative", "copy", "share", "download", "listen"]);
|
27
51
|
const responseActions = (0, react_2.useRef)(null);
|
28
52
|
(0, react_2.useEffect)(() => {
|
29
53
|
const handleClickOutside = (e) => {
|
30
|
-
if (responseActions.current && !responseActions.current.contains(e.target)) {
|
54
|
+
if (responseActions.current && !responseActions.current.contains(e.target) && !clickStatePersisted) {
|
31
55
|
setActiveButton(undefined);
|
32
56
|
}
|
33
57
|
};
|
@@ -35,8 +59,9 @@ const ResponseActions = ({ actions }) => {
|
|
35
59
|
return () => {
|
36
60
|
window.removeEventListener('click', handleClickOutside);
|
37
61
|
};
|
38
|
-
}, []);
|
62
|
+
}, [clickStatePersisted]);
|
39
63
|
const handleClick = (e, id, onClick) => {
|
64
|
+
setClickStatePersisted(false);
|
40
65
|
setActiveButton(id);
|
41
66
|
onClick && onClick(e);
|
42
67
|
};
|
@@ -116,6 +116,66 @@ describe('ResponseActions', () => {
|
|
116
116
|
expect(goodBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
117
117
|
expect(badBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
118
118
|
}));
|
119
|
+
it('should handle isClicked prop within group of buttons correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
120
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: {
|
121
|
+
positive: { 'data-testid': 'positive-btn', onClick: jest.fn(), isClicked: true },
|
122
|
+
negative: { 'data-testid': 'negative-btn', onClick: jest.fn() }
|
123
|
+
} }));
|
124
|
+
expect(react_1.screen.getByTestId('positive-btn')).toHaveClass('pf-chatbot__button--response-action-clicked');
|
125
|
+
expect(react_1.screen.getByTestId('negative-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
126
|
+
}));
|
127
|
+
it('should set "listen" button as active if its `isClicked` is true', () => __awaiter(void 0, void 0, void 0, function* () {
|
128
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: {
|
129
|
+
positive: { 'data-testid': 'positive-btn', onClick: jest.fn(), isClicked: false },
|
130
|
+
negative: { 'data-testid': 'negative-btn', onClick: jest.fn(), isClicked: false },
|
131
|
+
listen: { 'data-testid': 'listen-btn', onClick: jest.fn(), isClicked: true }
|
132
|
+
} }));
|
133
|
+
expect(react_1.screen.getByTestId('listen-btn')).toHaveClass('pf-chatbot__button--response-action-clicked');
|
134
|
+
expect(react_1.screen.getByTestId('positive-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
135
|
+
expect(react_1.screen.getByTestId('negative-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
136
|
+
}));
|
137
|
+
it('should prioritize "positive" when both "positive" and "negative" are set to clicked', () => __awaiter(void 0, void 0, void 0, function* () {
|
138
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: {
|
139
|
+
positive: { 'data-testid': 'positive-btn', onClick: jest.fn(), isClicked: true },
|
140
|
+
negative: { 'data-testid': 'negative-btn', onClick: jest.fn(), isClicked: true }
|
141
|
+
} }));
|
142
|
+
// Positive button should take precendence
|
143
|
+
expect(react_1.screen.getByTestId('positive-btn')).toHaveClass('pf-chatbot__button--response-action-clicked');
|
144
|
+
expect(react_1.screen.getByTestId('negative-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
145
|
+
}));
|
146
|
+
it('should set an additional action button as active if it is initially clicked and no predefined are clicked', () => __awaiter(void 0, void 0, void 0, function* () {
|
147
|
+
const [additionalActions] = CUSTOM_ACTIONS;
|
148
|
+
const customActions = Object.assign({ positive: { 'data-testid': 'positive', onClick: jest.fn(), isClicked: false }, negative: { 'data-testid': 'negative', onClick: jest.fn(), isClicked: false } }, Object.keys(additionalActions).reduce((acc, actionKey) => {
|
149
|
+
acc[actionKey] = Object.assign(Object.assign({}, additionalActions[actionKey]), { 'data-testid': actionKey, isClicked: actionKey === 'regenerate' });
|
150
|
+
return acc;
|
151
|
+
}, {}));
|
152
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: customActions }));
|
153
|
+
Object.keys(customActions).forEach((actionKey) => {
|
154
|
+
if (actionKey === 'regenerate') {
|
155
|
+
expect(react_1.screen.getByTestId(actionKey)).toHaveClass('pf-chatbot__button--response-action-clicked');
|
156
|
+
}
|
157
|
+
else {
|
158
|
+
// Other actions should not have clicked class
|
159
|
+
expect(react_1.screen.getByTestId(actionKey)).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
160
|
+
}
|
161
|
+
});
|
162
|
+
}));
|
163
|
+
it('should activate the clicked button and deactivate any previously active button', () => __awaiter(void 0, void 0, void 0, function* () {
|
164
|
+
const actions = {
|
165
|
+
positive: { 'data-testid': 'positive', onClick: jest.fn(), isClicked: false },
|
166
|
+
negative: { 'data-testid': 'negative', onClick: jest.fn(), isClicked: true }
|
167
|
+
};
|
168
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: actions }));
|
169
|
+
const negativeBtn = react_1.screen.getByTestId('negative');
|
170
|
+
const positiveBtn = react_1.screen.getByTestId('positive');
|
171
|
+
// negative button is initially clicked
|
172
|
+
expect(negativeBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
|
173
|
+
expect(positiveBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
174
|
+
yield user_event_1.default.click(positiveBtn);
|
175
|
+
// positive button should now have the clicked class
|
176
|
+
expect(positiveBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
|
177
|
+
expect(negativeBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
178
|
+
}));
|
119
179
|
it('should render buttons correctly', () => {
|
120
180
|
ALL_ACTIONS.forEach(({ type, label }) => {
|
121
181
|
(0, react_1.render)((0, jsx_runtime_1.jsx)(ResponseActions_1.default, { actions: { [type]: { onClick: jest.fn() } } }));
|
package/dist/css/main.css
CHANGED
@@ -1210,14 +1210,13 @@
|
|
1210
1210
|
--pf-v6-c-button--hover--Color: var(--pf-t--global--color--nonstatus--blue--hover);
|
1211
1211
|
}
|
1212
1212
|
|
1213
|
+
.pf-chatbot__message-and-actions {
|
1214
|
+
width: 100%;
|
1215
|
+
}
|
1213
1216
|
.pf-chatbot__message-and-actions blockquote .pf-chatbot__message-text {
|
1214
1217
|
display: inline-block;
|
1215
1218
|
}
|
1216
1219
|
|
1217
|
-
.pf-chatbot__message-and-actions:has(.pf-chatbot__message-table) {
|
1218
|
-
width: 100%;
|
1219
|
-
}
|
1220
|
-
|
1221
1220
|
.pf-chatbot__message-text {
|
1222
1221
|
width: fit-content;
|
1223
1222
|
padding: var(--pf-t--global--spacer--sm) 0 var(--pf-t--global--spacer--sm) 0;
|
@@ -1367,14 +1366,13 @@
|
|
1367
1366
|
display: block;
|
1368
1367
|
}
|
1369
1368
|
|
1369
|
+
.pf-chatbot__message-and-actions {
|
1370
|
+
width: 100%;
|
1371
|
+
}
|
1370
1372
|
.pf-chatbot__message-and-actions blockquote .pf-chatbot__message-text {
|
1371
1373
|
display: inline-block;
|
1372
1374
|
}
|
1373
1375
|
|
1374
|
-
.pf-chatbot__message-and-actions:has(.pf-chatbot__message-table) {
|
1375
|
-
width: 100%;
|
1376
|
-
}
|
1377
|
-
|
1378
1376
|
.pf-chatbot__message-text {
|
1379
1377
|
width: fit-content;
|
1380
1378
|
padding: var(--pf-t--global--spacer--sm) 0 var(--pf-t--global--spacer--sm) 0;
|
package/dist/css/main.css.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sourceRoot":"","sources":["../../src/AttachMenu/AttachMenu.scss","../../src/Chatbot/Chatbot.scss","../../src/ChatbotAlert/ChatbotAlert.scss","../../src/ChatbotContent/ChatbotContent.scss","../../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss","../../src/ChatbotFooter/ChatbotFootnote.scss","../../src/ChatbotFooter/ChatbotFooter.scss","../../src/ChatbotHeader/ChatbotHeader.scss","../../src/ChatbotModal/ChatbotModal.scss","../../src/ChatbotPopover/ChatbotPopover.scss","../../src/ChatbotToggle/ChatbotToggle.scss","../../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.scss","../../src/CodeModal/CodeModal.scss","../../src/Compare/Compare.scss","../../src/FileDetails/FileDetails.scss","../../src/FileDetailsLabel/FileDetailsLabel.scss","../../src/FileDropZone/FileDropZone.scss","../../src/Message/Message.scss","../../src/Message/MessageLoading.scss","../../src/Message/CodeBlockMessage/CodeBlockMessage.scss","../../src/Message/TextMessage/TextMessage.scss","../../src/Message/ImageMessage/ImageMessage.scss","../../src/Message/ListMessage/ListMessage.scss","../../src/Message/TableMessage/TableMessage.scss","../../src/Message/QuickStarts/QuickStartTile.scss","../../src/Message/QuickResponse/QuickResponse.scss","../../src/Message/UserFeedback/UserFeedback.scss","../../src/MessageBar/AttachButton.scss","../../src/MessageBar/MicrophoneButton.scss","../../src/MessageBar/SendButton.scss","../../src/MessageBar/StopButton.scss","../../src/MessageBar/MessageBar.scss","../../src/MessageBox/JumpButton.scss","../../src/MessageBox/MessageBox.scss","../../src/ResponseActions/ResponseActions.scss","../../src/Settings/Settings.scss","../../src/SourcesCard/SourcesCard.scss","../../src/SourceDetailsMenuItem/SourceDetailsMenuItem.scss","../../src/TermsOfUse/TermsOfUse.scss","../../src/main.scss"],"names":[],"mappings":";AAAA;EACE;EACA;;;AAGF;AACE;AAsBA;AASA;;AA9BA;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAGF;AACE;;AACA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;;AAGF;EACE;;AAIF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;ACxDJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;AAKF;EAvBF;IAwBI;IACA;;;AAIF;EA7BF;IA8BI;;;;AAOJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;EAXF;IAYI;;;;AAOJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAMF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;AAIF;EAdF;IAeI;;;;AAIJ;EACE;;;AAGF;AAAA;AAAA;EAGE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAOJ;EACE;;;ACpIF;EACE;EACA;EACA;;;ACAF;EACE;EACA;EACA;EACA;EACA;;AAGA;EARF;IASI;;;;AAOJ;EAII;AAAA;AAAA;IACE;IACA;;;ACrBJ;EACE;EACA;;AAIF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEF;EACE;;AAGF;EACE;;AAGF;EACE;;;AAMJ;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAIF;EACE;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAKA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAKA;EACE;;;AASJ;EACE;;;AASF;AAAA;EACE;;AACA;AAAA;EACE;;;AASJ;EACE;;AACA;EACE;EACA;;AAEF;EACE;;;AAUF;AAAA;AAAA;AAAA;EACE;;;AAKN;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAKE;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;;AC1ON;EACE;;AAEA;EACE;EACA;;;ACHJ;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;;;AAMF;EAGI;AAAA;IACE;;EACA;AAAA;IACE;;EAGJ;AAAA;IACE;IACA;IACA;;;AASJ;EACE;;;AAQF;EACE;;;AAIJ;EACE;EACA;;;AC3DF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAEA;EACE;;AAKJ;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;;AAQN;EAGI;AAAA;IACE;;EAEF;AAAA;IACE;;;AAUJ;AAAA;EACE;;;AAOJ;AAAA;EAEE;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;AAGF;AAAA;AAAA;AAAA;EAEE;EACA;EACA;;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;;AAOJ;EACE;;;AAOJ;AAAA;EAEE;;;AAGF;EACE;;;AAGF;EACE;;;AAOA;EACE;EACA;;AAGF;EACE;EACA;;;AAIJ;AAAA;EAEE;EACA;;;AAGF;EACE;;;AClKF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAEF;EACE;;;AAOJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAGJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAOJ;EACE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAQE;EACE;;;AAQN;EACE;;;AAOA;EACE;;AAGF;EACE;EACA;;;ACjGF;EACE;;AAMA;EACE;;AAEF;EACE;;AAEF;EACE;;AAIF;EACE;EACA;;AAEF;EACE;;;ACxBN;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAGF;EACE;;AAIF;EACE;EACA;;;AAIJ;EACE;EACA;EACA;;;AC3BF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;;AAIJ;EACE;EACA;;AAEA;EACE;;;AAOJ;EAIM;AAAA;IACE;IACA;;;ACpDN;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;AACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;AAAA;AAAA;EAGA;EACA;;AAEF;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;;AAEF;EACE;;AAGA;EACE;;;AAUF;EACE;EACA;;;AAKN;EACE;;;AAGF;EACE;;;AAIA;EACE;;;AC5FJ;EACE;EACA;EACA;EACA;;;AAEF;EACE;;AAEA;EACE;EACA;EACA;;;AAGJ;EACE;EACA;EACA;;AAEA;EALF;IAMI;;;AAGF;EACE;;AAEA;EAHF;IAII;;;;AAKN;EACE;;AAEA;EACE;;AAGF;EACE;;AAIA;EADF;IAEI;;;;AAIN;EACE;;AAEA;EAHF;IAII;;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EARF;IASI;IACA;IACA;;;;ACrEJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAIF;EACE;EACA;EACA;EACA;EACA;;;ACvBF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EAEA;EACA;EACA;;AACA;EACE;;AAGF;AAAA;EAEE;EACA;;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;;;AAKF;EACE;;AAGF;EACE;;;AAIJ;AAAA;EAEE;EACA;;AAEA;AAAA;EACE;;;AAKF;EACE;;;AAMF;AAAA;EACE;;;AC/DJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;AAGA;EANF;IAOI;;;;AAIJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;AACA;EACE;EACA;EACA;EACA;;;AAME;EADF;IAEI;IACA;IACA;;EAEA;IACE;;;;AChDR;EACE;EACA;EACA;EACA;;AAIA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAKF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAKF;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;;AAIF;EACE;EACA;EACA;;AAEA;EACE;;AAKJ;EACE;;AAEF;EACE;;AAMJ;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;;AAMJ;EACE;EACA;EACA;;;AAGF;EACE;;;ACjGF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IACE;;EAEF;IAEE;;;;AC9CN;EACE;EACA;EACA;EACA;;AAGA;EACE;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEA;EAEE;;AAMN;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA;;;AAIA;EACE;EACA;;;AChFA;EACE;;;AAMN;EACE;;;AAIF;EACE;EACA;EACA;;AAEA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;EACA;EACA;;AACA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;;AAWF;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AH8BJ;EACE;EACA;;AAEA;EACE;;AAIJ;EACE;;AAGF;EACE;EACA;;AAGF;EACE;;;AE/HJ;EACE;EACA;EACA;EACA;;AAGA;EACE;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEA;EAEE;;AAMN;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA;;;AAIA;EACE;EACA;;;AEtFJ;EACE;EACA;EACA;EACA;EAGA;;;ADDE;EACE;;;AAMN;EACE;;;AAIF;EACE;EACA;EACA;;AAEA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;EACA;EACA;;AACA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;;AAWF;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AE7EN;AAAA;EAEE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;;AAKF;AAAA;EAEE;EACA;EACA;;;ACtBJ;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAGF;EACE;;;ALjBJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IACE;;EAEF;IAEE;;;;AMjDN;EACE;EACA;;AAEA;EAJF;IAKI;IACA;;;AAKA;EACE;;;AAOF;EACE;;;ACnBJ;EACE;;AAEA;EAHF;IAII;;;AAGF;EAPF;IAQI;;;AAKF;EACE;EACA;;AAIJ;AAAA;EAEE;EACA;;AAIF;EACE;EACA;EACA;;;AC7BJ;EACE;EACA;EACA;;;AAIF;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAIF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAKA;EACE;;;AAKF;EACE;;AAGF;EACE;;AAIA;EACE;;;ACnEN;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAKA;EACE;;AAIJ;EAEE;;AAEA;EACE;;AAKA;EACE;;;AASR;EACE;EACA;EACA;EACA;;;ACzCF;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAMA;EACE;;AAKJ;EACE;EACA;;AAGA;EACE;;AAKA;EACE;;;AAMR;EACE;IACE;;EAEF;IACE;;;AAOJ;EACE;EACA;EACA;EACA;;;ACrDF;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EAEE;EACA;;AAEA;EACE;;;AAMJ;EACE;;AACA;EACE;;AAIJ;EACE;EACA;;AAGF;AAAA;EAEE;;;AAIJ;EACE;IACE;IACA;;EAEF;IACE;IACA;;;AAOJ;EACE;EACA;EACA;EACA;;;AC1DF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;;AAEA;EACE;;AAKA;EACE;;;AASR;EACE;EACA;EACA;EACA;;;AClCF;EACE;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;IACE;IACA;;;AAKF;EACE;IACE;IACA;;;;AAQN;EACE;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;;AC1HJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAIF;;AAEA;EACE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAIF;EA3CF;IA4CI;;;;AC9CJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAIA;EAVF;IAWI;;;AAGF;EAdF;IAeI;;;;AAIJ;EACE;;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EAII;AAAA;AAAA;IACE;IACA;;;AAMJ;EACE;;;AD9CJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAIF;;AAEA;EACE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAIF;EA3CF;IA4CI;;;;AEhDJ;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEF;EACE;EACA;;;AAKN;EACE;EACA;;;AC1BF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;;;AAIA;EACE;EACA;;;AAIJ;EACE;;;AC3CF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;AAAA;EACE;;AAGJ;EACE;EACA;;AAKA;AAAA;EACE;;AAGJ;EACE;;;AAON;EACE;EACA;;;AChFJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAIF;EACE;EACA;;;AAGA;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AC9BA;EACE;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAIF;EACE;IACE;IACA;;;;AAKN;AAAA;EAGE;;AAGE;AAAA;EACE;;AAIJ;AAAA;EACE;;;AAKF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;;;AChDJ;EAKE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EASA;EACA;EAEA;EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAMA;EAKA;EACA;EACA;EAEA;EAEA;;;AAMF;EACE;EACA;EAEA;EAEA;EACA;;;AAGF;EACE;EACA","file":"main.css"}
|
1
|
+
{"version":3,"sourceRoot":"","sources":["../../src/AttachMenu/AttachMenu.scss","../../src/Chatbot/Chatbot.scss","../../src/ChatbotAlert/ChatbotAlert.scss","../../src/ChatbotContent/ChatbotContent.scss","../../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss","../../src/ChatbotFooter/ChatbotFootnote.scss","../../src/ChatbotFooter/ChatbotFooter.scss","../../src/ChatbotHeader/ChatbotHeader.scss","../../src/ChatbotModal/ChatbotModal.scss","../../src/ChatbotPopover/ChatbotPopover.scss","../../src/ChatbotToggle/ChatbotToggle.scss","../../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.scss","../../src/CodeModal/CodeModal.scss","../../src/Compare/Compare.scss","../../src/FileDetails/FileDetails.scss","../../src/FileDetailsLabel/FileDetailsLabel.scss","../../src/FileDropZone/FileDropZone.scss","../../src/Message/Message.scss","../../src/Message/MessageLoading.scss","../../src/Message/CodeBlockMessage/CodeBlockMessage.scss","../../src/Message/TextMessage/TextMessage.scss","../../src/Message/ImageMessage/ImageMessage.scss","../../src/Message/ListMessage/ListMessage.scss","../../src/Message/TableMessage/TableMessage.scss","../../src/Message/QuickStarts/QuickStartTile.scss","../../src/Message/QuickResponse/QuickResponse.scss","../../src/Message/UserFeedback/UserFeedback.scss","../../src/MessageBar/AttachButton.scss","../../src/MessageBar/MicrophoneButton.scss","../../src/MessageBar/SendButton.scss","../../src/MessageBar/StopButton.scss","../../src/MessageBar/MessageBar.scss","../../src/MessageBox/JumpButton.scss","../../src/MessageBox/MessageBox.scss","../../src/ResponseActions/ResponseActions.scss","../../src/Settings/Settings.scss","../../src/SourcesCard/SourcesCard.scss","../../src/SourceDetailsMenuItem/SourceDetailsMenuItem.scss","../../src/TermsOfUse/TermsOfUse.scss","../../src/main.scss"],"names":[],"mappings":";AAAA;EACE;EACA;;;AAGF;AACE;AAsBA;AASA;;AA9BA;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAGF;AACE;;AACA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;;AAGF;EACE;;AAIF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;ACxDJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;AAKF;EAvBF;IAwBI;IACA;;;AAIF;EA7BF;IA8BI;;;;AAOJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;EAXF;IAYI;;;;AAOJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAMF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;AAIF;EAdF;IAeI;;;;AAIJ;EACE;;;AAGF;AAAA;AAAA;EAGE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAOJ;EACE;;;ACpIF;EACE;EACA;EACA;;;ACAF;EACE;EACA;EACA;EACA;EACA;;AAGA;EARF;IASI;;;;AAOJ;EAII;AAAA;AAAA;IACE;IACA;;;ACrBJ;EACE;EACA;;AAIF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEF;EACE;;AAGF;EACE;;AAGF;EACE;;;AAMJ;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAIF;EACE;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAKA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAKA;EACE;;;AASJ;EACE;;;AASF;AAAA;EACE;;AACA;AAAA;EACE;;;AASJ;EACE;;AACA;EACE;EACA;;AAEF;EACE;;;AAUF;AAAA;AAAA;AAAA;EACE;;;AAKN;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAKE;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;;AC1ON;EACE;;AAEA;EACE;EACA;;;ACHJ;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;;;AAMF;EAGI;AAAA;IACE;;EACA;AAAA;IACE;;EAGJ;AAAA;IACE;IACA;IACA;;;AASJ;EACE;;;AAQF;EACE;;;AAIJ;EACE;EACA;;;AC3DF;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAEA;EACE;;AAKJ;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;;AAQN;EAGI;AAAA;IACE;;EAEF;AAAA;IACE;;;AAUJ;AAAA;EACE;;;AAOJ;AAAA;EAEE;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;AAGF;AAAA;AAAA;AAAA;EAEE;EACA;EACA;;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;;AAOJ;EACE;;;AAOJ;AAAA;EAEE;;;AAGF;EACE;;;AAGF;EACE;;;AAOA;EACE;EACA;;AAGF;EACE;EACA;;;AAIJ;AAAA;EAEE;EACA;;;AAGF;EACE;;;AClKF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAEF;EACE;;;AAOJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAGJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAOJ;EACE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAQE;EACE;;;AAQN;EACE;;;AAOA;EACE;;AAGF;EACE;EACA;;;ACjGF;EACE;;AAMA;EACE;;AAEF;EACE;;AAEF;EACE;;AAIF;EACE;EACA;;AAEF;EACE;;;ACxBN;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAGF;EACE;;AAIF;EACE;EACA;;;AAIJ;EACE;EACA;EACA;;;AC3BF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;;;AAIJ;EACE;EACA;;AAEA;EACE;;;AAOJ;EAIM;AAAA;IACE;IACA;;;ACpDN;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;AACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;AAAA;AAAA;EAGA;EACA;;AAEF;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;;AAEF;EACE;;AAGA;EACE;;;AAUF;EACE;EACA;;;AAKN;EACE;;;AAGF;EACE;;;AAIA;EACE;;;AC5FJ;EACE;EACA;EACA;EACA;;;AAEF;EACE;;AAEA;EACE;EACA;EACA;;;AAGJ;EACE;EACA;EACA;;AAEA;EALF;IAMI;;;AAGF;EACE;;AAEA;EAHF;IAII;;;;AAKN;EACE;;AAEA;EACE;;AAGF;EACE;;AAIA;EADF;IAEI;;;;AAIN;EACE;;AAEA;EAHF;IAII;;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EARF;IASI;IACA;IACA;;;;ACrEJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAIF;EACE;EACA;EACA;EACA;EACA;;;ACvBF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EAEA;EACA;EACA;;AACA;EACE;;AAGF;AAAA;EAEE;EACA;;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;;;AAKF;EACE;;AAGF;EACE;;;AAIJ;AAAA;EAEE;EACA;;AAEA;AAAA;EACE;;;AAKF;EACE;;;AAMF;AAAA;EACE;;;AC/DJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;AAGA;EANF;IAOI;;;;AAIJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;AACA;EACE;EACA;EACA;EACA;;;AAME;EADF;IAEI;IACA;IACA;;EAEA;IACE;;;;AChDR;EACE;EACA;EACA;EACA;;AAIA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAKF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAKF;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;;AAIF;EACE;EACA;EACA;;AAEA;EACE;;AAKJ;EACE;;AAEF;EACE;;AAMJ;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;;AAMJ;EACE;EACA;EACA;;;AAGF;EACE;;;ACjGF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IACE;;EAEF;IAEE;;;;AC9CN;EACE;EACA;EACA;EACA;;AAGA;EACE;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEA;EAEE;;AAMN;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA;;;AAIA;EACE;EACA;;;AClFJ;EACE;;AAGE;EACE;;;AAMN;EACE;EACA;EACA;;AAEA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;EACA;EACA;;AACA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;;AAWF;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AHiCJ;EACE;EACA;;AAEA;EACE;;AAIJ;EACE;;AAGF;EACE;EACA;;AAGF;EACE;;;AE/HJ;EACE;EACA;EACA;EACA;;AAGA;EACE;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEA;EAEE;;AAMN;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA;;;AAIA;EACE;EACA;;;AEtFJ;EACE;EACA;EACA;EACA;EAGA;;;ADHF;EACE;;AAGE;EACE;;;AAMN;EACE;EACA;EACA;;AAEA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;EACA;EACA;;AACA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;;AAWF;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AE1EN;AAAA;EAEE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;;AAKF;AAAA;EAEE;EACA;EACA;;;ACtBJ;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAGF;EACE;;;ALjBJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IACE;;EAEF;IAEE;;;;AMjDN;EACE;EACA;;AAEA;EAJF;IAKI;IACA;;;AAKA;EACE;;;AAOF;EACE;;;ACnBJ;EACE;;AAEA;EAHF;IAII;;;AAGF;EAPF;IAQI;;;AAKF;EACE;EACA;;AAIJ;AAAA;EAEE;EACA;;AAIF;EACE;EACA;EACA;;;AC7BJ;EACE;EACA;EACA;;;AAIF;EACE;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;;;AAIF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAKA;EACE;;;AAKF;EACE;;AAGF;EACE;;AAIA;EACE;;;ACnEN;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAKA;EACE;;AAIJ;EAEE;;AAEA;EACE;;AAKA;EACE;;;AASR;EACE;EACA;EACA;EACA;;;ACzCF;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAMA;EACE;;AAKJ;EACE;EACA;;AAGA;EACE;;AAKA;EACE;;;AAMR;EACE;IACE;;EAEF;IACE;;;AAOJ;EACE;EACA;EACA;EACA;;;ACrDF;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EAEE;EACA;;AAEA;EACE;;;AAMJ;EACE;;AACA;EACE;;AAIJ;EACE;EACA;;AAGF;AAAA;EAEE;;;AAIJ;EACE;IACE;IACA;;EAEF;IACE;IACA;;;AAOJ;EACE;EACA;EACA;EACA;;;AC1DF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;;AAEA;EACE;;AAKA;EACE;;;AASR;EACE;EACA;EACA;EACA;;;AClCF;EACE;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAGA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;IACE;IACA;;;AAKF;EACE;IACE;IACA;;;;AAQN;EACE;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;;AC1HJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAIF;;AAEA;EACE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAIF;EA3CF;IA4CI;;;;AC9CJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAIA;EAVF;IAWI;;;AAGF;EAdF;IAeI;;;;AAIJ;EACE;;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EAII;AAAA;AAAA;IACE;IACA;;;AAMJ;EACE;;;AD9CJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAIF;;AAEA;EACE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAIF;EA3CF;IA4CI;;;;AEhDJ;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEF;EACE;EACA;;;AAKN;EACE;EACA;;;AC1BF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;;;AAIA;EACE;EACA;;;AAIJ;EACE;;;AC3CF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;AAAA;EACE;;AAGJ;EACE;EACA;;AAKA;AAAA;EACE;;AAGJ;EACE;;;AAON;EACE;EACA;;;AChFJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAIF;EACE;EACA;;;AAGA;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AC9BA;EACE;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;;AAIF;EACE;IACE;IACA;;;;AAKN;AAAA;EAGE;;AAGE;AAAA;EACE;;AAIJ;AAAA;EACE;;;AAKF;EACE;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;;;AChDJ;EAKE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EASA;EACA;EAEA;EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAMA;EAKA;EACA;EACA;EAEA;EAEA;;;AAMF;EACE;EACA;EAEA;EAEA;EACA;;;AAGF;EACE;EACA","file":"main.css"}
|
@@ -17,11 +17,35 @@ import ResponseActionButton from './ResponseActionButton';
|
|
17
17
|
export const ResponseActions = ({ actions }) => {
|
18
18
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
|
19
19
|
const [activeButton, setActiveButton] = useState();
|
20
|
+
const [clickStatePersisted, setClickStatePersisted] = useState(false);
|
21
|
+
useEffect(() => {
|
22
|
+
// Define the order of precedence for checking initial `isClicked`
|
23
|
+
const actionPrecedence = ['positive', 'negative', 'copy', 'share', 'download', 'listen'];
|
24
|
+
let initialActive;
|
25
|
+
// Check predefined actions first based on precedence
|
26
|
+
for (const actionName of actionPrecedence) {
|
27
|
+
const actionProp = actions[actionName];
|
28
|
+
if (actionProp === null || actionProp === void 0 ? void 0 : actionProp.isClicked) {
|
29
|
+
initialActive = actionName;
|
30
|
+
break;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
// If no predefined action was initially clicked, check additionalActions
|
34
|
+
if (!initialActive) {
|
35
|
+
const clickedActionName = Object.keys(additionalActions).find((actionName) => { var _a; return !actionPrecedence.includes(actionName) && ((_a = additionalActions[actionName]) === null || _a === void 0 ? void 0 : _a.isClicked); });
|
36
|
+
initialActive = clickedActionName;
|
37
|
+
}
|
38
|
+
if (initialActive) {
|
39
|
+
// Click state is explicitly controlled by consumer.
|
40
|
+
setClickStatePersisted(true);
|
41
|
+
}
|
42
|
+
setActiveButton(initialActive);
|
43
|
+
}, [actions]);
|
20
44
|
const { positive, negative, copy, share, download, listen } = actions, additionalActions = __rest(actions, ["positive", "negative", "copy", "share", "download", "listen"]);
|
21
45
|
const responseActions = useRef(null);
|
22
46
|
useEffect(() => {
|
23
47
|
const handleClickOutside = (e) => {
|
24
|
-
if (responseActions.current && !responseActions.current.contains(e.target)) {
|
48
|
+
if (responseActions.current && !responseActions.current.contains(e.target) && !clickStatePersisted) {
|
25
49
|
setActiveButton(undefined);
|
26
50
|
}
|
27
51
|
};
|
@@ -29,8 +53,9 @@ export const ResponseActions = ({ actions }) => {
|
|
29
53
|
return () => {
|
30
54
|
window.removeEventListener('click', handleClickOutside);
|
31
55
|
};
|
32
|
-
}, []);
|
56
|
+
}, [clickStatePersisted]);
|
33
57
|
const handleClick = (e, id, onClick) => {
|
58
|
+
setClickStatePersisted(false);
|
34
59
|
setActiveButton(id);
|
35
60
|
onClick && onClick(e);
|
36
61
|
};
|
@@ -111,6 +111,66 @@ describe('ResponseActions', () => {
|
|
111
111
|
expect(goodBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
112
112
|
expect(badBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
113
113
|
}));
|
114
|
+
it('should handle isClicked prop within group of buttons correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
115
|
+
render(_jsx(ResponseActions, { actions: {
|
116
|
+
positive: { 'data-testid': 'positive-btn', onClick: jest.fn(), isClicked: true },
|
117
|
+
negative: { 'data-testid': 'negative-btn', onClick: jest.fn() }
|
118
|
+
} }));
|
119
|
+
expect(screen.getByTestId('positive-btn')).toHaveClass('pf-chatbot__button--response-action-clicked');
|
120
|
+
expect(screen.getByTestId('negative-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
121
|
+
}));
|
122
|
+
it('should set "listen" button as active if its `isClicked` is true', () => __awaiter(void 0, void 0, void 0, function* () {
|
123
|
+
render(_jsx(ResponseActions, { actions: {
|
124
|
+
positive: { 'data-testid': 'positive-btn', onClick: jest.fn(), isClicked: false },
|
125
|
+
negative: { 'data-testid': 'negative-btn', onClick: jest.fn(), isClicked: false },
|
126
|
+
listen: { 'data-testid': 'listen-btn', onClick: jest.fn(), isClicked: true }
|
127
|
+
} }));
|
128
|
+
expect(screen.getByTestId('listen-btn')).toHaveClass('pf-chatbot__button--response-action-clicked');
|
129
|
+
expect(screen.getByTestId('positive-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
130
|
+
expect(screen.getByTestId('negative-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
131
|
+
}));
|
132
|
+
it('should prioritize "positive" when both "positive" and "negative" are set to clicked', () => __awaiter(void 0, void 0, void 0, function* () {
|
133
|
+
render(_jsx(ResponseActions, { actions: {
|
134
|
+
positive: { 'data-testid': 'positive-btn', onClick: jest.fn(), isClicked: true },
|
135
|
+
negative: { 'data-testid': 'negative-btn', onClick: jest.fn(), isClicked: true }
|
136
|
+
} }));
|
137
|
+
// Positive button should take precendence
|
138
|
+
expect(screen.getByTestId('positive-btn')).toHaveClass('pf-chatbot__button--response-action-clicked');
|
139
|
+
expect(screen.getByTestId('negative-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
140
|
+
}));
|
141
|
+
it('should set an additional action button as active if it is initially clicked and no predefined are clicked', () => __awaiter(void 0, void 0, void 0, function* () {
|
142
|
+
const [additionalActions] = CUSTOM_ACTIONS;
|
143
|
+
const customActions = Object.assign({ positive: { 'data-testid': 'positive', onClick: jest.fn(), isClicked: false }, negative: { 'data-testid': 'negative', onClick: jest.fn(), isClicked: false } }, Object.keys(additionalActions).reduce((acc, actionKey) => {
|
144
|
+
acc[actionKey] = Object.assign(Object.assign({}, additionalActions[actionKey]), { 'data-testid': actionKey, isClicked: actionKey === 'regenerate' });
|
145
|
+
return acc;
|
146
|
+
}, {}));
|
147
|
+
render(_jsx(ResponseActions, { actions: customActions }));
|
148
|
+
Object.keys(customActions).forEach((actionKey) => {
|
149
|
+
if (actionKey === 'regenerate') {
|
150
|
+
expect(screen.getByTestId(actionKey)).toHaveClass('pf-chatbot__button--response-action-clicked');
|
151
|
+
}
|
152
|
+
else {
|
153
|
+
// Other actions should not have clicked class
|
154
|
+
expect(screen.getByTestId(actionKey)).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
155
|
+
}
|
156
|
+
});
|
157
|
+
}));
|
158
|
+
it('should activate the clicked button and deactivate any previously active button', () => __awaiter(void 0, void 0, void 0, function* () {
|
159
|
+
const actions = {
|
160
|
+
positive: { 'data-testid': 'positive', onClick: jest.fn(), isClicked: false },
|
161
|
+
negative: { 'data-testid': 'negative', onClick: jest.fn(), isClicked: true }
|
162
|
+
};
|
163
|
+
render(_jsx(ResponseActions, { actions: actions }));
|
164
|
+
const negativeBtn = screen.getByTestId('negative');
|
165
|
+
const positiveBtn = screen.getByTestId('positive');
|
166
|
+
// negative button is initially clicked
|
167
|
+
expect(negativeBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
|
168
|
+
expect(positiveBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
169
|
+
yield userEvent.click(positiveBtn);
|
170
|
+
// positive button should now have the clicked class
|
171
|
+
expect(positiveBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
|
172
|
+
expect(negativeBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
173
|
+
}));
|
114
174
|
it('should render buttons correctly', () => {
|
115
175
|
ALL_ACTIONS.forEach(({ type, label }) => {
|
116
176
|
render(_jsx(ResponseActions, { actions: { [type]: { onClick: jest.fn() } } }));
|
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.25",
|
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",
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { FunctionComponent } from 'react';
|
2
|
+
|
3
|
+
import Message from '@patternfly/chatbot/dist/dynamic/Message';
|
4
|
+
import patternflyAvatar from './patternfly_avatar.jpg';
|
5
|
+
|
6
|
+
export const ResponseActionClickedExample: FunctionComponent = () => (
|
7
|
+
<Message
|
8
|
+
name="Bot"
|
9
|
+
role="bot"
|
10
|
+
avatar={patternflyAvatar}
|
11
|
+
content="I updated your account with those settings. You're ready to set up your first dashboard!"
|
12
|
+
actions={{
|
13
|
+
// eslint-disable-next-line no-console
|
14
|
+
positive: { onClick: () => console.log('Good response'), isClicked: true },
|
15
|
+
// eslint-disable-next-line no-console
|
16
|
+
negative: { onClick: () => console.log('Bad response') },
|
17
|
+
// eslint-disable-next-line no-console
|
18
|
+
copy: { onClick: () => console.log('Copy') },
|
19
|
+
// eslint-disable-next-line no-console
|
20
|
+
download: { onClick: () => console.log('Download') },
|
21
|
+
// eslint-disable-next-line no-console
|
22
|
+
listen: { onClick: () => console.log('Listen') }
|
23
|
+
}}
|
24
|
+
/>
|
25
|
+
);
|
@@ -15,6 +15,7 @@ export const CustomActionExample: FunctionComponent = () => (
|
|
15
15
|
regenerate: {
|
16
16
|
ariaLabel: 'Regenerate',
|
17
17
|
clickedAriaLabel: 'Regenerated',
|
18
|
+
isClicked: true,
|
18
19
|
// eslint-disable-next-line no-console
|
19
20
|
onClick: () => console.log('Clicked regenerate'),
|
20
21
|
tooltipContent: 'Regenerate',
|
@@ -79,6 +79,22 @@ You can add actions to a message, to allow users to interact with the message co
|
|
79
79
|
|
80
80
|
```
|
81
81
|
|
82
|
+
### Message actions clicked state
|
83
|
+
|
84
|
+
You can apply a clicked state to message actions, to convey that the action has previously been selected.
|
85
|
+
|
86
|
+
To define which message response action should show a clicked state when the `<ResponseActions>` component first renders, use the `isClicked` boolean property within each action's configuration object.
|
87
|
+
|
88
|
+
To make an action button appear active by default, set `isClicked: true`. Only 1 action can be visually active at any given time.
|
89
|
+
|
90
|
+
If you unintentionally set `isClicked: true` for multiple buttons, the component will apply a predefined internal precedence order to resolve the conflict. The button encountered first in this order will be displayed as clicked, while other buttons will sustain their default appearance. The default precedence of button actions is: "positive", "negative", "copy", "share", "listen", followed by any other custom actions (in object key order).
|
91
|
+
|
92
|
+
Once the component has rendered, user interactions will take precedence over the initial `isClicked` prop. Clicking a button will activate it and deactivate any other active button. The `isDisabled` prop for each action button specifies if a button is interactive or not.
|
93
|
+
|
94
|
+
```js file="./MessageWithClickedResponseActions.tsx"
|
95
|
+
|
96
|
+
```
|
97
|
+
|
82
98
|
### Custom message actions
|
83
99
|
|
84
100
|
Beyond the standard message actions (good response, bad response, copy, share, or listen), you can add custom actions to a bot message by passing an `actions` object to the `<Message>` component. This object can contain the following customizations:
|
@@ -86,6 +102,7 @@ Beyond the standard message actions (good response, bad response, copy, share, o
|
|
86
102
|
- `ariaLabel`
|
87
103
|
- `onClick`
|
88
104
|
- `className`
|
105
|
+
- `isClicked`
|
89
106
|
- `isDisabled`
|
90
107
|
- `tooltipContent`
|
91
108
|
- `tooltipContent`
|
@@ -3,6 +3,8 @@
|
|
3
3
|
// ============================================================================
|
4
4
|
|
5
5
|
.pf-chatbot__message-and-actions {
|
6
|
+
width: 100%;
|
7
|
+
|
6
8
|
blockquote {
|
7
9
|
.pf-chatbot__message-text {
|
8
10
|
display: inline-block;
|
@@ -10,11 +12,6 @@
|
|
10
12
|
}
|
11
13
|
}
|
12
14
|
|
13
|
-
// make it full width when there's a table, so the table can grow as needed
|
14
|
-
.pf-chatbot__message-and-actions:has(.pf-chatbot__message-table) {
|
15
|
-
width: 100%;
|
16
|
-
}
|
17
|
-
|
18
15
|
// Need to inline shorter text
|
19
16
|
.pf-chatbot__message-text {
|
20
17
|
width: fit-content;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { render, screen } from '@testing-library/react';
|
2
2
|
import '@testing-library/jest-dom';
|
3
|
-
import ResponseActions from './ResponseActions';
|
3
|
+
import ResponseActions, { ActionProps } from './ResponseActions';
|
4
4
|
import userEvent from '@testing-library/user-event';
|
5
5
|
import { DownloadIcon, InfoCircleIcon, RedoIcon } from '@patternfly/react-icons';
|
6
6
|
import Message from '../Message';
|
@@ -129,6 +129,103 @@ describe('ResponseActions', () => {
|
|
129
129
|
expect(goodBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
130
130
|
expect(badBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
131
131
|
});
|
132
|
+
|
133
|
+
it('should handle isClicked prop within group of buttons correctly', async () => {
|
134
|
+
render(
|
135
|
+
<ResponseActions
|
136
|
+
actions={
|
137
|
+
{
|
138
|
+
positive: { 'data-testid': 'positive-btn', onClick: jest.fn(), isClicked: true },
|
139
|
+
negative: { 'data-testid': 'negative-btn', onClick: jest.fn() }
|
140
|
+
} as Record<string, ActionProps>
|
141
|
+
}
|
142
|
+
/>
|
143
|
+
);
|
144
|
+
|
145
|
+
expect(screen.getByTestId('positive-btn')).toHaveClass('pf-chatbot__button--response-action-clicked');
|
146
|
+
expect(screen.getByTestId('negative-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
147
|
+
});
|
148
|
+
|
149
|
+
it('should set "listen" button as active if its `isClicked` is true', async () => {
|
150
|
+
render(
|
151
|
+
<ResponseActions
|
152
|
+
actions={
|
153
|
+
{
|
154
|
+
positive: { 'data-testid': 'positive-btn', onClick: jest.fn(), isClicked: false },
|
155
|
+
negative: { 'data-testid': 'negative-btn', onClick: jest.fn(), isClicked: false },
|
156
|
+
listen: { 'data-testid': 'listen-btn', onClick: jest.fn(), isClicked: true }
|
157
|
+
} as Record<string, ActionProps>
|
158
|
+
}
|
159
|
+
/>
|
160
|
+
);
|
161
|
+
expect(screen.getByTestId('listen-btn')).toHaveClass('pf-chatbot__button--response-action-clicked');
|
162
|
+
|
163
|
+
expect(screen.getByTestId('positive-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
164
|
+
expect(screen.getByTestId('negative-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
165
|
+
});
|
166
|
+
|
167
|
+
it('should prioritize "positive" when both "positive" and "negative" are set to clicked', async () => {
|
168
|
+
render(
|
169
|
+
<ResponseActions
|
170
|
+
actions={
|
171
|
+
{
|
172
|
+
positive: { 'data-testid': 'positive-btn', onClick: jest.fn(), isClicked: true },
|
173
|
+
negative: { 'data-testid': 'negative-btn', onClick: jest.fn(), isClicked: true }
|
174
|
+
} as Record<string, ActionProps>
|
175
|
+
}
|
176
|
+
/>
|
177
|
+
);
|
178
|
+
// Positive button should take precendence
|
179
|
+
expect(screen.getByTestId('positive-btn')).toHaveClass('pf-chatbot__button--response-action-clicked');
|
180
|
+
expect(screen.getByTestId('negative-btn')).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
181
|
+
});
|
182
|
+
|
183
|
+
it('should set an additional action button as active if it is initially clicked and no predefined are clicked', async () => {
|
184
|
+
const [additionalActions] = CUSTOM_ACTIONS;
|
185
|
+
const customActions = {
|
186
|
+
positive: { 'data-testid': 'positive', onClick: jest.fn(), isClicked: false },
|
187
|
+
negative: { 'data-testid': 'negative', onClick: jest.fn(), isClicked: false },
|
188
|
+
...Object.keys(additionalActions).reduce((acc, actionKey) => {
|
189
|
+
acc[actionKey] = {
|
190
|
+
...additionalActions[actionKey],
|
191
|
+
'data-testid': actionKey,
|
192
|
+
isClicked: actionKey === 'regenerate'
|
193
|
+
};
|
194
|
+
return acc;
|
195
|
+
}, {})
|
196
|
+
};
|
197
|
+
render(<ResponseActions actions={customActions} />);
|
198
|
+
|
199
|
+
Object.keys(customActions).forEach((actionKey) => {
|
200
|
+
if (actionKey === 'regenerate') {
|
201
|
+
expect(screen.getByTestId(actionKey)).toHaveClass('pf-chatbot__button--response-action-clicked');
|
202
|
+
} else {
|
203
|
+
// Other actions should not have clicked class
|
204
|
+
expect(screen.getByTestId(actionKey)).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
205
|
+
}
|
206
|
+
});
|
207
|
+
});
|
208
|
+
|
209
|
+
it('should activate the clicked button and deactivate any previously active button', async () => {
|
210
|
+
const actions = {
|
211
|
+
positive: { 'data-testid': 'positive', onClick: jest.fn(), isClicked: false },
|
212
|
+
negative: { 'data-testid': 'negative', onClick: jest.fn(), isClicked: true }
|
213
|
+
};
|
214
|
+
render(<ResponseActions actions={actions} />);
|
215
|
+
|
216
|
+
const negativeBtn = screen.getByTestId('negative');
|
217
|
+
const positiveBtn = screen.getByTestId('positive');
|
218
|
+
// negative button is initially clicked
|
219
|
+
expect(negativeBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
|
220
|
+
expect(positiveBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
221
|
+
|
222
|
+
await userEvent.click(positiveBtn);
|
223
|
+
|
224
|
+
// positive button should now have the clicked class
|
225
|
+
expect(positiveBtn).toHaveClass('pf-chatbot__button--response-action-clicked');
|
226
|
+
expect(negativeBtn).not.toHaveClass('pf-chatbot__button--response-action-clicked');
|
227
|
+
});
|
228
|
+
|
132
229
|
it('should render buttons correctly', () => {
|
133
230
|
ALL_ACTIONS.forEach(({ type, label }) => {
|
134
231
|
render(<ResponseActions actions={{ [type]: { onClick: jest.fn() } }} />);
|
@@ -55,12 +55,40 @@ export interface ResponseActionProps {
|
|
55
55
|
|
56
56
|
export const ResponseActions: FunctionComponent<ResponseActionProps> = ({ actions }) => {
|
57
57
|
const [activeButton, setActiveButton] = useState<string>();
|
58
|
+
const [clickStatePersisted, setClickStatePersisted] = useState<boolean>(false);
|
59
|
+
useEffect(() => {
|
60
|
+
// Define the order of precedence for checking initial `isClicked`
|
61
|
+
const actionPrecedence = ['positive', 'negative', 'copy', 'share', 'download', 'listen'];
|
62
|
+
let initialActive: string | undefined;
|
63
|
+
|
64
|
+
// Check predefined actions first based on precedence
|
65
|
+
for (const actionName of actionPrecedence) {
|
66
|
+
const actionProp = actions[actionName as keyof typeof actions];
|
67
|
+
if (actionProp?.isClicked) {
|
68
|
+
initialActive = actionName;
|
69
|
+
break;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
// If no predefined action was initially clicked, check additionalActions
|
73
|
+
if (!initialActive) {
|
74
|
+
const clickedActionName = Object.keys(additionalActions).find(
|
75
|
+
(actionName) => !actionPrecedence.includes(actionName) && additionalActions[actionName]?.isClicked
|
76
|
+
);
|
77
|
+
initialActive = clickedActionName;
|
78
|
+
}
|
79
|
+
if (initialActive) {
|
80
|
+
// Click state is explicitly controlled by consumer.
|
81
|
+
setClickStatePersisted(true);
|
82
|
+
}
|
83
|
+
setActiveButton(initialActive);
|
84
|
+
}, [actions]);
|
85
|
+
|
58
86
|
const { positive, negative, copy, share, download, listen, ...additionalActions } = actions;
|
59
87
|
const responseActions = useRef<HTMLDivElement>(null);
|
60
88
|
|
61
89
|
useEffect(() => {
|
62
90
|
const handleClickOutside = (e) => {
|
63
|
-
if (responseActions.current && !responseActions.current.contains(e.target)) {
|
91
|
+
if (responseActions.current && !responseActions.current.contains(e.target) && !clickStatePersisted) {
|
64
92
|
setActiveButton(undefined);
|
65
93
|
}
|
66
94
|
};
|
@@ -69,13 +97,14 @@ export const ResponseActions: FunctionComponent<ResponseActionProps> = ({ action
|
|
69
97
|
return () => {
|
70
98
|
window.removeEventListener('click', handleClickOutside);
|
71
99
|
};
|
72
|
-
}, []);
|
100
|
+
}, [clickStatePersisted]);
|
73
101
|
|
74
102
|
const handleClick = (
|
75
103
|
e: MouseEvent | MouseEvent<Element, MouseEvent> | KeyboardEvent,
|
76
104
|
id: string,
|
77
105
|
onClick?: (event: MouseEvent | MouseEvent<Element, MouseEvent> | KeyboardEvent) => void
|
78
106
|
) => {
|
107
|
+
setClickStatePersisted(false);
|
79
108
|
setActiveButton(id);
|
80
109
|
onClick && onClick(e);
|
81
110
|
};
|