@constructor-io/constructorio-ui-pia 2.11.0 → 2.13.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.
Files changed (69) hide show
  1. package/dist/constructorio-ui-pia-bundled.js +62 -62
  2. package/lib/cjs/components/CioPia/CioPiaQna.js +10 -4
  3. package/lib/cjs/components/CioPia/CioPiaStyles.css +5 -0
  4. package/lib/cjs/components/CioPia/PiaCustomCarousel.js +34 -29
  5. package/lib/cjs/components/ConversationHistory/ConversationHistory.js +10 -5
  6. package/lib/cjs/components/Error/ErrorBlock.js +7 -5
  7. package/lib/cjs/components/Feedback/Feedback.js +4 -4
  8. package/lib/cjs/components/Input/Input.js +2 -1
  9. package/lib/cjs/components/LoadingSkeleton/LoadingSkeleton.js +2 -1
  10. package/lib/cjs/components/PiaConversation/PiaModal.js +22 -4
  11. package/lib/cjs/components/StatusRegion/StatusRegion.js +34 -0
  12. package/lib/cjs/components/SuggestedQuestionsContainer/SuggestedQuestionsSkeleton.js +1 -1
  13. package/lib/cjs/components/icons/QuestionIcon.js +1 -1
  14. package/lib/cjs/components/icons/SendIcon.js +1 -1
  15. package/lib/cjs/components/icons/SparklesIcon.js +1 -1
  16. package/lib/cjs/hooks/useAnswerResults.js +4 -14
  17. package/lib/cjs/hooks/useCioPia.js +42 -4
  18. package/lib/cjs/hooks/useConversation.js +10 -8
  19. package/lib/cjs/hooks/usePiaClient.js +2 -7
  20. package/lib/cjs/hooks/useRecsPod.js +10 -5
  21. package/lib/cjs/hooks/useSuggestedQuestions.js +10 -26
  22. package/lib/cjs/types.js +0 -2
  23. package/lib/cjs/utils/translate.js +12 -0
  24. package/lib/cjs/version.js +1 -1
  25. package/lib/mjs/components/CioPia/CioPiaQna.js +10 -4
  26. package/lib/mjs/components/CioPia/CioPiaStyles.css +5 -0
  27. package/lib/mjs/components/CioPia/PiaCustomCarousel.js +53 -30
  28. package/lib/mjs/components/ConversationHistory/ConversationHistory.js +10 -5
  29. package/lib/mjs/components/Error/ErrorBlock.js +7 -5
  30. package/lib/mjs/components/Feedback/Feedback.js +4 -4
  31. package/lib/mjs/components/Input/Input.js +2 -1
  32. package/lib/mjs/components/LoadingSkeleton/LoadingSkeleton.js +2 -1
  33. package/lib/mjs/components/PiaConversation/PiaModal.js +22 -4
  34. package/lib/mjs/components/StatusRegion/StatusRegion.js +28 -0
  35. package/lib/mjs/components/SuggestedQuestionsContainer/SuggestedQuestionsSkeleton.js +1 -1
  36. package/lib/mjs/components/icons/QuestionIcon.js +1 -1
  37. package/lib/mjs/components/icons/SendIcon.js +1 -1
  38. package/lib/mjs/components/icons/SparklesIcon.js +1 -1
  39. package/lib/mjs/hooks/useAnswerResults.js +4 -13
  40. package/lib/mjs/hooks/useCioPia.js +43 -4
  41. package/lib/mjs/hooks/useConversation.js +7 -5
  42. package/lib/mjs/hooks/usePiaClient.js +2 -7
  43. package/lib/mjs/hooks/useRecsPod.js +9 -5
  44. package/lib/mjs/hooks/useSuggestedQuestions.js +12 -24
  45. package/lib/mjs/types.js +0 -1
  46. package/lib/mjs/utils/translate.js +12 -0
  47. package/lib/mjs/version.js +1 -1
  48. package/lib/types/components/CioPia/types.d.ts +20 -5
  49. package/lib/types/components/ConversationHistory/ConversationHistory.d.ts +7 -1
  50. package/lib/types/components/Error/ErrorBlock.d.ts +9 -1
  51. package/lib/types/components/StatusRegion/StatusRegion.d.ts +13 -0
  52. package/lib/types/hooks/useAnswerResults.d.ts +4 -4
  53. package/lib/types/hooks/useCioPia.d.ts +20 -5
  54. package/lib/types/hooks/usePiaClient.d.ts +4 -9
  55. package/lib/types/hooks/useRecsPod.d.ts +2 -2
  56. package/lib/types/hooks/useSuggestedQuestions.d.ts +3 -4
  57. package/lib/types/types.d.ts +53 -6
  58. package/lib/types/utils/translate.d.ts +3 -0
  59. package/lib/types/version.d.ts +1 -1
  60. package/package.json +3 -3
  61. package/lib/cjs/hooks/mocks/MockConstructorIOClient.js +0 -24
  62. package/lib/cjs/hooks/mocks/agent.js +0 -183
  63. package/lib/cjs/hooks/mocks/types.js +0 -2
  64. package/lib/mjs/hooks/mocks/MockConstructorIOClient.js +0 -38
  65. package/lib/mjs/hooks/mocks/agent.js +0 -173
  66. package/lib/mjs/hooks/mocks/types.js +0 -1
  67. package/lib/types/hooks/mocks/MockConstructorIOClient.d.ts +0 -14
  68. package/lib/types/hooks/mocks/agent.d.ts +0 -23
  69. package/lib/types/hooks/mocks/types.d.ts +0 -77
@@ -17,11 +17,12 @@ const translate_1 = require("../../utils/translate");
17
17
  const PiaInlineAnswer_1 = tslib_1.__importDefault(require("../PiaInlineAnswer/PiaInlineAnswer"));
18
18
  const PiaModal_1 = tslib_1.__importDefault(require("../PiaConversation/PiaModal"));
19
19
  const PiaConversation_1 = tslib_1.__importDefault(require("../PiaConversation/PiaConversation"));
20
+ const StatusRegion_1 = tslib_1.__importStar(require("../StatusRegion/StatusRegion"));
20
21
  /** The question-and-answer experience: `mode: 'default'`, `mode: 'conversation'`, and the modal. */
21
22
  // eslint-disable-next-line complexity
22
23
  function CioPiaQna(props) {
23
24
  var _a;
24
- const { apiKey, itemId, itemName, threadId, variationId, cioClient, displayConfigs, componentOverrides, callbacks, formatters, productCardProps, children, translations, suggestedQuestionsParameters, parameters, trackingConfigs, } = props;
25
+ const { apiKey, itemId, itemName, threadId, variationId, cioClient, displayConfigs, componentOverrides, callbacks, formatters, productCardProps, children, translations, suggestedQuestionsParameters, answerParameters, parameters, trackingConfigs, } = props;
25
26
  const { learnMoreUrl, showFeedback, mode = 'default', type = 'inline', showPreviousItems, disclaimerPosition = 'bottom', } = displayConfigs || {};
26
27
  const isConversation = mode === 'conversation' || type === 'modal';
27
28
  const { priceCurrency } = productCardProps || {};
@@ -32,6 +33,7 @@ function CioPiaQna(props) {
32
33
  variationId,
33
34
  cioClient,
34
35
  suggestedQuestionsParameters,
36
+ answerParameters,
35
37
  parameters,
36
38
  formatImageUrl: formatters === null || formatters === void 0 ? void 0 : formatters.formatImageUrl,
37
39
  });
@@ -54,10 +56,12 @@ function CioPiaQna(props) {
54
56
  callbackContainerRef(node);
55
57
  }, [viewportContainerRef, callbackContainerRef]);
56
58
  const qnaResultId = (_a = pia.answers.data) === null || _a === void 0 ? void 0 : _a.qna_result_id;
57
- // The text bars stand in for the answer alone, so they track the answer request only. The question
59
+ // The text bars and the "Loading answer" status track the answer request only. The question
58
60
  // row keeps the combined `isLoading`: the follow-up questions that refill it arrive with the
59
61
  // answer, so the row is waiting on either request.
60
62
  const isAnswerLoading = pia.answers.isLoading;
63
+ // Inline mode renders the answer outside any live region.
64
+ const answerStatus = (0, StatusRegion_1.answerStatusMessage)(isAnswerLoading, !!currentAnswer, translations);
61
65
  const renderProps = {
62
66
  items: currentItems,
63
67
  isLoading,
@@ -71,6 +75,7 @@ function CioPiaQna(props) {
71
75
  const conversationHistoryProps = {
72
76
  conversationHistory,
73
77
  isLoading,
78
+ isAnswerLoading,
74
79
  error,
75
80
  currentItems,
76
81
  showFeedback,
@@ -102,9 +107,10 @@ function CioPiaQna(props) {
102
107
  react_1.default.createElement("p", { className: 'cio-pia-title', "data-testid": 'cio-pia-title' }, (0, translate_1.translate)('Any questions about this product?', translations)),
103
108
  react_1.default.createElement(Input_1.default, { onSubmit: handleSubmitQuestion, onFocus: handleInputFocus, value: currentQuestion, translations: translations, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.input }),
104
109
  isAnswerLoading && react_1.default.createElement(LoadingSkeleton_1.default, { componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.loading }),
105
- !isAnswerLoading && error && react_1.default.createElement(ErrorBlock_1.default, { message: (error === null || error === void 0 ? void 0 : error.message) || 'Unexpected error' }),
110
+ !isAnswerLoading && error && (react_1.default.createElement(ErrorBlock_1.default, { key: error.message || (0, translate_1.translate)('Unexpected error', translations), message: error.message, translations: translations })),
106
111
  !isAnswerLoading && !error && currentAnswer && (react_1.default.createElement(PiaInlineAnswer_1.default, { currentAnswer: currentAnswer, currentItems: currentItems, showFeedback: showFeedback, learnMoreUrl: learnMoreUrl, disclaimerPosition: disclaimerPosition, translations: translations, callbacks: callbacks, componentOverrides: componentOverrides, onFeedback: handleFeedback, onResultClick: tracking.trackResultClick, question: currentQuestion, qnaResultId: qnaResultId, priceCurrency: priceCurrency })),
107
112
  isLoading && react_1.default.createElement(SuggestedQuestionsSkeleton_1.default, null),
108
- !isLoading && !error && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions })))));
113
+ !isLoading && !error && (react_1.default.createElement(SuggestedQuestionsContainer_1.default, { questions: displayedQuestions, onQuestionClick: handleQuestionClick, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.suggestedQuestions }))),
114
+ react_1.default.createElement(StatusRegion_1.default, { message: answerStatus, "data-testid": 'answer-status' })));
109
115
  }
110
116
  exports.default = CioPiaQna;
@@ -49,3 +49,8 @@
49
49
  line-height: 20px;
50
50
  color: #6b7280;
51
51
  }
52
+
53
+ .cio-product-card[role='link']:focus-visible {
54
+ outline: 2px solid #0f1324;
55
+ outline-offset: 2px;
56
+ }
@@ -11,6 +11,13 @@ function HtmlDescription({ product }) {
11
11
  return null;
12
12
  return (react_1.default.createElement("p", { className: 'cio-product-card-description', dangerouslySetInnerHTML: { __html: (0, contentTransformers_1.sanitizeHtml)(description) } }));
13
13
  }
14
+ // The card root is focusable and acts as a link, so Enter must do what a click does.
15
+ // Only for the card itself: Enter on the Add to Cart button inside it is that button's.
16
+ function handleCardKeyDown(event) {
17
+ if (event.key === 'Enter' && event.target === event.currentTarget) {
18
+ event.currentTarget.click();
19
+ }
20
+ }
14
21
  function createPriceSectionOverride(priceCurrency) {
15
22
  return function PriceSectionOverride({ product }) {
16
23
  const { price, salePrice } = product;
@@ -46,12 +53,10 @@ function buildMergedOverrides(componentOverrides, priceSectionOverride) {
46
53
  return Object.assign(Object.assign({}, componentOverrides), { item: Object.assign(Object.assign({}, componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.item), { productCard: Object.assign(Object.assign({}, (_c = componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.item) === null || _c === void 0 ? void 0 : _c.productCard), { content: Object.assign(Object.assign({}, content), defaults) }) }) });
47
54
  }
48
55
  function PiaCustomCarousel({ items, componentOverrides, callbacks, onResultClick, question, qnaResultId, translations, priceCurrency, }) {
49
- const wrapperRef = (0, react_1.useRef)(null);
50
56
  const { onAddToCart } = callbacks || {};
51
57
  const addToCartHandler = (0, react_1.useCallback)((event, product) => {
52
58
  onAddToCart === null || onAddToCart === void 0 ? void 0 : onAddToCart(product, event);
53
59
  }, [onAddToCart]);
54
- // Determine to use user-defined click handler or default behavior
55
60
  const productClickHandler = (0, react_1.useCallback)((item) => {
56
61
  const position = items.findIndex((i) => i.id === item.id);
57
62
  if (onResultClick && question) {
@@ -65,40 +70,40 @@ function PiaCustomCarousel({ items, componentOverrides, callbacks, onResultClick
65
70
  window.open(item.url, '_blank', 'noopener,noreferrer');
66
71
  }
67
72
  }, [callbacks, items, onResultClick, question, qnaResultId]);
68
- // Set up event listener for product card clicks
69
- (0, react_1.useEffect)(() => {
70
- const el = wrapperRef.current;
71
- if (!el)
72
- return undefined;
73
- const handleClick = (e) => {
74
- const { product } = e.detail;
75
- if (product) {
76
- productClickHandler(product);
77
- }
78
- };
79
- el.addEventListener(constructorio_ui_components_1.CIO_EVENTS.productCard.click, handleClick);
80
- return () => {
81
- el.removeEventListener(constructorio_ui_components_1.CIO_EVENTS.productCard.click, handleClick);
82
- };
83
- }, [productClickHandler]);
84
73
  const priceSectionOverride = (0, react_1.useMemo)(() => (priceCurrency ? createPriceSectionOverride(priceCurrency) : undefined), [priceCurrency]);
74
+ const clickHandlerProps = (0, react_1.useMemo)(() => ({
75
+ onProductClick: productClickHandler,
76
+ onAddToCart: onAddToCart ? addToCartHandler : undefined,
77
+ }), [productClickHandler, onAddToCart, addToCartHandler]);
85
78
  const mergedOverrides = (0, react_1.useMemo)(() => {
86
- var _a;
79
+ var _a, _b;
87
80
  const baseOverrides = buildMergedOverrides(componentOverrides, priceSectionOverride);
81
+ // Override priority: carousel.reactNode → item.reactNode → item.productCard.reactNode → default ProductCard.
82
+ // The casts are required because the override signatures don't declare these extra props,
83
+ // but consumers receive them as part of the render-props contract documented in CioPiaProps.
84
+ const carouselOverride = baseOverrides.reactNode;
85
+ if (typeof carouselOverride === 'function') {
86
+ return Object.assign(Object.assign({}, baseOverrides), { reactNode: (props) => carouselOverride(Object.assign(Object.assign({}, props), clickHandlerProps)) });
87
+ }
88
88
  const cardOverrides = (_a = baseOverrides.item) === null || _a === void 0 ? void 0 : _a.productCard;
89
- // The carousel never passes onAddToCart down and the card hides the button without it, so
90
- // re-render the card with the handler. A full card override owns its own layout - skip it.
91
- if (!onAddToCart || (cardOverrides === null || cardOverrides === void 0 ? void 0 : cardOverrides.reactNode)) {
92
- return baseOverrides;
89
+ const itemOverride = (_b = baseOverrides.item) === null || _b === void 0 ? void 0 : _b.reactNode;
90
+ if (typeof itemOverride === 'function') {
91
+ return Object.assign(Object.assign({}, baseOverrides), { item: Object.assign(Object.assign({}, baseOverrides.item), { reactNode: (props) => itemOverride(Object.assign(Object.assign({}, props), clickHandlerProps)) }) });
92
+ }
93
+ if (typeof (cardOverrides === null || cardOverrides === void 0 ? void 0 : cardOverrides.reactNode) === 'function') {
94
+ const originalReactNode = cardOverrides.reactNode;
95
+ return Object.assign(Object.assign({}, baseOverrides), { item: Object.assign(Object.assign({}, baseOverrides.item), { productCard: Object.assign(Object.assign({}, cardOverrides), { reactNode: (props) => originalReactNode(Object.assign(Object.assign({}, props), clickHandlerProps)) }) }) });
93
96
  }
94
- const addToCartText = (0, translate_1.translate)('Add to Cart', translations);
95
- return Object.assign(Object.assign({}, baseOverrides), { item: Object.assign(Object.assign({}, baseOverrides.item), { productCard: Object.assign(Object.assign({}, cardOverrides), { reactNode: ({ product }) => (react_1.default.createElement(constructorio_ui_components_1.ProductCard, { product: product, className: 'w-full h-full', addToCartText: addToCartText, onAddToCart: addToCartHandler, componentOverrides: cardOverrides })) }) }) });
96
- }, [componentOverrides, priceSectionOverride, onAddToCart, translations, addToCartHandler]);
97
- // If there are no items, do not render the carousel
97
+ // Default: render ProductCard with handlers directly
98
+ const addToCartText = onAddToCart ? (0, translate_1.translate)('Add to Cart', translations) : undefined;
99
+ return Object.assign(Object.assign({}, baseOverrides), { item: Object.assign(Object.assign({}, baseOverrides.item), { productCard: Object.assign(Object.assign({}, cardOverrides), { reactNode: ({ product }) => (react_1.default.createElement(constructorio_ui_components_1.ProductCard, { product: product, className: 'w-full h-full',
100
+ // Reachable by Tab. The name is the product name: a name computed from the
101
+ // card's content would also swallow the Add to Cart button's text.
102
+ role: 'link', "aria-label": product.name || undefined, tabIndex: 0, onKeyDown: handleCardKeyDown, addToCartText: addToCartText, onAddToCart: clickHandlerProps.onAddToCart, onProductClick: clickHandlerProps.onProductClick, componentOverrides: cardOverrides })) }) }) });
103
+ }, [componentOverrides, priceSectionOverride, clickHandlerProps, onAddToCart, translations]);
98
104
  if (items.length === 0) {
99
105
  return null;
100
106
  }
101
- return (react_1.default.createElement("div", { ref: wrapperRef },
102
- react_1.default.createElement(constructorio_ui_components_1.Carousel, { items: items, componentOverrides: mergedOverrides })));
107
+ return react_1.default.createElement(constructorio_ui_components_1.Carousel, { items: items, componentOverrides: mergedOverrides });
103
108
  }
104
109
  exports.default = PiaCustomCarousel;
@@ -8,7 +8,9 @@ const Disclaimer_1 = tslib_1.__importDefault(require("../CioPia/Disclaimer"));
8
8
  const ErrorBlock_1 = tslib_1.__importDefault(require("../Error/ErrorBlock"));
9
9
  const LoadingSkeleton_1 = tslib_1.__importDefault(require("../LoadingSkeleton/LoadingSkeleton"));
10
10
  const PiaCustomCarousel_1 = tslib_1.__importDefault(require("../CioPia/PiaCustomCarousel"));
11
- function ConversationHistory({ conversationHistory, isLoading, error, currentItems, showFeedback, showPreviousItems = true, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, handleFeedback, onResultClick, qnaResultId, priceCurrency, }) {
11
+ const StatusRegion_1 = tslib_1.__importStar(require("../StatusRegion/StatusRegion"));
12
+ const translate_1 = require("../../utils/translate");
13
+ function ConversationHistory({ conversationHistory, isLoading, isAnswerLoading = isLoading, error, currentItems, showFeedback, showPreviousItems = true, learnMoreUrl, disclaimerPosition = 'bottom', translations, callbacks, componentOverrides, handleFeedback, onResultClick, qnaResultId, priceCurrency, }) {
12
14
  const scrollContainerRef = (0, react_1.useRef)(null);
13
15
  (0, react_1.useEffect)(() => {
14
16
  const container = scrollContainerRef.current;
@@ -19,24 +21,27 @@ function ConversationHistory({ conversationHistory, isLoading, error, currentIte
19
21
  });
20
22
  return () => cancelAnimationFrame(frameId);
21
23
  }, [conversationHistory, isLoading]);
24
+ const lastEntry = conversationHistory[conversationHistory.length - 1];
25
+ const answerStatus = (0, StatusRegion_1.answerStatusMessage)(isAnswerLoading, !!(lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.answer), translations);
22
26
  const disclaimer = (react_1.default.createElement(Disclaimer_1.default, { learnMoreUrl: learnMoreUrl, translations: translations, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.disclaimer }));
23
27
  return (react_1.default.createElement("div", { className: 'cio-pia-conversation-history' },
24
28
  disclaimerPosition === 'top' && disclaimer,
25
- react_1.default.createElement("div", { ref: scrollContainerRef, className: 'cio-pia-conversation-entries', role: 'log', "aria-label": 'Conversation history' }, conversationHistory.map((entry, index) => {
29
+ react_1.default.createElement("div", { ref: scrollContainerRef, className: 'cio-pia-conversation-entries', role: 'log', tabIndex: 0, "aria-label": (0, translate_1.translate)('Conversation history', translations) }, conversationHistory.map((entry, index) => {
26
30
  const isLast = index === conversationHistory.length - 1;
27
31
  const previousEntryItems = showPreviousItems ? entry.items : null;
28
32
  const latestEntryItems = currentItems !== undefined ? currentItems : entry.items;
29
33
  const carouselItems = isLast ? latestEntryItems : previousEntryItems;
30
34
  return (react_1.default.createElement("div", { key: entry.id, className: 'cio-pia-conversation-entry' },
31
35
  react_1.default.createElement("div", { className: 'cio-pia-chat-question' }, entry.question),
32
- isLast && isLoading && (react_1.default.createElement("div", { className: 'cio-pia-conversation-loading', "aria-live": 'polite' },
36
+ isLast && isLoading && (react_1.default.createElement("div", { className: 'cio-pia-conversation-loading' },
33
37
  react_1.default.createElement(LoadingSkeleton_1.default, { componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.loading }))),
34
- isLast && !isLoading && error && (react_1.default.createElement(ErrorBlock_1.default, { message: error.message || 'Unexpected error' })),
38
+ isLast && !isLoading && error && (react_1.default.createElement(ErrorBlock_1.default, { key: error.message || (0, translate_1.translate)('Unexpected error', translations), message: error.message, translations: translations, announce: false })),
35
39
  entry.answer && (react_1.default.createElement("div", { className: 'cio-pia-answer-container' },
36
40
  react_1.default.createElement(Answer_1.default, { text: entry.answer, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.answer }),
37
41
  carouselItems && (react_1.default.createElement(PiaCustomCarousel_1.default, { items: carouselItems, componentOverrides: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.carousel, callbacks: callbacks, onResultClick: onResultClick, question: entry.question, qnaResultId: qnaResultId, translations: translations, priceCurrency: priceCurrency })),
38
42
  isLast && showFeedback && (react_1.default.createElement(Feedback_1.default, { translations: translations, onFeedback: handleFeedback, componentOverride: componentOverrides === null || componentOverrides === void 0 ? void 0 : componentOverrides.feedback }))))));
39
43
  })),
40
- disclaimerPosition === 'bottom' && disclaimer));
44
+ disclaimerPosition === 'bottom' && disclaimer,
45
+ react_1.default.createElement(StatusRegion_1.default, { message: answerStatus, "data-testid": 'answer-status' })));
41
46
  }
42
47
  exports.default = ConversationHistory;
@@ -2,22 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importDefault(require("react"));
5
+ const translate_1 = require("../../utils/translate");
5
6
  function WarningIcon() {
6
- return (react_1.default.createElement("svg", { width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
7
+ return (react_1.default.createElement("svg", { width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-hidden": 'true', focusable: 'false' },
7
8
  react_1.default.createElement("path", { d: 'M12.0004 2C6.4804 2 2.0004 6.48 2.0004 12C2.0004 17.52 6.4804 22 12.0004 22C17.5204 22 22.0004 17.52 22.0004 12C22.0004 6.48 17.5204 2 12.0004 2ZM13.0004 17H11.0004V15H13.0004V17ZM13.0004 13H11.0004V7H13.0004V13Z', fill: '#F1923A' })));
8
9
  }
9
10
  function RetryIcon() {
10
- return (react_1.default.createElement("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
11
+ return (react_1.default.createElement("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-hidden": 'true', focusable: 'false' },
11
12
  react_1.default.createElement("path", { d: 'M11.7633 4.23329C10.7966 3.26663 9.46992 2.66663 7.99659 2.66663C5.04992 2.66663 2.66992 5.05329 2.66992 7.99996C2.66992 10.9466 5.04992 13.3333 7.99659 13.3333C10.4833 13.3333 12.5566 11.6333 13.1499 9.33329H11.7633C11.2166 10.8866 9.73659 12 7.99659 12C5.78992 12 3.99659 10.2066 3.99659 7.99996C3.99659 5.79329 5.78992 3.99996 7.99659 3.99996C9.10326 3.99996 10.0899 4.45996 10.8099 5.18663L8.66326 7.33329H13.3299V2.66663L11.7633 4.23329Z', fill: 'white' })));
12
13
  }
13
- function ErrorBlock({ message, onRetry = undefined }) {
14
+ function ErrorBlock({ message, onRetry = undefined, translations, announce = true, }) {
15
+ const resolvedMessage = message || (0, translate_1.translate)('Unexpected error', translations);
14
16
  return (react_1.default.createElement("div", { className: 'cio-pia-error-block-container', "data-testid": 'error-block' },
15
17
  react_1.default.createElement("div", { className: 'cio-pia-error-block-warning-icon-container', "data-testid": 'error-block-warning-icon' },
16
18
  react_1.default.createElement(WarningIcon, null)),
17
19
  react_1.default.createElement("div", { className: 'cio-pia-error-block-text-container' },
18
- react_1.default.createElement("p", { className: 'cio-pia-error-block-text' }, message),
20
+ react_1.default.createElement("p", { className: 'cio-pia-error-block-text', role: announce ? 'alert' : undefined }, resolvedMessage),
19
21
  onRetry && (react_1.default.createElement("button", { type: 'button', onClick: onRetry, className: 'cio-pia-error-block-retry-button' },
20
22
  react_1.default.createElement(RetryIcon, null),
21
- "Retry")))));
23
+ (0, translate_1.translate)('Retry', translations))))));
22
24
  }
23
25
  exports.default = ErrorBlock;
@@ -6,10 +6,10 @@ const constructorio_ui_components_1 = require("@constructor-io/constructorio-ui-
6
6
  const types_1 = require("../../types");
7
7
  const translate_1 = require("../../utils/translate");
8
8
  function ThumbsUpIcon({ isSelected }) {
9
- return (react_1.default.createElement("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' }, isSelected ? (react_1.default.createElement("path", { d: 'M3.33317 6.66667H0.666504V14.6667H3.33317V6.66667ZM5.99984 14.6667C5.2665 14.6667 4.6665 14.0667 4.6665 13.3333V6.66667C4.6665 6.3 4.81317 5.96667 5.05317 5.72667L9.4465 1.33333L10.1532 2.03333C10.3332 2.21333 10.4465 2.46667 10.4465 2.74L10.4265 2.95333L9.79317 6.00001H13.9998C14.7332 6.00001 15.3332 6.60001 15.3332 7.33334V8.66668C15.3332 8.84001 15.2998 9.00001 15.2398 9.15334L13.2265 13.8533C13.0265 14.3333 12.5532 14.6667 11.9998 14.6667H5.99984Z', fill: '#4CAF50', fillOpacity: '1' })) : (react_1.default.createElement("path", { d: 'M5.99984 14.6667H11.9998C12.5532 14.6667 13.0265 14.3333 13.2265 13.8533L15.2398 9.15334C15.2998 9.00001 15.3332 8.84001 15.3332 8.66668V7.33334C15.3332 6.60001 14.7332 6.00001 13.9998 6.00001H9.79317L10.4265 2.95334L10.4465 2.74001C10.4465 2.46668 10.3332 2.21334 10.1532 2.03334L9.4465 1.33334L5.05317 5.72668C4.81317 5.96668 4.6665 6.30001 4.6665 6.66668V13.3333C4.6665 14.0667 5.2665 14.6667 5.99984 14.6667ZM5.99984 6.66668L8.89317 3.77334L7.99984 7.33334H13.9998V8.66668L11.9998 13.3333H5.99984V6.66668ZM0.666504 6.66668H3.33317V14.6667H0.666504V6.66668Z', fill: '#0F1324', fillOpacity: '0.6' }))));
9
+ return (react_1.default.createElement("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-hidden": 'true', focusable: 'false' }, isSelected ? (react_1.default.createElement("path", { d: 'M3.33317 6.66667H0.666504V14.6667H3.33317V6.66667ZM5.99984 14.6667C5.2665 14.6667 4.6665 14.0667 4.6665 13.3333V6.66667C4.6665 6.3 4.81317 5.96667 5.05317 5.72667L9.4465 1.33333L10.1532 2.03333C10.3332 2.21333 10.4465 2.46667 10.4465 2.74L10.4265 2.95333L9.79317 6.00001H13.9998C14.7332 6.00001 15.3332 6.60001 15.3332 7.33334V8.66668C15.3332 8.84001 15.2998 9.00001 15.2398 9.15334L13.2265 13.8533C13.0265 14.3333 12.5532 14.6667 11.9998 14.6667H5.99984Z', fill: '#4CAF50', fillOpacity: '1' })) : (react_1.default.createElement("path", { d: 'M5.99984 14.6667H11.9998C12.5532 14.6667 13.0265 14.3333 13.2265 13.8533L15.2398 9.15334C15.2998 9.00001 15.3332 8.84001 15.3332 8.66668V7.33334C15.3332 6.60001 14.7332 6.00001 13.9998 6.00001H9.79317L10.4265 2.95334L10.4465 2.74001C10.4465 2.46668 10.3332 2.21334 10.1532 2.03334L9.4465 1.33334L5.05317 5.72668C4.81317 5.96668 4.6665 6.30001 4.6665 6.66668V13.3333C4.6665 14.0667 5.2665 14.6667 5.99984 14.6667ZM5.99984 6.66668L8.89317 3.77334L7.99984 7.33334H13.9998V8.66668L11.9998 13.3333H5.99984V6.66668ZM0.666504 6.66668H3.33317V14.6667H0.666504V6.66668Z', fill: '#0F1324', fillOpacity: '0.6' }))));
10
10
  }
11
11
  function ThumbsDownIcon({ isSelected }) {
12
- return (react_1.default.createElement("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' }, isSelected ? (react_1.default.createElement("path", { d: 'M12.6665 9.33334H15.3332V1.33334H12.6665V9.33334ZM9.99984 1.33334C10.7332 1.33334 11.3332 1.93334 11.3332 2.66668V9.33334C11.3332 9.70001 11.1865 10.0333 10.9465 10.2733L6.55317 14.6667L5.8465 13.9667C5.6665 13.7867 5.55317 13.5333 5.55317 13.26L5.57317 13.0467L6.2065 10H1.99984C1.2665 10 0.666504 9.40001 0.666504 8.66668V7.33334C0.666504 7.16001 0.699837 7.00001 0.759837 6.84668L2.77317 2.14668C2.97317 1.66668 3.4465 1.33334 3.99984 1.33334H9.99984Z', fill: '#F44336', fillOpacity: '1' })) : (react_1.default.createElement("path", { d: 'M9.99984 1.33334H3.99984C3.4465 1.33334 2.97317 1.66668 2.77317 2.14668L0.759837 6.84668C0.699837 7.00001 0.666504 7.16001 0.666504 7.33334V8.66668C0.666504 9.40001 1.2665 10 1.99984 10H6.2065L5.57317 13.0467L5.55317 13.26C5.55317 13.5333 5.6665 13.7867 5.8465 13.9667L6.55317 14.6667L10.9465 10.2733C11.1865 10.0333 11.3332 9.70001 11.3332 9.33334V2.66668C11.3332 1.93334 10.7332 1.33334 9.99984 1.33334ZM9.99984 9.33334L7.1065 12.2267L7.99984 8.66668H1.99984V7.33334L3.99984 2.66668H9.99984V9.33334ZM12.6665 1.33334H15.3332V9.33334H12.6665V1.33334Z', fill: '#0F1324', fillOpacity: '0.6' }))));
12
+ return (react_1.default.createElement("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-hidden": 'true', focusable: 'false' }, isSelected ? (react_1.default.createElement("path", { d: 'M12.6665 9.33334H15.3332V1.33334H12.6665V9.33334ZM9.99984 1.33334C10.7332 1.33334 11.3332 1.93334 11.3332 2.66668V9.33334C11.3332 9.70001 11.1865 10.0333 10.9465 10.2733L6.55317 14.6667L5.8465 13.9667C5.6665 13.7867 5.55317 13.5333 5.55317 13.26L5.57317 13.0467L6.2065 10H1.99984C1.2665 10 0.666504 9.40001 0.666504 8.66668V7.33334C0.666504 7.16001 0.699837 7.00001 0.759837 6.84668L2.77317 2.14668C2.97317 1.66668 3.4465 1.33334 3.99984 1.33334H9.99984Z', fill: '#F44336', fillOpacity: '1' })) : (react_1.default.createElement("path", { d: 'M9.99984 1.33334H3.99984C3.4465 1.33334 2.97317 1.66668 2.77317 2.14668L0.759837 6.84668C0.699837 7.00001 0.666504 7.16001 0.666504 7.33334V8.66668C0.666504 9.40001 1.2665 10 1.99984 10H6.2065L5.57317 13.0467L5.55317 13.26C5.55317 13.5333 5.6665 13.7867 5.8465 13.9667L6.55317 14.6667L10.9465 10.2733C11.1865 10.0333 11.3332 9.70001 11.3332 9.33334V2.66668C11.3332 1.93334 10.7332 1.33334 9.99984 1.33334ZM9.99984 9.33334L7.1065 12.2267L7.99984 8.66668H1.99984V7.33334L3.99984 2.66668H9.99984V9.33334ZM12.6665 1.33334H15.3332V9.33334H12.6665V1.33334Z', fill: '#0F1324', fillOpacity: '0.6' }))));
13
13
  }
14
14
  function Feedback({ translations, onFeedback, componentOverride }) {
15
15
  const [feedback, setFeedback] = (0, react_1.useState)(null);
@@ -20,9 +20,9 @@ function Feedback({ translations, onFeedback, componentOverride }) {
20
20
  return (react_1.default.createElement(constructorio_ui_components_1.RenderPropsWrapper, { props: { translations, onFeedback }, override: componentOverride === null || componentOverride === void 0 ? void 0 : componentOverride.reactNode },
21
21
  react_1.default.createElement("div", { className: 'cio-pia-feedback-container' },
22
22
  react_1.default.createElement("p", { className: 'cio-pia-feedback-text' }, (0, translate_1.translate)('Is this answer useful?', translations)),
23
- react_1.default.createElement("button", { type: 'button', className: 'cio-pia-feedback-button', "aria-label": 'thumbs up', onClick: () => handleFeedback(types_1.FeedbackType.UP) },
23
+ react_1.default.createElement("button", { type: 'button', className: 'cio-pia-feedback-button', "aria-label": (0, translate_1.translate)('thumbs up', translations), "aria-pressed": feedback === types_1.FeedbackType.UP, onClick: () => handleFeedback(types_1.FeedbackType.UP) },
24
24
  react_1.default.createElement(ThumbsUpIcon, { isSelected: feedback === types_1.FeedbackType.UP })),
25
- react_1.default.createElement("button", { type: 'button', className: 'cio-pia-feedback-button', "aria-label": 'thumbs down', onClick: () => handleFeedback(types_1.FeedbackType.DOWN) },
25
+ react_1.default.createElement("button", { type: 'button', className: 'cio-pia-feedback-button', "aria-label": (0, translate_1.translate)('thumbs down', translations), "aria-pressed": feedback === types_1.FeedbackType.DOWN, onClick: () => handleFeedback(types_1.FeedbackType.DOWN) },
26
26
  react_1.default.createElement(ThumbsDownIcon, { isSelected: feedback === types_1.FeedbackType.DOWN })))));
27
27
  }
28
28
  exports.default = Feedback;
@@ -45,6 +45,7 @@ function Input({ value: providedValue, placeholder, disabled = false, onSubmit,
45
45
  const resolvedPlaceholder = (translations === null || translations === void 0 ? void 0 : translations[placeholderKey]) !== undefined
46
46
  ? (0, translate_1.translate)(placeholderKey, translations)
47
47
  : (placeholder !== null && placeholder !== void 0 ? placeholder : (0, translate_1.translate)(placeholderKey));
48
+ const accessibleName = resolvedPlaceholder || (0, translate_1.translate)('Your question', translations);
48
49
  return (react_1.default.createElement(constructorio_ui_components_1.RenderPropsWrapper, { props: {
49
50
  disabled,
50
51
  placeholder: resolvedPlaceholder,
@@ -55,7 +56,7 @@ function Input({ value: providedValue, placeholder, disabled = false, onSubmit,
55
56
  }, override: componentOverride === null || componentOverride === void 0 ? void 0 : componentOverride.reactNode },
56
57
  react_1.default.createElement(react_1.default.Fragment, null,
57
58
  react_1.default.createElement("div", { className: 'cio-pia-input-container' },
58
- react_1.default.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, onFocus: onFocus, placeholder: resolvedPlaceholder, disabled: disabled, className: (0, classNames_1.cx)('cio-pia-input', error && 'cio-pia-input--error', !showSendButton && 'cio-pia-input--no-send'), "aria-invalid": error ? true : undefined, "aria-describedby": error ? errorId : undefined }),
59
+ react_1.default.createElement("input", { type: 'text', value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleSubmitOnEnter, onFocus: onFocus, placeholder: resolvedPlaceholder, "aria-label": accessibleName, disabled: disabled, className: (0, classNames_1.cx)('cio-pia-input', error && 'cio-pia-input--error', !showSendButton && 'cio-pia-input--no-send'), "aria-invalid": error ? true : undefined, "aria-describedby": error ? errorId : undefined }),
59
60
  showSendButton && (react_1.default.createElement("button", { type: 'button', onClick: () => handleSubmit(value), className: 'cio-pia-send-button', disabled: disabled },
60
61
  (0, translate_1.translate)('Send', translations),
61
62
  react_1.default.createElement(icons_1.SendIcon, null)))),
@@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importDefault(require("react"));
5
5
  const constructorio_ui_components_1 = require("@constructor-io/constructorio-ui-components");
6
- const skeleton = (react_1.default.createElement("div", { className: 'cio-pia-loading-skeleton', "data-testid": 'loading-skeleton' },
6
+ // Decorative: loading is announced by the always-mounted status region.
7
+ const skeleton = (react_1.default.createElement("div", { className: 'cio-pia-loading-skeleton', "data-testid": 'loading-skeleton', "aria-hidden": 'true' },
7
8
  react_1.default.createElement("div", { className: 'skeleton-bar' }),
8
9
  react_1.default.createElement("div", { className: 'skeleton-bar' }),
9
10
  react_1.default.createElement("div", { className: 'skeleton-bar skeleton-short' })));
@@ -7,13 +7,17 @@ const translate_1 = require("../../utils/translate");
7
7
  const SuggestedQuestionsContainer_1 = tslib_1.__importDefault(require("../SuggestedQuestionsContainer/SuggestedQuestionsContainer"));
8
8
  const OVERFLOW_HIDDEN_CLASS = 'cio-pia-modal-open';
9
9
  function CloseIcon() {
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' },
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', "aria-hidden": 'true', focusable: 'false' },
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
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
+ const triggerRef = (0, react_1.useRef)(null);
16
17
  const openModal = (0, react_1.useCallback)(() => {
18
+ const active = document.activeElement;
19
+ const isRealTrigger = !!active && active !== document.body && active !== document.documentElement;
20
+ triggerRef.current = isRealTrigger ? active : null;
17
21
  setIsOpen(true);
18
22
  }, []);
19
23
  const closeModal = (0, react_1.useCallback)(() => {
@@ -28,14 +32,28 @@ function PiaModal({ initialQuestions, handleSubmitQuestion, handleQuestionClick,
28
32
  dialog.showModal();
29
33
  document.body.classList.add(OVERFLOW_HIDDEN_CLASS);
30
34
  }
31
- else if (dialog.open) {
32
- dialog.close();
35
+ else {
36
+ if (dialog.open)
37
+ dialog.close();
33
38
  document.body.classList.remove(OVERFLOW_HIDDEN_CLASS);
34
39
  }
35
40
  return () => {
36
41
  document.body.classList.remove(OVERFLOW_HIDDEN_CLASS);
37
42
  };
38
43
  }, [isOpen]);
44
+ // Restore focus to the trigger. Re-runs on `isLoading`: the input trigger is
45
+ // disabled while a request is in flight and `focus()` would no-op.
46
+ (0, react_1.useEffect)(() => {
47
+ if (isOpen)
48
+ return;
49
+ const trigger = triggerRef.current;
50
+ if (!trigger || !trigger.isConnected)
51
+ return;
52
+ if (trigger.disabled)
53
+ return;
54
+ trigger.focus();
55
+ triggerRef.current = null;
56
+ }, [isOpen, isLoading]);
39
57
  (0, react_1.useEffect)(() => {
40
58
  const dialog = dialogRef.current;
41
59
  if (!dialog)
@@ -72,7 +90,7 @@ function PiaModal({ initialQuestions, handleSubmitQuestion, handleQuestionClick,
72
90
  react_1.default.createElement("div", { className: 'cio-pia-modal-content' },
73
91
  react_1.default.createElement("div", { className: 'cio-pia-modal-header' },
74
92
  react_1.default.createElement("p", { className: 'cio-pia-title', id: 'cio-pia-modal-title' }, (0, translate_1.translate)('Ask about this product', translations)),
75
- react_1.default.createElement("button", { type: 'button', className: 'cio-pia-modal-close-button', "aria-label": 'Close', onClick: closeModal },
93
+ react_1.default.createElement("button", { type: 'button', className: 'cio-pia-modal-close-button', "aria-label": (0, translate_1.translate)('Close', translations), onClick: closeModal },
76
94
  react_1.default.createElement(CloseIcon, null))),
77
95
  react_1.default.createElement("div", { className: 'cio-pia-modal-body' }, children)))));
78
96
  }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.answerStatusMessage = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const translate_1 = require("../../utils/translate");
7
+ // Inline so it stays hidden for consumers who do not load the stylesheet.
8
+ const SR_ONLY_STYLE = {
9
+ position: 'absolute',
10
+ width: 1,
11
+ height: 1,
12
+ padding: 0,
13
+ margin: -1,
14
+ overflow: 'hidden',
15
+ clip: 'rect(0, 0, 0, 0)',
16
+ whiteSpace: 'nowrap',
17
+ border: 0,
18
+ };
19
+ /**
20
+ * Visually hidden `role='status'`. Keep it mounted and change only `message`:
21
+ * a live region created together with its text is announced inconsistently.
22
+ */
23
+ function StatusRegion({ message, 'data-testid': testId }) {
24
+ return (react_1.default.createElement("div", { className: 'cio-pia-sr-only', style: SR_ONLY_STYLE, role: 'status', "data-testid": testId }, message));
25
+ }
26
+ exports.default = StatusRegion;
27
+ function answerStatusMessage(isLoading, hasAnswer, translations) {
28
+ if (isLoading)
29
+ return (0, translate_1.translate)('Loading answer', translations);
30
+ if (hasAnswer)
31
+ return (0, translate_1.translate)('Answer ready', translations);
32
+ return '';
33
+ }
34
+ exports.answerStatusMessage = answerStatusMessage;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importDefault(require("react"));
5
5
  function SuggestedQuestionsSkeleton() {
6
- return (react_1.default.createElement("div", { className: 'cio-pia-suggested-questions-container', "data-testid": 'suggested-questions-skeleton', "aria-busy": 'true', "aria-label": 'Loading suggestions' },
6
+ return (react_1.default.createElement("div", { className: 'cio-pia-suggested-questions-container', "data-testid": 'suggested-questions-skeleton', "aria-hidden": 'true' },
7
7
  react_1.default.createElement("div", { className: 'cio-pia-suggested-question-skeleton' }),
8
8
  react_1.default.createElement("div", { className: 'cio-pia-suggested-question-skeleton' }),
9
9
  react_1.default.createElement("div", { className: 'cio-pia-suggested-question-skeleton' })));
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importDefault(require("react"));
5
5
  function QuestionIcon() {
6
- return (react_1.default.createElement("svg", { "aria-hidden": 'true', width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
6
+ return (react_1.default.createElement("svg", { "aria-hidden": 'true', focusable: 'false', width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
7
7
  react_1.default.createElement("path", { d: 'M8.00004 1.33331C4.32004 1.33331 1.33337 4.31998 1.33337 7.99998C1.33337 11.68 4.32004 14.6666 8.00004 14.6666C11.68 14.6666 14.6667 11.68 14.6667 7.99998C14.6667 4.31998 11.68 1.33331 8.00004 1.33331ZM8.66671 12.6666H7.33337V11.3333H8.66671V12.6666ZM10.0467 7.49998L9.44671 8.11331C8.96671 8.59998 8.66671 8.99998 8.66671 9.99998H7.33337V9.66665C7.33337 8.93331 7.63337 8.26665 8.11337 7.77998L8.94004 6.93998C9.18671 6.69998 9.33337 6.36665 9.33337 5.99998C9.33337 5.26665 8.73337 4.66665 8.00004 4.66665C7.26671 4.66665 6.66671 5.26665 6.66671 5.99998H5.33337C5.33337 4.52665 6.52671 3.33331 8.00004 3.33331C9.47337 3.33331 10.6667 4.52665 10.6667 5.99998C10.6667 6.58665 10.4267 7.11998 10.0467 7.49998Z', fill: '#0F1324', fillOpacity: '0.6' })));
8
8
  }
9
9
  exports.default = QuestionIcon;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importDefault(require("react"));
5
5
  function SendIcon() {
6
- return (react_1.default.createElement("svg", { "aria-hidden": 'true', width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
6
+ return (react_1.default.createElement("svg", { "aria-hidden": 'true', focusable: 'false', width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
7
7
  react_1.default.createElement("path", { 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' })));
8
8
  }
9
9
  exports.default = SendIcon;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importDefault(require("react"));
5
5
  function SparklesIcon() {
6
- return (react_1.default.createElement("svg", { "aria-hidden": 'true', width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
6
+ return (react_1.default.createElement("svg", { "aria-hidden": 'true', focusable: 'false', width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' },
7
7
  react_1.default.createElement("path", { d: 'M12.6667 6.0013L13.5001 4.16797L15.3334 3.33464L13.5001 2.5013L12.6667 0.667969L11.8334 2.5013L10.0001 3.33464L11.8334 4.16797L12.6667 6.0013Z', fill: '#1C1917' }),
8
8
  react_1.default.createElement("path", { d: 'M12.6667 10.0013L11.8334 11.8346L10.0001 12.668L11.8334 13.5013L12.6667 15.3346L13.5001 13.5013L15.3334 12.668L13.5001 11.8346L12.6667 10.0013Z', fill: '#1C1917' }),
9
9
  react_1.default.createElement("path", { d: 'M7.66675 6.33464L6.00008 2.66797L4.33341 6.33464L0.666748 8.0013L4.33341 9.66797L6.00008 13.3346L7.66675 9.66797L11.3334 8.0013L7.66675 6.33464ZM6.66008 8.6613L6.00008 10.1146L5.34008 8.6613L3.88675 8.0013L5.34008 7.3413L6.00008 5.88797L6.66008 7.3413L8.11341 8.0013L6.66008 8.6613Z', fill: '#1C1917' })));
@@ -1,18 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
3
  const react_1 = require("react");
5
4
  const transformers_1 = require("../utils/transformers");
6
- const fetchAnswerResults = ({ client, itemId, question, variationId, threadId, parameters, }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
7
- const response = yield client.agent.getAnswerResults({
8
- itemId,
9
- variationId,
10
- threadId,
11
- question,
12
- parameters,
13
- });
14
- return response;
15
- });
16
5
  function useAnswerResults({ itemId, variationId, threadId, cioClient, parameters, formatImageUrl, }) {
17
6
  const [answerResults, setAnswerResults] = (0, react_1.useState)(null);
18
7
  const [isLoading, setIsLoading] = (0, react_1.useState)(false);
@@ -24,9 +13,10 @@ function useAnswerResults({ itemId, variationId, threadId, cioClient, parameters
24
13
  setIsLoading(true);
25
14
  setError(null);
26
15
  setAnswerResults(null);
27
- fetchAnswerResults({ client: cioClient, itemId, question, variationId, threadId, parameters })
28
- .then((fetchedAnswerResults) => {
29
- setAnswerResults(fetchedAnswerResults);
16
+ cioClient.agent.pia
17
+ .getAnswerResults(itemId, question, Object.assign({ threadId, variationId }, parameters))
18
+ .then((response) => {
19
+ setAnswerResults(response);
30
20
  setError(null);
31
21
  })
32
22
  .catch((err) => {
@@ -4,27 +4,65 @@ const tslib_1 = require("tslib");
4
4
  const useAnswerResults_1 = tslib_1.__importDefault(require("./useAnswerResults"));
5
5
  const usePiaClient_1 = tslib_1.__importDefault(require("./usePiaClient"));
6
6
  const useSuggestedQuestions_1 = tslib_1.__importDefault(require("./useSuggestedQuestions"));
7
+ // TODO: remove SUPPORTED_DEPRECATED_PARAMS and mapDeprecatedParameters once the
8
+ // deprecated `parameters` prop is removed from CioPiaProps.
9
+ const SUPPORTED_DEPRECATED_PARAMS = {
10
+ guard: { camelKey: 'guard', isObject: false },
11
+ num_results: { camelKey: 'numResults', isObject: false },
12
+ numResults: { camelKey: 'numResults', isObject: false },
13
+ pre_filter_expression: { camelKey: 'preFilterExpression', isObject: true },
14
+ preFilterExpression: { camelKey: 'preFilterExpression', isObject: true },
15
+ fmt_options: { camelKey: 'fmtOptions', isObject: true },
16
+ fmtOptions: { camelKey: 'fmtOptions', isObject: true },
17
+ };
18
+ function mapDeprecatedParameters(params) {
19
+ if (!params)
20
+ return undefined;
21
+ const mapped = {};
22
+ let hasEntries = false;
23
+ for (const [key, value] of Object.entries(params)) {
24
+ const config = SUPPORTED_DEPRECATED_PARAMS[key];
25
+ if (!config)
26
+ continue;
27
+ hasEntries = true;
28
+ if (config.isObject && typeof value === 'string') {
29
+ try {
30
+ mapped[config.camelKey] = JSON.parse(value);
31
+ }
32
+ catch (_a) {
33
+ mapped[config.camelKey] = value;
34
+ }
35
+ }
36
+ else {
37
+ mapped[config.camelKey] = value;
38
+ }
39
+ }
40
+ return hasEntries ? mapped : undefined;
41
+ }
7
42
  function useCioPia(props) {
8
- const { apiKey, itemId, variationId, threadId: providedThreadId, cioClient: providedClient, suggestedQuestionsParameters, parameters, formatImageUrl, } = props;
43
+ const { apiKey, itemId, variationId, threadId: providedThreadId, cioClient: providedClient, suggestedQuestionsParameters, answerParameters, parameters, formatImageUrl, } = props;
9
44
  const { cioClient: client, threadId } = (0, usePiaClient_1.default)({
10
45
  apiKey,
11
46
  threadId: providedThreadId,
12
47
  cioClient: providedClient,
13
48
  });
49
+ const mappedDeprecated = mapDeprecatedParameters(parameters);
50
+ const mergedSuggestedParams = mappedDeprecated || suggestedQuestionsParameters
51
+ ? Object.assign(Object.assign({}, mappedDeprecated), suggestedQuestionsParameters) : undefined;
52
+ const mergedAnswerParams = mappedDeprecated || answerParameters ? Object.assign(Object.assign({}, mappedDeprecated), answerParameters) : undefined;
14
53
  const suggestedQuestions = (0, useSuggestedQuestions_1.default)({
15
54
  itemId,
16
55
  variationId,
17
56
  threadId,
18
57
  cioClient: client,
19
- parameters: suggestedQuestionsParameters,
20
- requestParameters: parameters,
58
+ parameters: mergedSuggestedParams,
21
59
  });
22
60
  const answers = (0, useAnswerResults_1.default)({
23
61
  itemId,
24
62
  variationId,
25
63
  threadId,
26
64
  cioClient: client,
27
- parameters,
65
+ parameters: mergedAnswerParams,
28
66
  formatImageUrl,
29
67
  });
30
68
  return {