@constructor-io/constructorio-ui-asa 1.0.0
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/LICENSE +21 -0
- package/README.md +253 -0
- package/dist/constructorio-ui-asa-bundled.js +33 -0
- package/lib/cjs/components/Button/Button.css +61 -0
- package/lib/cjs/components/Button/Button.js +12 -0
- package/lib/cjs/components/Chat/AiMessage.css +35 -0
- package/lib/cjs/components/Chat/AiMessage.js +34 -0
- package/lib/cjs/components/Chat/Chat.css +103 -0
- package/lib/cjs/components/Chat/Chat.js +34 -0
- package/lib/cjs/components/Chat/ChatHeader.css +41 -0
- package/lib/cjs/components/Chat/ChatHeader.js +18 -0
- package/lib/cjs/components/Chat/ChatInput.css +83 -0
- package/lib/cjs/components/Chat/ChatInput.js +30 -0
- package/lib/cjs/components/Chat/ChatMessageList.css +23 -0
- package/lib/cjs/components/Chat/ChatMessageList.js +46 -0
- package/lib/cjs/components/Chat/TypingIndicator.css +51 -0
- package/lib/cjs/components/Chat/TypingIndicator.js +14 -0
- package/lib/cjs/components/Chat/UserMessage.css +25 -0
- package/lib/cjs/components/Chat/UserMessage.js +14 -0
- package/lib/cjs/components/Chat/WelcomeScreen.css +205 -0
- package/lib/cjs/components/Chat/WelcomeScreen.js +43 -0
- package/lib/cjs/components/CioAsaProvider/CioAsaProvider.js +23 -0
- package/lib/cjs/components/ResultsBlock/ResultsBlock.css +217 -0
- package/lib/cjs/components/ResultsBlock/ResultsBlock.js +73 -0
- package/lib/cjs/components/ResultsBlock/constants.js +11 -0
- package/lib/cjs/components/ResultsBlock/renderProductCard.js +21 -0
- package/lib/cjs/components/icons/ArrowRightIcon.js +9 -0
- package/lib/cjs/components/icons/ChatBubbleDarkIcon.js +9 -0
- package/lib/cjs/components/icons/ChatBubbleLightIcon.js +9 -0
- package/lib/cjs/components/icons/SendArrowIcon.js +9 -0
- package/lib/cjs/components/icons/SendPlaneIcon.js +9 -0
- package/lib/cjs/components/icons/index.js +16 -0
- package/lib/cjs/constants.js +6 -0
- package/lib/cjs/hooks/asaStreamHandlers.js +34 -0
- package/lib/cjs/hooks/useAsaResults.js +120 -0
- package/lib/cjs/hooks/useCioAsaContext.js +15 -0
- package/lib/cjs/hooks/useCioClient.js +21 -0
- package/lib/cjs/hooks/useFocusTrap.js +38 -0
- package/lib/cjs/hooks/useMessageInput.js +22 -0
- package/lib/cjs/hooks/useRequestConfigs.js +27 -0
- package/lib/cjs/index.js +24 -0
- package/lib/cjs/styles.css +34 -0
- package/lib/cjs/types.js +6 -0
- package/lib/cjs/utils/formatters.js +11 -0
- package/lib/cjs/utils/productNormalizer.js +20 -0
- package/lib/cjs/utils/translate.js +30 -0
- package/lib/cjs/utils/typeHelpers.js +2 -0
- package/lib/cjs/utils/urlHelpers.js +102 -0
- package/lib/cjs/version.js +3 -0
- package/lib/mjs/components/Button/Button.css +61 -0
- package/lib/mjs/components/Button/Button.js +8 -0
- package/lib/mjs/components/Chat/AiMessage.css +35 -0
- package/lib/mjs/components/Chat/AiMessage.js +29 -0
- package/lib/mjs/components/Chat/Chat.css +103 -0
- package/lib/mjs/components/Chat/Chat.js +31 -0
- package/lib/mjs/components/Chat/ChatHeader.css +41 -0
- package/lib/mjs/components/Chat/ChatHeader.js +14 -0
- package/lib/mjs/components/Chat/ChatInput.css +83 -0
- package/lib/mjs/components/Chat/ChatInput.js +26 -0
- package/lib/mjs/components/Chat/ChatMessageList.css +23 -0
- package/lib/mjs/components/Chat/ChatMessageList.js +41 -0
- package/lib/mjs/components/Chat/TypingIndicator.css +51 -0
- package/lib/mjs/components/Chat/TypingIndicator.js +10 -0
- package/lib/mjs/components/Chat/UserMessage.css +25 -0
- package/lib/mjs/components/Chat/UserMessage.js +10 -0
- package/lib/mjs/components/Chat/WelcomeScreen.css +205 -0
- package/lib/mjs/components/Chat/WelcomeScreen.js +38 -0
- package/lib/mjs/components/CioAsaProvider/CioAsaProvider.js +19 -0
- package/lib/mjs/components/ResultsBlock/ResultsBlock.css +217 -0
- package/lib/mjs/components/ResultsBlock/ResultsBlock.js +76 -0
- package/lib/mjs/components/ResultsBlock/constants.js +8 -0
- package/lib/mjs/components/ResultsBlock/renderProductCard.js +17 -0
- package/lib/mjs/components/icons/ArrowRightIcon.js +5 -0
- package/lib/mjs/components/icons/ChatBubbleDarkIcon.js +5 -0
- package/lib/mjs/components/icons/ChatBubbleLightIcon.js +5 -0
- package/lib/mjs/components/icons/SendArrowIcon.js +5 -0
- package/lib/mjs/components/icons/SendPlaneIcon.js +5 -0
- package/lib/mjs/components/icons/index.js +5 -0
- package/lib/mjs/constants.js +3 -0
- package/lib/mjs/hooks/asaStreamHandlers.js +39 -0
- package/lib/mjs/hooks/useAsaResults.js +118 -0
- package/lib/mjs/hooks/useCioAsaContext.js +11 -0
- package/lib/mjs/hooks/useCioClient.js +23 -0
- package/lib/mjs/hooks/useFocusTrap.js +35 -0
- package/lib/mjs/hooks/useMessageInput.js +19 -0
- package/lib/mjs/hooks/useRequestConfigs.js +24 -0
- package/lib/mjs/index.js +11 -0
- package/lib/mjs/styles.css +34 -0
- package/lib/mjs/types.js +2 -0
- package/lib/mjs/utils/formatters.js +7 -0
- package/lib/mjs/utils/productNormalizer.js +15 -0
- package/lib/mjs/utils/translate.js +26 -0
- package/lib/mjs/utils/typeHelpers.js +1 -0
- package/lib/mjs/utils/urlHelpers.js +90 -0
- package/lib/mjs/version.js +1 -0
- package/lib/types/components/Button/Button.d.ts +12 -0
- package/lib/types/components/Chat/AiMessage.d.ts +12 -0
- package/lib/types/components/Chat/Chat.d.ts +38 -0
- package/lib/types/components/Chat/ChatHeader.d.ts +12 -0
- package/lib/types/components/Chat/ChatInput.d.ts +13 -0
- package/lib/types/components/Chat/ChatMessageList.d.ts +24 -0
- package/lib/types/components/Chat/TypingIndicator.d.ts +10 -0
- package/lib/types/components/Chat/UserMessage.d.ts +12 -0
- package/lib/types/components/Chat/WelcomeScreen.d.ts +16 -0
- package/lib/types/components/CioAsaProvider/CioAsaProvider.d.ts +3 -0
- package/lib/types/components/ResultsBlock/ResultsBlock.d.ts +32 -0
- package/lib/types/components/ResultsBlock/constants.d.ts +3 -0
- package/lib/types/components/ResultsBlock/renderProductCard.d.ts +12 -0
- package/lib/types/components/icons/ArrowRightIcon.d.ts +2 -0
- package/lib/types/components/icons/ChatBubbleDarkIcon.d.ts +2 -0
- package/lib/types/components/icons/ChatBubbleLightIcon.d.ts +2 -0
- package/lib/types/components/icons/SendArrowIcon.d.ts +2 -0
- package/lib/types/components/icons/SendPlaneIcon.d.ts +2 -0
- package/lib/types/components/icons/index.d.ts +5 -0
- package/lib/types/constants.d.ts +2 -0
- package/lib/types/hooks/asaStreamHandlers.d.ts +8 -0
- package/lib/types/hooks/useAsaResults.d.ts +2 -0
- package/lib/types/hooks/useCioAsaContext.d.ts +9 -0
- package/lib/types/hooks/useCioClient.d.ts +6 -0
- package/lib/types/hooks/useFocusTrap.d.ts +11 -0
- package/lib/types/hooks/useMessageInput.d.ts +15 -0
- package/lib/types/hooks/useRequestConfigs.d.ts +7 -0
- package/lib/types/index.d.ts +12 -0
- package/lib/types/types.d.ts +178 -0
- package/lib/types/utils/formatters.d.ts +1 -0
- package/lib/types/utils/productNormalizer.d.ts +14 -0
- package/lib/types/utils/translate.d.ts +2 -0
- package/lib/types/utils/typeHelpers.d.ts +4 -0
- package/lib/types/utils/urlHelpers.d.ts +8 -0
- package/lib/types/version.d.ts +2 -0
- package/package.json +150 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.cio-asa-ai-message {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: flex-start;
|
|
5
|
+
gap: 12px;
|
|
6
|
+
padding-right: 12px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.cio-asa-ai-message__bubble {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
align-items: flex-start;
|
|
13
|
+
padding: 12px;
|
|
14
|
+
gap: 8px;
|
|
15
|
+
background: #ECEEF3;
|
|
16
|
+
border-radius: 6px;
|
|
17
|
+
width: 100%;
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.cio-asa-ai-message__bubble--error {
|
|
22
|
+
background: #FDECEC;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.cio-asa-ai-message__text {
|
|
26
|
+
font-weight: 400;
|
|
27
|
+
font-size: 14px;
|
|
28
|
+
line-height: 20px;
|
|
29
|
+
letter-spacing: -0.005em;
|
|
30
|
+
color: #0F1324;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.cio-asa-ai-message__bubble--error .cio-asa-ai-message__text {
|
|
34
|
+
color: #B42318;
|
|
35
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
5
|
+
const constructorio_ui_components_1 = require("@constructor-io/constructorio-ui-components");
|
|
6
|
+
const translate_1 = tslib_1.__importDefault(require("../../utils/translate"));
|
|
7
|
+
const TypingIndicator_1 = tslib_1.__importDefault(require("./TypingIndicator"));
|
|
8
|
+
function AiMessage({ message, componentOverrides, translations }) {
|
|
9
|
+
var _a, _b, _c;
|
|
10
|
+
const isLoading = message.status === 'loading';
|
|
11
|
+
const isError = message.status === 'error';
|
|
12
|
+
const hasGroups = !!((_a = message.groups) === null || _a === void 0 ? void 0 : _a.length);
|
|
13
|
+
// On error, fall back to the (translatable) error message when the agent
|
|
14
|
+
// returned no partial text of its own.
|
|
15
|
+
const text = isError
|
|
16
|
+
? message.text || (0, translate_1.default)('CioAsa.error.message', translations)
|
|
17
|
+
: message.text || '';
|
|
18
|
+
const hasText = text.length > 0;
|
|
19
|
+
const loaderRenderProps = { translations };
|
|
20
|
+
const textRenderProps = { text };
|
|
21
|
+
return (react_1.default.createElement("div", { className: 'cio-asa-ai-message' },
|
|
22
|
+
isLoading && !hasText && !hasGroups && (react_1.default.createElement(constructorio_ui_components_1.RenderPropsWrapper, { override: (_b = componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.loader) === null || _b === void 0 ? void 0 : _b.reactNode, props: loaderRenderProps },
|
|
23
|
+
react_1.default.createElement(TypingIndicator_1.default, { translations: translations }))),
|
|
24
|
+
hasText && (react_1.default.createElement(constructorio_ui_components_1.RenderPropsWrapper, { override: (_c = componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.text) === null || _c === void 0 ? void 0 : _c.reactNode, props: textRenderProps },
|
|
25
|
+
react_1.default.createElement("div", { className: [
|
|
26
|
+
'cio-asa-ai-message__bubble',
|
|
27
|
+
isError && 'cio-asa-ai-message__bubble--error',
|
|
28
|
+
]
|
|
29
|
+
.filter(Boolean)
|
|
30
|
+
.join(' ') },
|
|
31
|
+
react_1.default.createElement("div", { className: 'cio-asa-ai-message__text' }, text))))));
|
|
32
|
+
}
|
|
33
|
+
exports.default = AiMessage;
|
|
34
|
+
AiMessage.displayName = 'AiMessage';
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
.cio-asa-chat {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 100%;
|
|
6
|
+
background: rgba(248, 249, 252, 1);
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
position: relative;
|
|
9
|
+
animation: cio-asa-fade-in 0.4s ease;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.cio-asa-chat-body {
|
|
13
|
+
flex: 1;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
position: relative;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.cio-asa-chat-view {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
flex: 1;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.cio-asa-chat-view--welcome {
|
|
28
|
+
animation: cio-asa-fade-in 0.3s ease;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.cio-asa-chat-view--chat {
|
|
32
|
+
animation: cio-asa-fade-in 0.3s ease;
|
|
33
|
+
position: relative;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Overlay backdrop */
|
|
37
|
+
.cio-asa-chat-overlay {
|
|
38
|
+
position: fixed;
|
|
39
|
+
inset: 0;
|
|
40
|
+
border: none;
|
|
41
|
+
padding: 0;
|
|
42
|
+
margin: 0;
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
background: rgba(0, 0, 0, 0.4);
|
|
45
|
+
z-index: 999;
|
|
46
|
+
animation: cio-asa-fade-in 0.2s ease;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Slide-in panel from right */
|
|
50
|
+
.cio-asa-chat-panel {
|
|
51
|
+
position: fixed;
|
|
52
|
+
top: 0;
|
|
53
|
+
right: 0;
|
|
54
|
+
bottom: 0;
|
|
55
|
+
width: 420px;
|
|
56
|
+
z-index: 1000;
|
|
57
|
+
animation: cio-asa-slide-in-right 0.3s ease;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.cio-asa-chat-panel .cio-asa-chat {
|
|
61
|
+
height: 100%;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@keyframes cio-asa-fade-in {
|
|
65
|
+
from {
|
|
66
|
+
opacity: 0;
|
|
67
|
+
}
|
|
68
|
+
to {
|
|
69
|
+
opacity: 1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@keyframes cio-asa-slide-in-right {
|
|
74
|
+
from {
|
|
75
|
+
transform: translateX(100%);
|
|
76
|
+
}
|
|
77
|
+
to {
|
|
78
|
+
transform: translateX(0);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@keyframes cio-asa-slide-in-up {
|
|
83
|
+
from {
|
|
84
|
+
transform: translateY(100%);
|
|
85
|
+
}
|
|
86
|
+
to {
|
|
87
|
+
transform: translateY(0);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.cio-asa-chat-fullscreen {
|
|
92
|
+
position: absolute;
|
|
93
|
+
inset: 0;
|
|
94
|
+
z-index: 1000;
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
animation: cio-asa-fade-in 0.4s ease;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.cio-asa-chat-fullscreen--right {
|
|
100
|
+
inset: 0 0 0 auto;
|
|
101
|
+
width: 504px;
|
|
102
|
+
animation: cio-asa-slide-in-right 0.4s ease 0.2s both;
|
|
103
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const react_1 = tslib_1.__importStar(require("react"));
|
|
5
|
+
const useAsaResults_1 = tslib_1.__importDefault(require("../../hooks/useAsaResults"));
|
|
6
|
+
const useFocusTrap_1 = tslib_1.__importDefault(require("../../hooks/useFocusTrap"));
|
|
7
|
+
const translate_1 = tslib_1.__importDefault(require("../../utils/translate"));
|
|
8
|
+
const ChatHeader_1 = tslib_1.__importDefault(require("./ChatHeader"));
|
|
9
|
+
const WelcomeScreen_1 = tslib_1.__importDefault(require("./WelcomeScreen"));
|
|
10
|
+
const ChatMessageList_1 = tslib_1.__importDefault(require("./ChatMessageList"));
|
|
11
|
+
const ChatInput_1 = tslib_1.__importDefault(require("./ChatInput"));
|
|
12
|
+
const Chat = (0, react_1.forwardRef)(({ onClose, className, initialSuggestions, termsText, onProductClick, onViewMore, onAddToCart, aspectRatio, currency, normalizeItem, componentOverrides, translations, }, ref) => {
|
|
13
|
+
const { messages, sendMessage, isStreaming, clearHistory } = (0, useAsaResults_1.default)();
|
|
14
|
+
const chatViewRef = (0, react_1.useRef)(null);
|
|
15
|
+
const containerRef = (0, react_1.useRef)(null);
|
|
16
|
+
const isWelcome = messages.length === 0;
|
|
17
|
+
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
18
|
+
clearHistory,
|
|
19
|
+
}));
|
|
20
|
+
(0, react_1.useEffect)(() => {
|
|
21
|
+
const root = isWelcome ? containerRef.current : chatViewRef.current;
|
|
22
|
+
const input = root === null || root === void 0 ? void 0 : root.querySelector('input');
|
|
23
|
+
input === null || input === void 0 ? void 0 : input.focus();
|
|
24
|
+
}, [isWelcome]);
|
|
25
|
+
(0, useFocusTrap_1.default)(containerRef, { onEscape: onClose });
|
|
26
|
+
return (react_1.default.createElement("div", { className: ['cio-asa', 'cio-asa-chat', className].filter(Boolean).join(' '), ref: containerRef, role: 'dialog', "aria-labelledby": 'cio-asa-chat-title' },
|
|
27
|
+
react_1.default.createElement("div", { className: 'cio-asa-chat-body' }, isWelcome ? (react_1.default.createElement("div", { className: 'cio-asa-chat-view cio-asa-chat-view--welcome' },
|
|
28
|
+
react_1.default.createElement(WelcomeScreen_1.default, { suggestions: initialSuggestions, onSend: sendMessage, onClose: onClose, termsText: termsText, translations: translations, componentOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.welcomeScreen }))) : (react_1.default.createElement("div", { className: 'cio-asa-chat-view cio-asa-chat-view--chat', ref: chatViewRef },
|
|
29
|
+
react_1.default.createElement(ChatHeader_1.default, { onClose: onClose, translations: translations, componentOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.header }),
|
|
30
|
+
react_1.default.createElement(ChatMessageList_1.default, { messages: messages, onProductClick: onProductClick, onViewMore: onViewMore, onAddToCart: onAddToCart, aspectRatio: aspectRatio, currency: currency, normalizeItem: normalizeItem, addToCartText: (0, translate_1.default)('CioAsa.results.addToCart', translations), viewMoreText: (0, translate_1.default)('CioAsa.results.viewMore', translations), aiMessageOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.aiMessage, userMessageOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.userMessage, resultsBlockOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.resultsBlock, translations: translations }),
|
|
31
|
+
react_1.default.createElement(ChatInput_1.default, { onSubmit: sendMessage, isDisabled: isStreaming, translations: translations, componentOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.input }))))));
|
|
32
|
+
});
|
|
33
|
+
Chat.displayName = 'Chat';
|
|
34
|
+
exports.default = Chat;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
.cio-asa-chat-header {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: flex-end;
|
|
5
|
+
padding: 16px 20px;
|
|
6
|
+
position: relative;
|
|
7
|
+
flex-shrink: 0;
|
|
8
|
+
border-bottom: 1px solid rgba(222, 224, 227, 1);
|
|
9
|
+
background: #FFFFFF;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.cio-asa-chat-header__title {
|
|
13
|
+
position: absolute;
|
|
14
|
+
left: 50%;
|
|
15
|
+
transform: translateX(-50%);
|
|
16
|
+
font-weight: 600;
|
|
17
|
+
font-size: 16px;
|
|
18
|
+
line-height: 1;
|
|
19
|
+
color: #0F1324;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.cio-asa-chat-header__close {
|
|
23
|
+
background: none;
|
|
24
|
+
border: none;
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
padding: 4px;
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
color: #1a1a1a;
|
|
31
|
+
font-size: 20px;
|
|
32
|
+
line-height: 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.cio-asa-chat-header__close::before {
|
|
36
|
+
content: '\2715';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.cio-asa-chat-header__close:hover {
|
|
40
|
+
opacity: 0.7;
|
|
41
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
5
|
+
const constructorio_ui_components_1 = require("@constructor-io/constructorio-ui-components");
|
|
6
|
+
const translate_1 = tslib_1.__importDefault(require("../../utils/translate"));
|
|
7
|
+
function ChatHeader({ onClose, translations, componentOverrides }) {
|
|
8
|
+
const renderProps = {
|
|
9
|
+
title: (0, translate_1.default)('CioAsa.header.title', translations),
|
|
10
|
+
onClose,
|
|
11
|
+
};
|
|
12
|
+
return (react_1.default.createElement(constructorio_ui_components_1.RenderPropsWrapper, { override: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.reactNode, props: renderProps },
|
|
13
|
+
react_1.default.createElement("div", { className: 'cio-asa-chat-header' },
|
|
14
|
+
react_1.default.createElement("span", { id: 'cio-asa-chat-title', className: 'cio-asa-chat-header__title' }, renderProps.title),
|
|
15
|
+
onClose && (react_1.default.createElement("button", { type: 'button', className: 'cio-asa-chat-header__close', onClick: onClose, "aria-label": (0, translate_1.default)('CioAsa.header.close', translations) })))));
|
|
16
|
+
}
|
|
17
|
+
exports.default = ChatHeader;
|
|
18
|
+
ChatHeader.displayName = 'ChatHeader';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
.cio-asa-chat-input-wrapper {
|
|
2
|
+
position: absolute;
|
|
3
|
+
bottom: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
right: 0;
|
|
6
|
+
display: flex;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
padding: 24px 12px 16px;
|
|
9
|
+
background: linear-gradient(to bottom, rgba(248, 249, 252, 0) 0%, rgba(248, 249, 252, 1) 40%);
|
|
10
|
+
pointer-events: none;
|
|
11
|
+
z-index: 10;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.cio-asa-chat-input {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: row;
|
|
17
|
+
justify-content: space-between;
|
|
18
|
+
align-items: center;
|
|
19
|
+
padding: 4px 12px;
|
|
20
|
+
gap: 12px;
|
|
21
|
+
height: 40px;
|
|
22
|
+
max-width: 508px;
|
|
23
|
+
width: 100%;
|
|
24
|
+
background: #FFFFFF;
|
|
25
|
+
border: 1px solid #DEE0E3;
|
|
26
|
+
box-shadow: 0px 6px 14px rgba(18, 18, 105, 0.11), 0px 2px 4px rgba(18, 18, 105, 0.0716748), 0px 1px 2px rgba(18, 18, 105, 0.055);
|
|
27
|
+
border-radius: 4px;
|
|
28
|
+
box-sizing: border-box;
|
|
29
|
+
pointer-events: all;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.cio-asa-chat-input:hover {
|
|
33
|
+
border-color: #C8CAD0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.cio-asa-chat-input:focus-within {
|
|
37
|
+
border-color: #000000;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.cio-asa-chat-input__field {
|
|
41
|
+
flex: 1;
|
|
42
|
+
padding: 0;
|
|
43
|
+
border: none;
|
|
44
|
+
font-weight: 400;
|
|
45
|
+
font-size: 14px;
|
|
46
|
+
line-height: 16px;
|
|
47
|
+
letter-spacing: -0.005em;
|
|
48
|
+
font-feature-settings: 'tnum' on, 'lnum' on;
|
|
49
|
+
color: #0F1324;
|
|
50
|
+
outline: none;
|
|
51
|
+
background: transparent;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.cio-asa-chat-input__field::placeholder {
|
|
55
|
+
color: rgba(15, 19, 36, 0.7);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.cio-asa-chat-input__field:disabled {
|
|
59
|
+
cursor: not-allowed;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.cio-asa-chat-input__send {
|
|
63
|
+
display: flex;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
align-items: center;
|
|
66
|
+
width: 16px;
|
|
67
|
+
height: 16px;
|
|
68
|
+
background: none;
|
|
69
|
+
border: none;
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
flex-shrink: 0;
|
|
72
|
+
padding: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.cio-asa-chat-input__send:hover:not(:disabled) svg path {
|
|
76
|
+
stroke: #0F1324;
|
|
77
|
+
stroke-opacity: 1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.cio-asa-chat-input__send:disabled {
|
|
81
|
+
cursor: default;
|
|
82
|
+
opacity: 0.3;
|
|
83
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
5
|
+
const constructorio_ui_components_1 = require("@constructor-io/constructorio-ui-components");
|
|
6
|
+
const icons_1 = require("../icons");
|
|
7
|
+
const translate_1 = tslib_1.__importDefault(require("../../utils/translate"));
|
|
8
|
+
const useMessageInput_1 = tslib_1.__importDefault(require("../../hooks/useMessageInput"));
|
|
9
|
+
function ChatInput({ onSubmit, isDisabled = false, translations, componentOverrides, }) {
|
|
10
|
+
const { value, setValue, handleSubmit, handleKeyDown } = (0, useMessageInput_1.default)({
|
|
11
|
+
onSend: onSubmit,
|
|
12
|
+
isDisabled,
|
|
13
|
+
submitOnEnterOnly: true,
|
|
14
|
+
});
|
|
15
|
+
const renderProps = {
|
|
16
|
+
value,
|
|
17
|
+
onChange: setValue,
|
|
18
|
+
onSubmit: handleSubmit,
|
|
19
|
+
placeholder: (0, translate_1.default)('CioAsa.input.placeholder', translations),
|
|
20
|
+
isDisabled,
|
|
21
|
+
};
|
|
22
|
+
return (react_1.default.createElement(constructorio_ui_components_1.RenderPropsWrapper, { override: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.reactNode, props: renderProps },
|
|
23
|
+
react_1.default.createElement("div", { className: 'cio-asa-chat-input-wrapper' },
|
|
24
|
+
react_1.default.createElement("div", { className: 'cio-asa-chat-input' },
|
|
25
|
+
react_1.default.createElement("input", { type: 'text', className: 'cio-asa-chat-input__field', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, placeholder: renderProps.placeholder, disabled: isDisabled, "aria-label": (0, translate_1.default)('CioAsa.input.ariaLabel', translations) }),
|
|
26
|
+
react_1.default.createElement("button", { type: 'button', className: 'cio-asa-chat-input__send', onClick: handleSubmit, disabled: isDisabled || !value.trim(), "aria-label": (0, translate_1.default)('CioAsa.input.sendAriaLabel', translations) },
|
|
27
|
+
react_1.default.createElement(icons_1.SendArrowIcon, null))))));
|
|
28
|
+
}
|
|
29
|
+
exports.default = ChatInput;
|
|
30
|
+
ChatInput.displayName = 'ChatInput';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.cio-asa-chat-message-list {
|
|
2
|
+
flex: 1;
|
|
3
|
+
overflow-y: auto;
|
|
4
|
+
padding: 32px 12px 80px;
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
gap: 16px;
|
|
8
|
+
max-width: 508px;
|
|
9
|
+
width: 100%;
|
|
10
|
+
margin: 0 auto;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
scrollbar-width: none;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.cio-asa-chat-message-list::-webkit-scrollbar {
|
|
16
|
+
display: none;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.cio-asa-ai-message-group {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
gap: 12px;
|
|
23
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const react_1 = tslib_1.__importStar(require("react"));
|
|
5
|
+
const translate_1 = tslib_1.__importDefault(require("../../utils/translate"));
|
|
6
|
+
const ResultsBlock_1 = tslib_1.__importDefault(require("../ResultsBlock/ResultsBlock"));
|
|
7
|
+
const UserMessage_1 = tslib_1.__importDefault(require("./UserMessage"));
|
|
8
|
+
const AiMessage_1 = tslib_1.__importDefault(require("./AiMessage"));
|
|
9
|
+
function ChatMessageList({ messages, onProductClick, onViewMore, onAddToCart, aspectRatio, currency, normalizeItem, addToCartText, viewMoreText, aiMessageOverrides, userMessageOverrides, resultsBlockOverrides, translations, }) {
|
|
10
|
+
const listRef = (0, react_1.useRef)(null);
|
|
11
|
+
const isNearBottomRef = (0, react_1.useRef)(true);
|
|
12
|
+
const prevMessageCountRef = (0, react_1.useRef)(messages.length);
|
|
13
|
+
const handleScroll = (0, react_1.useCallback)(() => {
|
|
14
|
+
const el = listRef.current;
|
|
15
|
+
if (!el)
|
|
16
|
+
return;
|
|
17
|
+
const threshold = 100;
|
|
18
|
+
isNearBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < threshold;
|
|
19
|
+
}, []);
|
|
20
|
+
(0, react_1.useEffect)(() => {
|
|
21
|
+
const isNewMessage = messages.length > prevMessageCountRef.current;
|
|
22
|
+
prevMessageCountRef.current = messages.length;
|
|
23
|
+
if (!isNearBottomRef.current)
|
|
24
|
+
return;
|
|
25
|
+
const el = listRef.current;
|
|
26
|
+
if (!el)
|
|
27
|
+
return;
|
|
28
|
+
// Smooth-scroll only when a new message is added; use 'auto' for the frequent
|
|
29
|
+
// updates during SSE streaming to avoid restarting the animation on every chunk.
|
|
30
|
+
requestAnimationFrame(() => {
|
|
31
|
+
el.scrollTo({ top: el.scrollHeight, behavior: isNewMessage ? 'smooth' : 'auto' });
|
|
32
|
+
});
|
|
33
|
+
}, [messages]);
|
|
34
|
+
return (react_1.default.createElement("div", { className: 'cio-asa-chat-message-list', ref: listRef, onScroll: handleScroll, role: 'log', "aria-live": 'polite', "aria-label": (0, translate_1.default)('CioAsa.messageList.ariaLabel', translations) }, messages.map((message) => {
|
|
35
|
+
var _a;
|
|
36
|
+
if (message.role === 'user') {
|
|
37
|
+
return (react_1.default.createElement(UserMessage_1.default, { key: message.id, text: message.text, translations: translations, componentOverrides: userMessageOverrides }));
|
|
38
|
+
}
|
|
39
|
+
const hasGroups = !!((_a = message.groups) === null || _a === void 0 ? void 0 : _a.length);
|
|
40
|
+
return (react_1.default.createElement("div", { key: message.id, className: 'cio-asa-ai-message-group' },
|
|
41
|
+
react_1.default.createElement(AiMessage_1.default, { message: message, componentOverrides: aiMessageOverrides, translations: translations }),
|
|
42
|
+
hasGroups && (react_1.default.createElement(ResultsBlock_1.default, { groups: message.groups, onProductClick: onProductClick, onViewMore: onViewMore, onAddToCart: onAddToCart, aspectRatio: aspectRatio, currency: currency, normalizeItem: normalizeItem, addToCartText: addToCartText, viewMoreText: viewMoreText, saleBadgeText: (0, translate_1.default)('CioAsa.results.saleBadge', translations), componentOverrides: resultsBlockOverrides }))));
|
|
43
|
+
})));
|
|
44
|
+
}
|
|
45
|
+
exports.default = ChatMessageList;
|
|
46
|
+
ChatMessageList.displayName = 'ChatMessageList';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.cio-asa-typing-indicator {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: flex-start;
|
|
5
|
+
padding: 12px;
|
|
6
|
+
gap: 8px;
|
|
7
|
+
background: #ECEEF3;
|
|
8
|
+
border-radius: 6px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.cio-asa-typing-indicator__dots {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: row;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
align-items: center;
|
|
16
|
+
gap: 6px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.cio-asa-typing-indicator__dot {
|
|
20
|
+
width: 8px;
|
|
21
|
+
height: 8px;
|
|
22
|
+
background: #C8CAD0;
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
animation: cio-asa-typing-bounce 1.4s infinite ease-in-out both;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.cio-asa-typing-indicator__dot:nth-child(1) {
|
|
28
|
+
background: rgba(15, 19, 36, 0.6);
|
|
29
|
+
animation-delay: -0.32s;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.cio-asa-typing-indicator__dot:nth-child(2) {
|
|
33
|
+
animation-delay: -0.16s;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.cio-asa-typing-indicator__dot:nth-child(3) {
|
|
37
|
+
animation-delay: 0s;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@keyframes cio-asa-typing-bounce {
|
|
41
|
+
0%,
|
|
42
|
+
80%,
|
|
43
|
+
100% {
|
|
44
|
+
transform: scale(0.8);
|
|
45
|
+
opacity: 0.5;
|
|
46
|
+
}
|
|
47
|
+
40% {
|
|
48
|
+
transform: scale(1);
|
|
49
|
+
opacity: 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
5
|
+
const translate_1 = tslib_1.__importDefault(require("../../utils/translate"));
|
|
6
|
+
function TypingIndicator({ translations }) {
|
|
7
|
+
return (react_1.default.createElement("div", { className: 'cio-asa-typing-indicator', role: 'status', "aria-label": (0, translate_1.default)('CioAsa.typingIndicator.ariaLabel', translations) },
|
|
8
|
+
react_1.default.createElement("div", { className: 'cio-asa-typing-indicator__dots' },
|
|
9
|
+
react_1.default.createElement("span", { className: 'cio-asa-typing-indicator__dot' }),
|
|
10
|
+
react_1.default.createElement("span", { className: 'cio-asa-typing-indicator__dot' }),
|
|
11
|
+
react_1.default.createElement("span", { className: 'cio-asa-typing-indicator__dot' }))));
|
|
12
|
+
}
|
|
13
|
+
exports.default = TypingIndicator;
|
|
14
|
+
TypingIndicator.displayName = 'TypingIndicator';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.cio-asa-user-message {
|
|
2
|
+
display: flex;
|
|
3
|
+
justify-content: flex-end;
|
|
4
|
+
padding-left: 12px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.cio-asa-user-message__bubble {
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
flex-direction: row;
|
|
10
|
+
justify-content: flex-end;
|
|
11
|
+
align-items: center;
|
|
12
|
+
padding: 13px 12px;
|
|
13
|
+
gap: 8px;
|
|
14
|
+
background: rgba(9, 9, 12, 0.9);
|
|
15
|
+
border-radius: 8px 0px 8px 8px;
|
|
16
|
+
font-weight: 400;
|
|
17
|
+
font-size: 14px;
|
|
18
|
+
line-height: 16px;
|
|
19
|
+
letter-spacing: -0.005em;
|
|
20
|
+
font-feature-settings: 'tnum' on, 'lnum' on;
|
|
21
|
+
color: #ffffff;
|
|
22
|
+
max-width: 100%;
|
|
23
|
+
word-wrap: break-word;
|
|
24
|
+
text-align: left;
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
5
|
+
const constructorio_ui_components_1 = require("@constructor-io/constructorio-ui-components");
|
|
6
|
+
const translate_1 = tslib_1.__importDefault(require("../../utils/translate"));
|
|
7
|
+
function UserMessage({ text, translations, componentOverrides }) {
|
|
8
|
+
const renderProps = { text };
|
|
9
|
+
return (react_1.default.createElement(constructorio_ui_components_1.RenderPropsWrapper, { override: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.reactNode, props: renderProps },
|
|
10
|
+
react_1.default.createElement("div", { className: 'cio-asa-user-message', role: 'group', "aria-label": (0, translate_1.default)('CioAsa.userMessage.ariaLabel', translations) },
|
|
11
|
+
react_1.default.createElement("div", { className: 'cio-asa-user-message__bubble' }, text))));
|
|
12
|
+
}
|
|
13
|
+
exports.default = UserMessage;
|
|
14
|
+
UserMessage.displayName = 'UserMessage';
|