@constructor-io/constructorio-ui-pia 2.4.0 → 2.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/constructorio-ui-pia-bundled.js +60 -60
  2. package/lib/cjs/components/CioPia/CioPia.js +10 -5
  3. package/lib/cjs/components/Input/Input.js +2 -2
  4. package/lib/cjs/components/PiaConversation/PiaConversation.js +4 -4
  5. package/lib/cjs/components/PiaConversation/PiaModal.js +8 -4
  6. package/lib/cjs/hooks/useAnswerResults.js +2 -4
  7. package/lib/cjs/hooks/useCioPia.js +5 -1
  8. package/lib/cjs/hooks/useConversation.js +61 -15
  9. package/lib/cjs/hooks/useViewportCallbacks.js +50 -0
  10. package/lib/cjs/stories/assets/storybook-styles.css +89 -0
  11. package/lib/cjs/utils/contentTransformers.js +8 -2
  12. package/lib/cjs/version.js +1 -1
  13. package/lib/mjs/components/CioPia/CioPia.js +10 -5
  14. package/lib/mjs/components/Input/Input.js +2 -2
  15. package/lib/mjs/components/PiaConversation/PiaConversation.js +4 -4
  16. package/lib/mjs/components/PiaConversation/PiaModal.js +8 -4
  17. package/lib/mjs/hooks/useAnswerResults.js +3 -5
  18. package/lib/mjs/hooks/useCioPia.js +5 -1
  19. package/lib/mjs/hooks/useConversation.js +60 -15
  20. package/lib/mjs/hooks/useViewportCallbacks.js +45 -0
  21. package/lib/mjs/stories/assets/storybook-styles.css +89 -0
  22. package/lib/mjs/utils/contentTransformers.js +7 -2
  23. package/lib/mjs/version.js +1 -1
  24. package/lib/types/components/Input/Input.d.ts +2 -1
  25. package/lib/types/components/PiaConversation/PiaConversation.d.ts +4 -1
  26. package/lib/types/components/PiaConversation/PiaModal.d.ts +4 -1
  27. package/lib/types/hooks/mocks/MockConstructorIOClient.d.ts +1 -1
  28. package/lib/types/hooks/useCioPia.d.ts +1 -0
  29. package/lib/types/hooks/useConversation.d.ts +4 -1
  30. package/lib/types/hooks/useViewportCallbacks.d.ts +9 -0
  31. package/lib/types/index.d.ts +1 -0
  32. package/lib/types/types.d.ts +18 -2
  33. package/lib/types/utils/contentTransformers.d.ts +26 -1
  34. package/lib/types/version.d.ts +1 -1
  35. package/package.json +1 -1
@@ -7,6 +7,7 @@ const Input_1 = tslib_1.__importDefault(require("../Input/Input"));
7
7
  const SuggestedQuestionsContainer_1 = tslib_1.__importDefault(require("../SuggestedQuestionsContainer/SuggestedQuestionsContainer"));
8
8
  const useCioPia_1 = tslib_1.__importDefault(require("../../hooks/useCioPia"));
9
9
  const useConversation_1 = tslib_1.__importDefault(require("../../hooks/useConversation"));
10
+ const useViewportCallbacks_1 = tslib_1.__importDefault(require("../../hooks/useViewportCallbacks"));
10
11
  const ErrorBlock_1 = tslib_1.__importDefault(require("../Error/ErrorBlock"));
11
12
  const LoadingSkeleton_1 = tslib_1.__importDefault(require("../LoadingSkeleton/LoadingSkeleton"));
12
13
  const translate_1 = require("../../utils/translate");
@@ -26,7 +27,8 @@ function CioPia(props) {
26
27
  suggestedQuestionsParameters,
27
28
  formatImageUrl: formatters === null || formatters === void 0 ? void 0 : formatters.formatImageUrl,
28
29
  });
29
- const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, handleSubmitQuestion, resetState, } = (0, useConversation_1.default)({ pia, itemId, isConversation, callbacks });
30
+ const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, context, handleSubmitQuestion, handleQuestionClick, handleInputFocus, resetState, } = (0, useConversation_1.default)({ pia, itemId, isConversation, callbacks });
31
+ const { containerRef } = (0, useViewportCallbacks_1.default)({ callbacks, context });
30
32
  const renderProps = {
31
33
  items: currentItems,
32
34
  isLoading,
@@ -51,22 +53,25 @@ function CioPia(props) {
51
53
  componentOverrides,
52
54
  displayedQuestions,
53
55
  handleSubmitQuestion,
56
+ handleQuestionClick,
57
+ containerRef,
58
+ onInputFocus: handleInputFocus,
54
59
  };
55
60
  if (type === 'modal') {
56
- return (react_1.default.createElement(PiaModal_1.default, { initialQuestions: pia.suggestedQuestions.data, handleSubmitQuestion: handleSubmitQuestion, isLoading: isLoading, componentOverrides: componentOverrides, translations: translations, onClose: resetState },
61
+ return (react_1.default.createElement(PiaModal_1.default, { initialQuestions: pia.suggestedQuestions.data, handleSubmitQuestion: handleSubmitQuestion, handleQuestionClick: handleQuestionClick, containerRef: containerRef, isLoading: isLoading, componentOverrides: componentOverrides, translations: translations, onInputFocus: handleInputFocus, onClose: resetState },
57
62
  react_1.default.createElement(PiaConversation_1.default, Object.assign({}, conversationHistoryProps))));
58
63
  }
59
64
  if (isConversation)
60
65
  return react_1.default.createElement(PiaConversation_1.default, Object.assign({}, conversationHistoryProps));
61
66
  // Default inline mode
62
- return (react_1.default.createElement("div", { className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
67
+ return (react_1.default.createElement("div", { ref: containerRef, className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
63
68
  react_1.default.createElement(constructorio_ui_components_1.RenderPropsWrapper, { props: renderProps, override: children || (componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.reactNode) },
64
69
  react_1.default.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, (0, translate_1.translate)('Any questions about this product?', translations)),
65
- react_1.default.createElement(Input_1.default, { onSubmit: handleSubmitQuestion, value: currentQuestion, translations: translations }),
70
+ react_1.default.createElement(Input_1.default, { onSubmit: handleSubmitQuestion, onFocus: handleInputFocus, value: currentQuestion, translations: translations }),
66
71
  isLoading && react_1.default.createElement(LoadingSkeleton_1.default, null),
67
72
  !isLoading && error && react_1.default.createElement(ErrorBlock_1.default, { message: (error === null || error === void 0 ? void 0 : error.message) || 'Unexpected error' }),
68
73
  !isLoading && !error && (react_1.default.createElement(react_1.default.Fragment, null,
69
74
  currentAnswer && (react_1.default.createElement(PiaInlineAnswer_1.default, { currentAnswer: currentAnswer, currentItems: currentItems, showFeedback: showFeedback, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides })),
70
- react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleSubmitQuestion, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions }))))));
75
+ react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions }))))));
71
76
  }
72
77
  exports.default = CioPia;
@@ -8,7 +8,7 @@ function SendIcon() {
8
8
  react_1.default.createElement("g", { id: '.icon-send' },
9
9
  react_1.default.createElement("path", { id: 'Vector', d: 'M14.8934 7.09533L14.8884 7.09314L1.54219 1.55752C1.42993 1.51053 1.30778 1.49211 1.18666 1.50388C1.06554 1.51566 0.949225 1.55728 0.848125 1.62502C0.741311 1.69501 0.653573 1.79045 0.592805 1.90277C0.532037 2.01509 0.500145 2.14075 0.5 2.26845V5.80877C0.50006 5.98335 0.561019 6.15243 0.67237 6.28689C0.783722 6.42134 0.938491 6.51274 1.11 6.54533L8.38906 7.89127C8.41767 7.89669 8.44348 7.91193 8.46205 7.93435C8.48062 7.95677 8.49078 7.98497 8.49078 8.01408C8.49078 8.04319 8.48062 8.07139 8.46205 8.09381C8.44348 8.11623 8.41767 8.13147 8.38906 8.13689L1.11031 9.48283C0.938851 9.51533 0.784092 9.60661 0.67269 9.74094C0.561288 9.87528 0.500219 10.0443 0.5 10.2188V13.7597C0.499917 13.8816 0.530111 14.0017 0.587871 14.1091C0.645632 14.2165 0.729152 14.3079 0.830938 14.375C0.953375 14.4564 1.09706 14.4998 1.24406 14.5C1.34626 14.4999 1.4474 14.4794 1.54156 14.4397L14.8875 8.93564L14.8934 8.93283C15.0731 8.85563 15.2262 8.72745 15.3337 8.56415C15.4413 8.40086 15.4986 8.20961 15.4986 8.01408C15.4986 7.81855 15.4413 7.6273 15.3337 7.46401C15.2262 7.30071 15.0731 7.17253 14.8934 7.09533Z', fill: 'white' }))));
10
10
  }
11
- function Input({ value: providedValue, placeholder, disabled = false, onSubmit, translations, }) {
11
+ function Input({ value: providedValue, placeholder, disabled = false, onSubmit, onFocus, translations, }) {
12
12
  const [value, setValue] = (0, react_1.useState)(providedValue || '');
13
13
  (0, react_1.useEffect)(() => {
14
14
  if (providedValue) {
@@ -32,7 +32,7 @@ function Input({ value: providedValue, placeholder, disabled = false, onSubmit,
32
32
  ? (0, translate_1.translate)('Ask anything', translations)
33
33
  : (placeholder !== null && placeholder !== void 0 ? placeholder : (0, translate_1.translate)('Ask anything'));
34
34
  return (react_1.default.createElement("div", { className: 'cio-pia-input-container' },
35
- react_1.default.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, placeholder: resolvedPlaceholder, disabled: disabled, className: 'cio-pia-input' }),
35
+ react_1.default.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, onFocus: onFocus, placeholder: resolvedPlaceholder, disabled: disabled, className: 'cio-pia-input' }),
36
36
  react_1.default.createElement("button", { type: 'button', onClick: handleSubmit, className: 'cio-pia-send-button', disabled: disabled },
37
37
  (0, translate_1.translate)('Send', translations),
38
38
  react_1.default.createElement(SendIcon, null))));
@@ -7,14 +7,14 @@ const SuggestedQuestionsContainer_1 = tslib_1.__importDefault(require("../Sugges
7
7
  const SuggestedQuestionsSkeleton_1 = tslib_1.__importDefault(require("../SuggestedQuestionsContainer/SuggestedQuestionsSkeleton"));
8
8
  const translate_1 = require("../../utils/translate");
9
9
  const ConversationHistory_1 = tslib_1.__importDefault(require("../ConversationHistory/ConversationHistory"));
10
- function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, }) {
10
+ function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, onInputFocus, }) {
11
11
  const hasHistory = conversationHistory.length > 0;
12
- return (react_1.default.createElement("div", { className: 'cio-pia-container cio-pia-conversation', "data-testid": 'cio-pia-container' },
12
+ return (react_1.default.createElement("div", { ref: containerRef, className: 'cio-pia-container cio-pia-conversation', "data-testid": 'cio-pia-container' },
13
13
  !hasHistory && (react_1.default.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, (0, translate_1.translate)('Any questions about this product?', translations))),
14
14
  react_1.default.createElement(ConversationHistory_1.default, { conversationHistory: conversationHistory, isLoading: isLoading, error: error, currentItems: currentItems, showFeedback: showFeedback, showPreviousItems: showPreviousItems, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides }),
15
15
  react_1.default.createElement("div", { className: 'cio-pia-conversation-footer' },
16
16
  isLoading && !error && react_1.default.createElement(SuggestedQuestionsSkeleton_1.default, null),
17
- !isLoading && !error && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleSubmitQuestion, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions })),
18
- react_1.default.createElement(Input_1.default, { onSubmit: handleSubmitQuestion, disabled: isLoading, translations: translations }))));
17
+ !isLoading && !error && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions })),
18
+ react_1.default.createElement(Input_1.default, { onSubmit: handleSubmitQuestion, onFocus: onInputFocus, disabled: isLoading, translations: translations }))));
19
19
  }
20
20
  exports.default = PiaConversation;
@@ -10,7 +10,7 @@ function CloseIcon() {
10
10
  return (react_1.default.createElement("svg", { width: '20', height: '20', viewBox: '0 0 20 20', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
11
11
  react_1.default.createElement("path", { d: 'M15.8334 5.34166L14.6584 4.16666L10.0001 8.82499L5.34175 4.16666L4.16675 5.34166L8.82508 9.99999L4.16675 14.6583L5.34175 15.8333L10.0001 11.175L14.6584 15.8333L15.8334 14.6583L11.1751 9.99999L15.8334 5.34166Z', fill: 'currentColor' })));
12
12
  }
13
- function PiaModal({ initialQuestions, handleSubmitQuestion, isLoading, componentOverrides, translations, onClose, children, }) {
13
+ function PiaModal({ initialQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, isLoading, componentOverrides, translations, onInputFocus, onClose, children, }) {
14
14
  const [isOpen, setIsOpen] = (0, react_1.useState)(false);
15
15
  const dialogRef = (0, react_1.useRef)(null);
16
16
  const openModal = (0, react_1.useCallback)(() => {
@@ -59,11 +59,15 @@ function PiaModal({ initialQuestions, handleSubmitQuestion, isLoading, component
59
59
  handleSubmitQuestion(question);
60
60
  openModal();
61
61
  }, [handleSubmitQuestion, openModal]);
62
- return (react_1.default.createElement("div", { className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
62
+ const handleQuestionClicked = (0, react_1.useCallback)((question) => {
63
+ handleQuestionClick(question);
64
+ openModal();
65
+ }, [handleQuestionClick, openModal]);
66
+ return (react_1.default.createElement("div", { ref: containerRef, className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
63
67
  react_1.default.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, (0, translate_1.translate)('Any questions about this product?', translations)),
64
68
  react_1.default.createElement("div", { className: 'cio-pia-conversation-footer' },
65
- initialQuestions.length > 0 && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: initialQuestions, onQuestionClick: handleQuestion, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions })),
66
- react_1.default.createElement(Input_1.default, { onSubmit: handleQuestion, disabled: isLoading || isOpen, translations: translations })),
69
+ initialQuestions.length > 0 && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: initialQuestions, onQuestionClick: handleQuestionClicked, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions })),
70
+ react_1.default.createElement(Input_1.default, { onSubmit: handleQuestion, onFocus: onInputFocus, disabled: isLoading || isOpen, translations: translations })),
67
71
  react_1.default.createElement("dialog", { ref: dialogRef, className: 'cio-pia-modal', "aria-labelledby": 'cio-pia-modal-title' },
68
72
  react_1.default.createElement("div", { className: 'cio-pia-modal-content' },
69
73
  react_1.default.createElement("div", { className: 'cio-pia-modal-header' },
@@ -28,9 +28,9 @@ const fetchAnswerResults = ({ client, itemId, question, variationId, threadId, }
28
28
  });
29
29
  function useAnswerResults({ itemId, variationId, threadId, cioClient, formatImageUrl, }) {
30
30
  const [answerResults, setAnswerResults] = (0, react_1.useState)(null);
31
- const [items, setItems] = (0, react_1.useState)(null);
32
31
  const [isLoading, setIsLoading] = (0, react_1.useState)(false);
33
32
  const [error, setError] = (0, react_1.useState)(null);
33
+ const items = (0, react_1.useMemo)(() => extractAndTransformItems(answerResults, formatImageUrl), [answerResults, formatImageUrl]);
34
34
  const fetchResult = (0, react_1.useCallback)((question) => {
35
35
  if (!cioClient)
36
36
  return;
@@ -39,18 +39,16 @@ function useAnswerResults({ itemId, variationId, threadId, cioClient, formatImag
39
39
  fetchAnswerResults({ client: cioClient, itemId, question, variationId, threadId })
40
40
  .then((fetchedAnswerResults) => {
41
41
  setAnswerResults(fetchedAnswerResults);
42
- setItems(extractAndTransformItems(fetchedAnswerResults, formatImageUrl));
43
42
  setError(null);
44
43
  })
45
44
  .catch((err) => {
46
45
  setError(err instanceof Error ? err : new Error('Error fetching answer'));
47
46
  setAnswerResults(null);
48
- setItems(null);
49
47
  })
50
48
  .finally(() => {
51
49
  setIsLoading(false);
52
50
  });
53
- }, [cioClient, itemId, variationId, threadId, formatImageUrl]);
51
+ }, [cioClient, itemId, variationId, threadId]);
54
52
  return {
55
53
  data: answerResults,
56
54
  items,
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
+ const react_1 = require("react");
4
5
  const useAnswerResults_1 = tslib_1.__importDefault(require("./useAnswerResults"));
5
6
  const useCioClient_1 = tslib_1.__importDefault(require("./useCioClient"));
6
7
  const useSuggestedQuestions_1 = tslib_1.__importDefault(require("./useSuggestedQuestions"));
7
8
  function useCioPia(props) {
8
- const { apiKey, itemId, variationId, threadId, cioClient: providedClient, suggestedQuestionsParameters, formatImageUrl, } = props;
9
+ const { apiKey, itemId, variationId, threadId: providedThreadId, cioClient: providedClient, suggestedQuestionsParameters, formatImageUrl, } = props;
10
+ const [generatedThreadId] = (0, react_1.useState)(() => crypto.randomUUID());
11
+ const threadId = providedThreadId || generatedThreadId;
9
12
  const defaultClient = (0, useCioClient_1.default)({ apiKey });
10
13
  const client = providedClient || defaultClient;
11
14
  const suggestedQuestions = (0, useSuggestedQuestions_1.default)({
@@ -23,6 +26,7 @@ function useCioPia(props) {
23
26
  formatImageUrl,
24
27
  });
25
28
  return {
29
+ threadId,
26
30
  suggestedQuestions,
27
31
  answers,
28
32
  };
@@ -3,24 +3,49 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const react_1 = require("react");
4
4
  function useConversation({ pia, itemId, isConversation, callbacks, }) {
5
5
  var _a, _b, _c, _d;
6
- const { suggestedQuestions, answers } = pia;
6
+ const { suggestedQuestions, answers, threadId } = pia;
7
7
  const { getAnswer } = answers;
8
+ const context = (0, react_1.useMemo)(() => ({ itemId, threadId }), [itemId, threadId]);
8
9
  const [currentQuestion, setCurrentQuestion] = (0, react_1.useState)('');
9
10
  const [displayedQuestions, setDisplayedQuestions] = (0, react_1.useState)([]);
10
11
  const [conversationHistory, setConversationHistory] = (0, react_1.useState)([]);
11
12
  const entryIdRef = (0, react_1.useRef)(0);
12
13
  const prevAnswerValueRef = (0, react_1.useRef)((_a = answers.data) === null || _a === void 0 ? void 0 : _a.value);
13
- const handleSubmitQuestion = (0, react_1.useCallback)((question) => {
14
- var _a;
15
- (_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onQuestionSubmit) === null || _a === void 0 ? void 0 : _a.call(callbacks, question);
14
+ const callbacksRef = (0, react_1.useRef)(callbacks);
15
+ const contextRef = (0, react_1.useRef)(context);
16
+ const lastQuestionRef = (0, react_1.useRef)('');
17
+ const lastSourceRef = (0, react_1.useRef)('user');
18
+ (0, react_1.useEffect)(() => {
19
+ callbacksRef.current = callbacks;
20
+ }, [callbacks]);
21
+ (0, react_1.useEffect)(() => {
22
+ contextRef.current = context;
23
+ }, [context]);
24
+ const submitQuestion = (0, react_1.useCallback)((question, source) => {
25
+ lastSourceRef.current = source;
26
+ lastQuestionRef.current = question;
16
27
  setCurrentQuestion(question);
17
28
  getAnswer(question);
18
29
  if (isConversation) {
19
30
  entryIdRef.current += 1;
20
31
  const id = entryIdRef.current;
21
- setConversationHistory((prev) => [...prev, { id, question, answer: '' }]);
32
+ setConversationHistory((prev) => [...prev, { id, question, answer: '', source }]);
22
33
  }
23
- }, [getAnswer, isConversation, callbacks]);
34
+ }, [getAnswer, isConversation]);
35
+ const handleSubmitQuestion = (0, react_1.useCallback)((question) => {
36
+ var _a, _b;
37
+ (_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onQuestionSubmit) === null || _b === void 0 ? void 0 : _b.call(_a, question, contextRef.current, 'user');
38
+ submitQuestion(question, 'user');
39
+ }, [submitQuestion]);
40
+ const handleQuestionClick = (0, react_1.useCallback)((question) => {
41
+ var _a, _b;
42
+ (_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onQuestionSubmit) === null || _b === void 0 ? void 0 : _b.call(_a, question, contextRef.current, 'suggestion');
43
+ submitQuestion(question, 'suggestion');
44
+ }, [submitQuestion]);
45
+ const handleInputFocus = (0, react_1.useCallback)(() => {
46
+ var _a, _b;
47
+ (_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, contextRef.current);
48
+ }, []);
24
49
  const resetState = (0, react_1.useCallback)(() => {
25
50
  setCurrentQuestion('');
26
51
  setDisplayedQuestions(suggestedQuestions.data);
@@ -42,20 +67,38 @@ function useConversation({ pia, itemId, isConversation, callbacks, }) {
42
67
  setDisplayedQuestions(answers.data.follow_up_questions);
43
68
  }, [answers.data]);
44
69
  (0, react_1.useEffect)(() => {
45
- var _a, _b;
70
+ var _a, _b, _c, _d, _e, _f;
46
71
  const answerValue = (_b = (_a = answers.data) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
47
- if (!isConversation || !answerValue)
72
+ if (!answerValue)
48
73
  return;
49
74
  if (answerValue === prevAnswerValueRef.current)
50
75
  return;
51
76
  prevAnswerValueRef.current = answerValue;
52
- setConversationHistory((prev) => {
53
- if (prev.length === 0)
54
- return prev;
55
- const updated = [...prev];
56
- updated[updated.length - 1] = Object.assign(Object.assign({}, updated[updated.length - 1]), { answer: answerValue, items: answers.items });
57
- return updated;
58
- });
77
+ const answerThreadId = (_c = answers.data) === null || _c === void 0 ? void 0 : _c.thread_id;
78
+ const qnaResultId = (_d = answers.data) === null || _d === void 0 ? void 0 : _d.qna_result_id;
79
+ if (isConversation) {
80
+ setConversationHistory((prev) => {
81
+ var _a, _b;
82
+ if (prev.length === 0)
83
+ return prev;
84
+ const updated = [...prev];
85
+ updated[updated.length - 1] = Object.assign(Object.assign({}, updated[updated.length - 1]), { answer: answerValue, items: answers.items, threadId: answerThreadId, qnaResultId });
86
+ (_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onAnswer) === null || _b === void 0 ? void 0 : _b.call(_a, updated, contextRef.current);
87
+ return updated;
88
+ });
89
+ }
90
+ else {
91
+ const entry = {
92
+ id: entryIdRef.current,
93
+ question: lastQuestionRef.current,
94
+ answer: answerValue,
95
+ source: lastSourceRef.current,
96
+ items: answers.items,
97
+ threadId: answerThreadId,
98
+ qnaResultId,
99
+ };
100
+ (_f = (_e = callbacksRef.current) === null || _e === void 0 ? void 0 : _e.onAnswer) === null || _f === void 0 ? void 0 : _f.call(_e, [entry], contextRef.current);
101
+ }
59
102
  }, [isConversation, answers.data, answers.items]);
60
103
  const currentAnswer = (_c = (_b = answers.data) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : '';
61
104
  const currentItems = (_d = answers.items) !== null && _d !== void 0 ? _d : null;
@@ -69,7 +112,10 @@ function useConversation({ pia, itemId, isConversation, callbacks, }) {
69
112
  currentItems,
70
113
  isLoading,
71
114
  error,
115
+ context,
72
116
  handleSubmitQuestion,
117
+ handleQuestionClick,
118
+ handleInputFocus,
73
119
  resetState,
74
120
  };
75
121
  }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const react_1 = require("react");
4
+ function useViewportCallbacks({ callbacks, context, }) {
5
+ const callbacksRef = (0, react_1.useRef)(callbacks);
6
+ const contextRef = (0, react_1.useRef)(context);
7
+ const hasBeenVisibleRef = (0, react_1.useRef)(false);
8
+ const hasFiredOutOfViewRef = (0, react_1.useRef)(false);
9
+ const observerRef = (0, react_1.useRef)(null);
10
+ (0, react_1.useEffect)(() => {
11
+ callbacksRef.current = callbacks;
12
+ }, [callbacks]);
13
+ (0, react_1.useEffect)(() => {
14
+ contextRef.current = context;
15
+ }, [context]);
16
+ (0, react_1.useEffect)(() => {
17
+ return () => {
18
+ var _a;
19
+ (_a = observerRef.current) === null || _a === void 0 ? void 0 : _a.disconnect();
20
+ };
21
+ }, []);
22
+ const containerRef = (0, react_1.useCallback)((node) => {
23
+ if (observerRef.current) {
24
+ observerRef.current.disconnect();
25
+ observerRef.current = null;
26
+ }
27
+ if (!node)
28
+ return;
29
+ hasBeenVisibleRef.current = false;
30
+ hasFiredOutOfViewRef.current = false;
31
+ const observer = new IntersectionObserver(([entry]) => {
32
+ var _a, _b, _c, _d;
33
+ if (entry.isIntersecting && !hasBeenVisibleRef.current) {
34
+ hasBeenVisibleRef.current = true;
35
+ (_b = (_a = callbacksRef.current) === null || _a === void 0 ? void 0 : _a.onView) === null || _b === void 0 ? void 0 : _b.call(_a, contextRef.current);
36
+ }
37
+ else if (!entry.isIntersecting &&
38
+ hasBeenVisibleRef.current &&
39
+ !hasFiredOutOfViewRef.current) {
40
+ hasFiredOutOfViewRef.current = true;
41
+ (_d = (_c = callbacksRef.current) === null || _c === void 0 ? void 0 : _c.onOutOfView) === null || _d === void 0 ? void 0 : _d.call(_c, contextRef.current);
42
+ observer.disconnect();
43
+ }
44
+ }, { threshold: 0.5 });
45
+ observer.observe(node);
46
+ observerRef.current = observer;
47
+ }, []);
48
+ return { containerRef };
49
+ }
50
+ exports.default = useViewportCallbacks;
@@ -110,3 +110,92 @@ div.badge-wrapper code {
110
110
  background: #d8e8fd;
111
111
  color: #3c70bf;
112
112
  }
113
+
114
+ .cio-flow-diagram {
115
+ display: flex;
116
+ flex-direction: column;
117
+ gap: 4px;
118
+ margin: 24px 0 0;
119
+ font-family: system-ui, sans-serif;
120
+ font-size: 14px;
121
+ }
122
+
123
+ .cio-flow-diagram .flow-step {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 12px;
127
+ }
128
+
129
+ .cio-flow-diagram .flow-box {
130
+ padding: 10px 16px;
131
+ border-radius: 8px;
132
+ min-width: 220px;
133
+ text-align: center;
134
+ }
135
+
136
+ .cio-flow-diagram .flow-box--consumer {
137
+ background: #eff6ff;
138
+ border: 1px solid #bfdbfe;
139
+ }
140
+
141
+ .cio-flow-diagram .flow-box--internal {
142
+ background: #f5f3ff;
143
+ border: 1px solid #ddd6fe;
144
+ }
145
+
146
+ .cio-flow-diagram .flow-box--output {
147
+ background: #f0fdf4;
148
+ border: 1px solid #bbf7d0;
149
+ }
150
+
151
+ .cio-flow-diagram .flow-arrow {
152
+ margin-left: 110px;
153
+ color: #9ca3af;
154
+ }
155
+
156
+ .cio-flow-diagram .flow-label {
157
+ font-size: 12px;
158
+ color: #9ca3af;
159
+ font-style: italic;
160
+ }
161
+
162
+ .cio-flow-diagram .flow-callback {
163
+ font-size: 12px;
164
+ color: #059669;
165
+ }
166
+
167
+ .cio-flow-diagram .flow-box-subtitle {
168
+ font-size: 12px;
169
+ color: #6b7280;
170
+ }
171
+
172
+ .cio-flow-legend {
173
+ display: flex;
174
+ gap: 16px;
175
+ margin: 32px 0 16px;
176
+ font-size: 12px;
177
+ }
178
+
179
+ .cio-flow-legend .legend-swatch {
180
+ display: inline-block;
181
+ width: 12px;
182
+ height: 12px;
183
+ border-radius: 3px;
184
+ margin-right: 4px;
185
+ vertical-align: middle;
186
+ }
187
+
188
+ .cio-flow-legend .legend-swatch--consumer {
189
+ background: #eff6ff;
190
+ border: 1px solid #bfdbfe;
191
+ }
192
+
193
+ .cio-flow-legend .legend-swatch--internal {
194
+ background: #f5f3ff;
195
+ border: 1px solid #ddd6fe;
196
+ }
197
+
198
+ .cio-flow-legend .legend-swatch--output {
199
+ background: #f0fdf4;
200
+ border: 1px solid #bbf7d0;
201
+ }
@@ -13,10 +13,16 @@ function sanitizeHtml(html) {
13
13
  return dompurify_1.default.sanitize(html, purifyConfig);
14
14
  }
15
15
  exports.sanitizeHtml = sanitizeHtml;
16
- function renderMarkdown(content) {
16
+ function renderMarkdown(content, options) {
17
+ var _a;
17
18
  if (!content)
18
19
  return '';
19
- const html = marked_1.marked.parse(content, { async: false });
20
+ const html = marked_1.marked.parse(content, { async: false, breaks: true });
21
+ if (options === null || options === void 0 ? void 0 : options.sanitize) {
22
+ const purifier = (0, dompurify_1.default)(window);
23
+ const config = Object.assign(Object.assign({}, purifyConfig), { FORBID_TAGS: [...((_a = purifyConfig.FORBID_TAGS) !== null && _a !== void 0 ? _a : [])] });
24
+ return options.sanitize(purifier, html, { config });
25
+ }
20
26
  return dompurify_1.default.sanitize(html, purifyConfig);
21
27
  }
22
28
  exports.renderMarkdown = renderMarkdown;
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = '2.4.0';
3
+ exports.default = '2.6.3';
@@ -4,6 +4,7 @@ import Input from '../Input/Input';
4
4
  import SuggestedQuestionsContainer from '../SuggestedQuestionsContainer/SuggestedQuestionsContainer';
5
5
  import useCioPia from '../../hooks/useCioPia';
6
6
  import useConversation from '../../hooks/useConversation';
7
+ import useViewportCallbacks from '../../hooks/useViewportCallbacks';
7
8
  import ErrorBlock from '../Error/ErrorBlock';
8
9
  import LoadingSkeleton from '../LoadingSkeleton/LoadingSkeleton';
9
10
  import { translate } from '../../utils/translate';
@@ -23,7 +24,8 @@ export default function CioPia(props) {
23
24
  suggestedQuestionsParameters,
24
25
  formatImageUrl: formatters?.formatImageUrl,
25
26
  });
26
- const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, handleSubmitQuestion, resetState, } = useConversation({ pia, itemId, isConversation, callbacks });
27
+ const { currentQuestion, displayedQuestions, conversationHistory, currentAnswer, currentItems, isLoading, error, context, handleSubmitQuestion, handleQuestionClick, handleInputFocus, resetState, } = useConversation({ pia, itemId, isConversation, callbacks });
28
+ const { containerRef } = useViewportCallbacks({ callbacks, context });
27
29
  const renderProps = {
28
30
  items: currentItems,
29
31
  isLoading,
@@ -48,21 +50,24 @@ export default function CioPia(props) {
48
50
  componentOverrides,
49
51
  displayedQuestions,
50
52
  handleSubmitQuestion,
53
+ handleQuestionClick,
54
+ containerRef,
55
+ onInputFocus: handleInputFocus,
51
56
  };
52
57
  if (type === 'modal') {
53
- return (React.createElement(PiaModal, { initialQuestions: pia.suggestedQuestions.data, handleSubmitQuestion: handleSubmitQuestion, isLoading: isLoading, componentOverrides: componentOverrides, translations: translations, onClose: resetState },
58
+ return (React.createElement(PiaModal, { initialQuestions: pia.suggestedQuestions.data, handleSubmitQuestion: handleSubmitQuestion, handleQuestionClick: handleQuestionClick, containerRef: containerRef, isLoading: isLoading, componentOverrides: componentOverrides, translations: translations, onInputFocus: handleInputFocus, onClose: resetState },
54
59
  React.createElement(PiaConversation, { ...conversationHistoryProps })));
55
60
  }
56
61
  if (isConversation)
57
62
  return React.createElement(PiaConversation, { ...conversationHistoryProps });
58
63
  // Default inline mode
59
- return (React.createElement("div", { className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
64
+ return (React.createElement("div", { ref: containerRef, className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
60
65
  React.createElement(RenderPropsWrapper, { props: renderProps, override: children || componentOverrides?.reactNode },
61
66
  React.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, translate('Any questions about this product?', translations)),
62
- React.createElement(Input, { onSubmit: handleSubmitQuestion, value: currentQuestion, translations: translations }),
67
+ React.createElement(Input, { onSubmit: handleSubmitQuestion, onFocus: handleInputFocus, value: currentQuestion, translations: translations }),
63
68
  isLoading && React.createElement(LoadingSkeleton, null),
64
69
  !isLoading && error && React.createElement(ErrorBlock, { message: error?.message || 'Unexpected error' }),
65
70
  !isLoading && !error && (React.createElement(React.Fragment, null,
66
71
  currentAnswer && (React.createElement(PiaInlineAnswer, { currentAnswer: currentAnswer, currentItems: currentItems, showFeedback: showFeedback, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides })),
67
- React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick: handleSubmitQuestion, componentOverride: componentOverrides?.suggestedQuestions }))))));
72
+ React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides?.suggestedQuestions }))))));
68
73
  }
@@ -5,7 +5,7 @@ function SendIcon() {
5
5
  React.createElement("g", { id: '.icon-send' },
6
6
  React.createElement("path", { id: 'Vector', d: 'M14.8934 7.09533L14.8884 7.09314L1.54219 1.55752C1.42993 1.51053 1.30778 1.49211 1.18666 1.50388C1.06554 1.51566 0.949225 1.55728 0.848125 1.62502C0.741311 1.69501 0.653573 1.79045 0.592805 1.90277C0.532037 2.01509 0.500145 2.14075 0.5 2.26845V5.80877C0.50006 5.98335 0.561019 6.15243 0.67237 6.28689C0.783722 6.42134 0.938491 6.51274 1.11 6.54533L8.38906 7.89127C8.41767 7.89669 8.44348 7.91193 8.46205 7.93435C8.48062 7.95677 8.49078 7.98497 8.49078 8.01408C8.49078 8.04319 8.48062 8.07139 8.46205 8.09381C8.44348 8.11623 8.41767 8.13147 8.38906 8.13689L1.11031 9.48283C0.938851 9.51533 0.784092 9.60661 0.67269 9.74094C0.561288 9.87528 0.500219 10.0443 0.5 10.2188V13.7597C0.499917 13.8816 0.530111 14.0017 0.587871 14.1091C0.645632 14.2165 0.729152 14.3079 0.830938 14.375C0.953375 14.4564 1.09706 14.4998 1.24406 14.5C1.34626 14.4999 1.4474 14.4794 1.54156 14.4397L14.8875 8.93564L14.8934 8.93283C15.0731 8.85563 15.2262 8.72745 15.3337 8.56415C15.4413 8.40086 15.4986 8.20961 15.4986 8.01408C15.4986 7.81855 15.4413 7.6273 15.3337 7.46401C15.2262 7.30071 15.0731 7.17253 14.8934 7.09533Z', fill: 'white' }))));
7
7
  }
8
- function Input({ value: providedValue, placeholder, disabled = false, onSubmit, translations, }) {
8
+ function Input({ value: providedValue, placeholder, disabled = false, onSubmit, onFocus, translations, }) {
9
9
  const [value, setValue] = useState(providedValue || '');
10
10
  useEffect(() => {
11
11
  if (providedValue) {
@@ -29,7 +29,7 @@ function Input({ value: providedValue, placeholder, disabled = false, onSubmit,
29
29
  ? translate('Ask anything', translations)
30
30
  : (placeholder ?? translate('Ask anything'));
31
31
  return (React.createElement("div", { className: 'cio-pia-input-container' },
32
- React.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, placeholder: resolvedPlaceholder, disabled: disabled, className: 'cio-pia-input' }),
32
+ React.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, onFocus: onFocus, placeholder: resolvedPlaceholder, disabled: disabled, className: 'cio-pia-input' }),
33
33
  React.createElement("button", { type: 'button', onClick: handleSubmit, className: 'cio-pia-send-button', disabled: disabled },
34
34
  translate('Send', translations),
35
35
  React.createElement(SendIcon, null))));
@@ -4,13 +4,13 @@ import SuggestedQuestionsContainer from '../SuggestedQuestionsContainer/Suggeste
4
4
  import SuggestedQuestionsSkeleton from '../SuggestedQuestionsContainer/SuggestedQuestionsSkeleton';
5
5
  import { translate } from '../../utils/translate';
6
6
  import ConversationHistory from '../ConversationHistory/ConversationHistory';
7
- export default function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, }) {
7
+ export default function PiaConversation({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems, learnMoreUrl, disclaimerPosition, translations, callbacks, componentOverrides, displayedQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, onInputFocus, }) {
8
8
  const hasHistory = conversationHistory.length > 0;
9
- return (React.createElement("div", { className: 'cio-pia-container cio-pia-conversation', "data-testid": 'cio-pia-container' },
9
+ return (React.createElement("div", { ref: containerRef, className: 'cio-pia-container cio-pia-conversation', "data-testid": 'cio-pia-container' },
10
10
  !hasHistory && (React.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, translate('Any questions about this product?', translations))),
11
11
  React.createElement(ConversationHistory, { conversationHistory: conversationHistory, isLoading: isLoading, error: error, currentItems: currentItems, showFeedback: showFeedback, showPreviousItems: showPreviousItems, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides }),
12
12
  React.createElement("div", { className: 'cio-pia-conversation-footer' },
13
13
  isLoading && !error && React.createElement(SuggestedQuestionsSkeleton, null),
14
- !isLoading && !error && (React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick: handleSubmitQuestion, componentOverride: componentOverrides?.suggestedQuestions })),
15
- React.createElement(Input, { onSubmit: handleSubmitQuestion, disabled: isLoading, translations: translations }))));
14
+ !isLoading && !error && (React.createElement(SuggestedQuestionsContainer, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides?.suggestedQuestions })),
15
+ React.createElement(Input, { onSubmit: handleSubmitQuestion, onFocus: onInputFocus, disabled: isLoading, translations: translations }))));
16
16
  }
@@ -7,7 +7,7 @@ function CloseIcon() {
7
7
  return (React.createElement("svg", { width: '20', height: '20', viewBox: '0 0 20 20', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
8
8
  React.createElement("path", { d: 'M15.8334 5.34166L14.6584 4.16666L10.0001 8.82499L5.34175 4.16666L4.16675 5.34166L8.82508 9.99999L4.16675 14.6583L5.34175 15.8333L10.0001 11.175L14.6584 15.8333L15.8334 14.6583L11.1751 9.99999L15.8334 5.34166Z', fill: 'currentColor' })));
9
9
  }
10
- export default function PiaModal({ initialQuestions, handleSubmitQuestion, isLoading, componentOverrides, translations, onClose, children, }) {
10
+ export default function PiaModal({ initialQuestions, handleSubmitQuestion, handleQuestionClick, containerRef, isLoading, componentOverrides, translations, onInputFocus, onClose, children, }) {
11
11
  const [isOpen, setIsOpen] = useState(false);
12
12
  const dialogRef = useRef(null);
13
13
  const openModal = useCallback(() => {
@@ -56,11 +56,15 @@ export default function PiaModal({ initialQuestions, handleSubmitQuestion, isLoa
56
56
  handleSubmitQuestion(question);
57
57
  openModal();
58
58
  }, [handleSubmitQuestion, openModal]);
59
- return (React.createElement("div", { className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
59
+ const handleQuestionClicked = useCallback((question) => {
60
+ handleQuestionClick(question);
61
+ openModal();
62
+ }, [handleQuestionClick, openModal]);
63
+ return (React.createElement("div", { ref: containerRef, className: 'cio-pia-container', "data-testid": 'cio-pia-container' },
60
64
  React.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, translate('Any questions about this product?', translations)),
61
65
  React.createElement("div", { className: 'cio-pia-conversation-footer' },
62
- initialQuestions.length > 0 && (React.createElement(SuggestedQuestionsContainer, { questions: initialQuestions, onQuestionClick: handleQuestion, componentOverride: componentOverrides?.suggestedQuestions })),
63
- React.createElement(Input, { onSubmit: handleQuestion, disabled: isLoading || isOpen, translations: translations })),
66
+ initialQuestions.length > 0 && (React.createElement(SuggestedQuestionsContainer, { questions: initialQuestions, onQuestionClick: handleQuestionClicked, componentOverride: componentOverrides?.suggestedQuestions })),
67
+ React.createElement(Input, { onSubmit: handleQuestion, onFocus: onInputFocus, disabled: isLoading || isOpen, translations: translations })),
64
68
  React.createElement("dialog", { ref: dialogRef, className: 'cio-pia-modal', "aria-labelledby": 'cio-pia-modal-title' },
65
69
  React.createElement("div", { className: 'cio-pia-modal-content' },
66
70
  React.createElement("div", { className: 'cio-pia-modal-header' },
@@ -1,4 +1,4 @@
1
- import { useCallback, useState } from 'react';
1
+ import { useCallback, useMemo, useState } from 'react';
2
2
  import { transformResultItem } from '../utils/transformers';
3
3
  const extractAndTransformItems = (data, formatImageUrl) => {
4
4
  if (!data?.item_results?.response?.results) {
@@ -24,9 +24,9 @@ const fetchAnswerResults = async ({ client, itemId, question, variationId, threa
24
24
  };
25
25
  export default function useAnswerResults({ itemId, variationId, threadId, cioClient, formatImageUrl, }) {
26
26
  const [answerResults, setAnswerResults] = useState(null);
27
- const [items, setItems] = useState(null);
28
27
  const [isLoading, setIsLoading] = useState(false);
29
28
  const [error, setError] = useState(null);
29
+ const items = useMemo(() => extractAndTransformItems(answerResults, formatImageUrl), [answerResults, formatImageUrl]);
30
30
  const fetchResult = useCallback((question) => {
31
31
  if (!cioClient)
32
32
  return;
@@ -35,18 +35,16 @@ export default function useAnswerResults({ itemId, variationId, threadId, cioCli
35
35
  fetchAnswerResults({ client: cioClient, itemId, question, variationId, threadId })
36
36
  .then((fetchedAnswerResults) => {
37
37
  setAnswerResults(fetchedAnswerResults);
38
- setItems(extractAndTransformItems(fetchedAnswerResults, formatImageUrl));
39
38
  setError(null);
40
39
  })
41
40
  .catch((err) => {
42
41
  setError(err instanceof Error ? err : new Error('Error fetching answer'));
43
42
  setAnswerResults(null);
44
- setItems(null);
45
43
  })
46
44
  .finally(() => {
47
45
  setIsLoading(false);
48
46
  });
49
- }, [cioClient, itemId, variationId, threadId, formatImageUrl]);
47
+ }, [cioClient, itemId, variationId, threadId]);
50
48
  return {
51
49
  data: answerResults,
52
50
  items,