@athoscommerce/snap-preact 1.13.3-beta.168 → 1.13.3-beta.191

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 (126) hide show
  1. package/dist/cjs/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.js +3 -1
  2. package/dist/cjs/components/src/components/Molecules/ChatMessageText/ChatMessageText.js +2 -1
  3. package/dist/cjs/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.js +4 -0
  4. package/dist/cjs/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.js +1 -0
  5. package/dist/cjs/components/src/components/Molecules/ChatQuickview/ChatQuickview.js +514 -0
  6. package/dist/cjs/components/src/components/Molecules/{ChatProductQueryMessage → ChatQuickview}/index.js +1 -1
  7. package/dist/cjs/components/src/components/Molecules/ChatResultsDisplay/ChatResultsDisplay.js +2 -2
  8. package/dist/cjs/components/src/components/Molecules/Slideshow/Slideshow.js +47 -20
  9. package/dist/cjs/components/src/components/Organisms/Chat/Chat.js +12 -5
  10. package/dist/cjs/components/src/components/Organisms/Chat/Chat.lang.js +5 -0
  11. package/dist/cjs/components/src/components/Organisms/Chat/components/ChatAttachments.js +5 -4
  12. package/dist/cjs/components/src/components/Organisms/Chat/components/ChatComposer.js +3 -3
  13. package/dist/cjs/components/src/components/Organisms/Chat/components/ChatSideChat.js +3 -3
  14. package/dist/cjs/components/src/components/Organisms/Chat/components/chatAccentTheme.js +22 -20
  15. package/dist/cjs/components/src/components/Organisms/QuickviewLayout/QuickviewLayout.js +44 -11
  16. package/dist/cjs/components/src/index.js +1 -1
  17. package/dist/cjs/components/src/providers/themeComponents.js +1 -1
  18. package/dist/cjs/src/Snap.js +13 -1
  19. package/dist/cjs/src/Templates/Stores/LibraryStore.js +2 -2
  20. package/dist/cjs/src/Templates/Stores/library/languages/ar.js +45 -34
  21. package/dist/cjs/src/Templates/Stores/library/languages/de.js +45 -34
  22. package/dist/cjs/src/Templates/Stores/library/languages/es.js +45 -34
  23. package/dist/cjs/src/Templates/Stores/library/languages/fr.js +45 -34
  24. package/dist/cjs/src/Templates/Stores/library/languages/hi.js +45 -34
  25. package/dist/cjs/src/Templates/Stores/library/languages/it.js +45 -34
  26. package/dist/cjs/src/Templates/Stores/library/languages/ja.js +45 -34
  27. package/dist/cjs/src/Templates/Stores/library/languages/ko.js +45 -34
  28. package/dist/cjs/src/Templates/Stores/library/languages/nl.js +45 -34
  29. package/dist/cjs/src/Templates/Stores/library/languages/pt.js +45 -34
  30. package/dist/cjs/src/Templates/Stores/library/languages/ru.js +45 -34
  31. package/dist/cjs/src/Templates/Stores/library/languages/tr.js +45 -34
  32. package/dist/cjs/src/Templates/Stores/library/languages/vi.js +45 -34
  33. package/dist/cjs/src/Templates/Stores/library/languages/zh.js +45 -34
  34. package/dist/cjs/src/create/createChatController.js +1 -0
  35. package/dist/esm/components/src/components/Atoms/Button/Button.d.ts +1 -1
  36. package/dist/esm/components/src/components/Atoms/Button/Button.d.ts.map +1 -1
  37. package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.d.ts +12 -5
  38. package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.d.ts.map +1 -1
  39. package/dist/esm/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.d.ts +13 -2
  40. package/dist/esm/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.d.ts.map +1 -1
  41. package/dist/esm/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.js +3 -1
  42. package/dist/esm/components/src/components/Molecules/ChatMessageText/ChatMessageText.d.ts.map +1 -1
  43. package/dist/esm/components/src/components/Molecules/ChatMessageText/ChatMessageText.js +2 -1
  44. package/dist/esm/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.d.ts +17 -3
  45. package/dist/esm/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.d.ts.map +1 -1
  46. package/dist/esm/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.js +4 -0
  47. package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.d.ts +7 -1
  48. package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.d.ts.map +1 -1
  49. package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.js +1 -0
  50. package/dist/esm/components/src/components/Molecules/ChatQuickview/ChatQuickview.d.ts +30 -0
  51. package/dist/esm/components/src/components/Molecules/ChatQuickview/ChatQuickview.d.ts.map +1 -0
  52. package/dist/esm/components/src/components/Molecules/ChatQuickview/ChatQuickview.js +508 -0
  53. package/dist/esm/components/src/components/Molecules/ChatQuickview/index.d.ts +2 -0
  54. package/dist/esm/components/src/components/Molecules/ChatQuickview/index.d.ts.map +1 -0
  55. package/dist/esm/components/src/components/Molecules/ChatQuickview/index.js +1 -0
  56. package/dist/esm/components/src/components/Molecules/ChatResultsDisplay/ChatResultsDisplay.js +2 -2
  57. package/dist/esm/components/src/components/Molecules/Slideshow/Slideshow.d.ts.map +1 -1
  58. package/dist/esm/components/src/components/Molecules/Slideshow/Slideshow.js +47 -20
  59. package/dist/esm/components/src/components/Organisms/Chat/Chat.d.ts.map +1 -1
  60. package/dist/esm/components/src/components/Organisms/Chat/Chat.js +12 -5
  61. package/dist/esm/components/src/components/Organisms/Chat/Chat.lang.d.ts +3 -0
  62. package/dist/esm/components/src/components/Organisms/Chat/Chat.lang.d.ts.map +1 -1
  63. package/dist/esm/components/src/components/Organisms/Chat/Chat.lang.js +5 -0
  64. package/dist/esm/components/src/components/Organisms/Chat/components/ChatAttachments.d.ts.map +1 -1
  65. package/dist/esm/components/src/components/Organisms/Chat/components/ChatAttachments.js +5 -4
  66. package/dist/esm/components/src/components/Organisms/Chat/components/ChatComposer.d.ts.map +1 -1
  67. package/dist/esm/components/src/components/Organisms/Chat/components/ChatComposer.js +3 -3
  68. package/dist/esm/components/src/components/Organisms/Chat/components/ChatSideChat.d.ts.map +1 -1
  69. package/dist/esm/components/src/components/Organisms/Chat/components/ChatSideChat.js +3 -3
  70. package/dist/esm/components/src/components/Organisms/Chat/components/chatAccentTheme.d.ts +1 -1
  71. package/dist/esm/components/src/components/Organisms/Chat/components/chatAccentTheme.d.ts.map +1 -1
  72. package/dist/esm/components/src/components/Organisms/Chat/components/chatAccentTheme.js +22 -20
  73. package/dist/esm/components/src/components/Organisms/QuickviewLayout/QuickviewLayout.d.ts +5 -1
  74. package/dist/esm/components/src/components/Organisms/QuickviewLayout/QuickviewLayout.d.ts.map +1 -1
  75. package/dist/esm/components/src/components/Organisms/QuickviewLayout/QuickviewLayout.js +44 -11
  76. package/dist/esm/components/src/index.d.ts +1 -1
  77. package/dist/esm/components/src/index.d.ts.map +1 -1
  78. package/dist/esm/components/src/index.js +1 -1
  79. package/dist/esm/components/src/providers/langComponents.d.ts +2 -2
  80. package/dist/esm/components/src/providers/langComponents.d.ts.map +1 -1
  81. package/dist/esm/components/src/providers/themeComponents.d.ts +7 -7
  82. package/dist/esm/components/src/providers/themeComponents.d.ts.map +1 -1
  83. package/dist/esm/components/src/providers/themeComponents.js +1 -1
  84. package/dist/esm/src/Snap.d.ts +1 -0
  85. package/dist/esm/src/Snap.d.ts.map +1 -1
  86. package/dist/esm/src/Snap.js +13 -1
  87. package/dist/esm/src/Templates/Stores/LibraryStore.d.ts +2 -2
  88. package/dist/esm/src/Templates/Stores/LibraryStore.d.ts.map +1 -1
  89. package/dist/esm/src/Templates/Stores/LibraryStore.js +2 -2
  90. package/dist/esm/src/Templates/Stores/library/languages/ar.d.ts.map +1 -1
  91. package/dist/esm/src/Templates/Stores/library/languages/ar.js +45 -34
  92. package/dist/esm/src/Templates/Stores/library/languages/de.d.ts.map +1 -1
  93. package/dist/esm/src/Templates/Stores/library/languages/de.js +45 -34
  94. package/dist/esm/src/Templates/Stores/library/languages/es.d.ts.map +1 -1
  95. package/dist/esm/src/Templates/Stores/library/languages/es.js +45 -34
  96. package/dist/esm/src/Templates/Stores/library/languages/fr.d.ts.map +1 -1
  97. package/dist/esm/src/Templates/Stores/library/languages/fr.js +45 -34
  98. package/dist/esm/src/Templates/Stores/library/languages/hi.d.ts.map +1 -1
  99. package/dist/esm/src/Templates/Stores/library/languages/hi.js +45 -34
  100. package/dist/esm/src/Templates/Stores/library/languages/it.d.ts.map +1 -1
  101. package/dist/esm/src/Templates/Stores/library/languages/it.js +45 -34
  102. package/dist/esm/src/Templates/Stores/library/languages/ja.d.ts.map +1 -1
  103. package/dist/esm/src/Templates/Stores/library/languages/ja.js +45 -34
  104. package/dist/esm/src/Templates/Stores/library/languages/ko.d.ts.map +1 -1
  105. package/dist/esm/src/Templates/Stores/library/languages/ko.js +45 -34
  106. package/dist/esm/src/Templates/Stores/library/languages/nl.d.ts.map +1 -1
  107. package/dist/esm/src/Templates/Stores/library/languages/nl.js +45 -34
  108. package/dist/esm/src/Templates/Stores/library/languages/pt.d.ts.map +1 -1
  109. package/dist/esm/src/Templates/Stores/library/languages/pt.js +45 -34
  110. package/dist/esm/src/Templates/Stores/library/languages/ru.d.ts.map +1 -1
  111. package/dist/esm/src/Templates/Stores/library/languages/ru.js +45 -34
  112. package/dist/esm/src/Templates/Stores/library/languages/tr.d.ts.map +1 -1
  113. package/dist/esm/src/Templates/Stores/library/languages/tr.js +45 -34
  114. package/dist/esm/src/Templates/Stores/library/languages/vi.d.ts.map +1 -1
  115. package/dist/esm/src/Templates/Stores/library/languages/vi.js +45 -34
  116. package/dist/esm/src/Templates/Stores/library/languages/zh.d.ts.map +1 -1
  117. package/dist/esm/src/Templates/Stores/library/languages/zh.js +45 -34
  118. package/dist/esm/src/create/createChatController.js +1 -0
  119. package/package.json +12 -12
  120. package/dist/cjs/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.js +0 -577
  121. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.d.ts +0 -38
  122. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.d.ts.map +0 -1
  123. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.js +0 -571
  124. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/index.d.ts +0 -2
  125. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/index.d.ts.map +0 -1
  126. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/index.js +0 -1
@@ -30,6 +30,10 @@ const defaultStyles = ({ theme, slidesToShow = 1, slideWidth, gap = 16, overlayN
30
30
  display: 'flex',
31
31
  width: `100%`,
32
32
  transition: 'transform 0.3s ease-in-out',
33
+ // keep the track on its own compositor layer at all times; otherwise Chrome promotes it
34
+ // when a transform transition starts and demotes it when it ends, re-rasterizing the
35
+ // (scaled) slide content each time, which reads as every image flickering
36
+ willChange: 'transform',
33
37
  // Disable transition during dragging
34
38
  '&.ss__slideshow__track--dragging': {
35
39
  transition: 'none',
@@ -271,6 +275,8 @@ exports.Slideshow = (0, mobx_react_lite_1.observer)((properties) => {
271
275
  return () => observer.disconnect();
272
276
  }, []);
273
277
  // Touch/Drag state
278
+ // drag positions live in refs so the document-level mousemove/mouseup listeners
279
+ // (registered once per drag) always read current values instead of stale state
274
280
  const [isDragging, setIsDragging] = (0, hooks_1.useState)(false);
275
281
  // mirrors `isDragging` state - the state drives renders (the dragging class, the transform,
276
282
  // the autoplay effect), but the drag handlers below run through refs and can fire before
@@ -430,8 +436,17 @@ exports.Slideshow = (0, mobx_react_lite_1.observer)((properties) => {
430
436
  return;
431
437
  const diff = currentXRef.current - startXRef.current;
432
438
  const threshold = getNavigationThreshold();
439
+ const slideWidthPx = (trackRef.current?.parentElement?.offsetWidth || 0) / visibleSlides;
433
440
  if (Math.abs(diff) > threshold) {
434
- if (diff > 0 && (loop || currentIndex > 0)) {
441
+ const slidesDragged = slideWidthPx > 0 ? Math.round(Math.abs(diff) / slideWidthPx) : 0;
442
+ if (slidesDragged > slidesToMove) {
443
+ // long drags land on the slide group they were dragged to instead of snapping back
444
+ setCurrentIndex((prevIndex) => {
445
+ const newIndex = diff > 0 ? prevIndex - slidesDragged : prevIndex + slidesDragged;
446
+ return Math.max(0, Math.min(maxIndex, newIndex));
447
+ });
448
+ }
449
+ else if (diff > 0 && (loop || currentIndex > 0)) {
435
450
  // Dragged right - go to previous
436
451
  goToPrevious();
437
452
  }
@@ -516,6 +531,16 @@ exports.Slideshow = (0, mobx_react_lite_1.observer)((properties) => {
516
531
  }, autoPlayInterval);
517
532
  }
518
533
  };
534
+ // The browser fires a click after a drag's mouseup/touchend. Catch it in the capture phase on
535
+ // the container so it never reaches slide content that carries its own onClick (e.g. product
536
+ // cards that open a quickview) — those handlers can't know a drag just happened.
537
+ const handleContainerClickCapture = (event) => {
538
+ if (!hasDraggedRef.current)
539
+ return;
540
+ hasDraggedRef.current = false;
541
+ event.stopPropagation();
542
+ event.preventDefault();
543
+ };
519
544
  // Handle image click
520
545
  const handleSlideClick = (slide, index) => {
521
546
  if (slide.onClick && !isDragging && !hasDraggedRef.current) {
@@ -662,27 +687,29 @@ exports.Slideshow = (0, mobx_react_lite_1.observer)((properties) => {
662
687
  }, { activeBreakpoint: globalTheme?.activeBreakpoint });
663
688
  return ((0, jsx_runtime_1.jsx)(providers_1.CacheProvider, { children: (0, jsx_runtime_1.jsxs)("div", { ...styling, className: (0, classnames_1.default)('ss__slideshow', className), ref: slideshowRef, role: "region", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-roledescription": "slideshow", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave,
664
689
  // @ts-ignore - ignore
665
- onKeyDown: handleKeyDown, tabIndex: 0, children: [(0, jsx_runtime_1.jsx)("div", { className: "ss__slideshow__sr-only", ...mergedLang.srInstructions.all }), (0, jsx_runtime_1.jsx)("div", { className: "ss__slideshow__container", children: (0, jsx_runtime_1.jsx)("div", { ref: trackRef, className: (0, classnames_1.default)('ss__slideshow__track', {
690
+ onKeyDown: handleKeyDown, tabIndex: 0, children: [(0, jsx_runtime_1.jsx)("div", { className: "ss__slideshow__sr-only", ...mergedLang.srInstructions.all }), (0, jsx_runtime_1.jsx)("div", { className: "ss__slideshow__container",
691
+ // @ts-ignore - capture-phase click
692
+ onClickCapture: touchDragging ? handleContainerClickCapture : undefined,
693
+ // Touch events
694
+ // @ts-ignore - touch events
695
+ onTouchStart: touchDragging ? (event) => handleDragStart(event.touches[0].clientX) : undefined,
696
+ // @ts-ignore - touch events
697
+ onTouchMove: touchDragging
698
+ ? (event) => {
699
+ if (isDraggingRef.current) {
700
+ event.preventDefault(); // Prevent scrolling while dragging
701
+ }
702
+ const touch = event.touches[0];
703
+ handleDragMove(touch.clientX);
704
+ }
705
+ : undefined, onTouchEnd: touchDragging ? handleDragEnd : undefined,
706
+ // mouse events for desktop dragging
707
+ // move/up are bound on document in handleMouseDown so the drag keeps tracking outside the container
708
+ // @ts-ignore - mouse events
709
+ onMouseDown: touchDragging ? handleMouseDown : undefined, children: (0, jsx_runtime_1.jsx)("div", { ref: trackRef, className: (0, classnames_1.default)('ss__slideshow__track', {
666
710
  'ss__slideshow__track--dragging': isDragging,
667
711
  'ss__slideshow__track--centered': centerInsufficientSlides && totalSlides <= computedSlidesToShow,
668
- }), style: { transform: `translateX(${translateX}${translateUnit})` }, role: "group", "aria-label": `Slide group ${currentIndex} of ${totalDots}`,
669
- // Touch events
670
- // @ts-ignore - touch events
671
- onTouchStart: touchDragging ? (event) => handleDragStart(event.touches[0].clientX) : undefined,
672
- // @ts-ignore - touch events
673
- onTouchMove: touchDragging
674
- ? (event) => {
675
- if (isDraggingRef.current) {
676
- event.preventDefault(); // Prevent scrolling while dragging
677
- }
678
- const touch = event.touches[0];
679
- handleDragMove(touch.clientX);
680
- }
681
- : undefined, onTouchEnd: touchDragging ? handleDragEnd : undefined,
682
- // mouse events for desktop dragging
683
- // move/up are bound on document in handleMouseDown so the drag keeps tracking outside the track
684
- // @ts-ignore - mouse events
685
- onMouseDown: touchDragging ? handleMouseDown : undefined, children: normalizedSlides.map((slide, index) => {
712
+ }), style: { transform: `translateX(${translateX}${translateUnit})` }, role: "group", "aria-label": `Slide group ${currentIndex} of ${totalDots}`, children: normalizedSlides.map((slide, index) => {
686
713
  const isVisible = index >= currentIndex && index < currentIndex + computedSlidesToShow;
687
714
  const hasClickHandler = !!slide.onClick;
688
715
  const hasContent = !!slide.content;
@@ -399,7 +399,6 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)((properties) => {
399
399
  position: 'right',
400
400
  hideMessageTypeIndicatorText: false,
401
401
  buttonBelowMessage: false,
402
- poweredByText: 'Powered by Athos Commerce.',
403
402
  };
404
403
  let props = (0, utilities_1.mergeProps)('chat', globalTheme, defaultProps, properties);
405
404
  const { overrideElement, shouldRenderDefault } = (0, hooks_2.useCustomComponentOverride)('chat', props);
@@ -501,7 +500,13 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)((properties) => {
501
500
  const sideChatTypes = isMobile
502
501
  ? ['inspirationResult', ...(isFirstMobileComparison ? ['productComparison'] : []), ...(mobileProductInfoOpen ? ['productQuery'] : [])]
503
502
  : ['inspirationResult', 'productComparison', 'productQuery'];
504
- const shouldShowSideChat = activeMessage && sideChatTypes.includes(activeMessage?.messageType) && store.currentChat?.dismissedSideChatMessageId !== activeMessage.id;
503
+ // productQuery panels are additionally driven by the chat quickview store — the controller's
504
+ // `show()` opening the store is what opens the window, and `close()` is what dismisses it
505
+ const quickviewOpen = Boolean(controller.quickviewManager?.store.isOpen);
506
+ const shouldShowSideChat = activeMessage &&
507
+ sideChatTypes.includes(activeMessage?.messageType) &&
508
+ store.currentChat?.dismissedSideChatMessageId !== activeMessage.id &&
509
+ (activeMessage.messageType !== 'productQuery' || quickviewOpen);
505
510
  const hasSideChat = !!shouldShowSideChat;
506
511
  // Lock body scrolling (wheel + touch) to the chat while it is open. Mobile only —
507
512
  // on desktop the chat is a side panel and the page behind it stays scrollable.
@@ -514,7 +519,8 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)((properties) => {
514
519
  if (e.key !== 'Escape')
515
520
  return;
516
521
  if (store.currentChat?.activeMessage && shouldShowSideChat) {
517
- store.currentChat?.dismissSideChat();
522
+ // dismiss through the controller so the product quickview closes with the window
523
+ controller.dismissSideChat();
518
524
  }
519
525
  else {
520
526
  controller.handlers.button.click();
@@ -547,7 +553,8 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)((properties) => {
547
553
  item.requestType !== 'productComparison');
548
554
  productAttachmentsToRemove.forEach((item) => store.currentChat?.attachments.remove(item.id));
549
555
  setMobileProductInfoOpen(false);
550
- store.currentChat?.dismissSideChat();
556
+ // dismiss through the controller so the product quickview closes with the window
557
+ controller.dismissSideChat();
551
558
  };
552
559
  const requestType = store.currentChat?.requestType;
553
560
  const loadingVerbLangKey = requestType ? LOADING_VERB_LANG_KEYS[requestType] : undefined;
@@ -609,7 +616,7 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)((properties) => {
609
616
  // On mobile, interacting with the primary chat (header or anywhere within)
610
617
  // dismisses the secondary panel. Capture phase so it fires even when an
611
618
  // inner control stops propagation.
612
- onClickCapture: isMobile && shouldShowSideChat ? () => dismissSideChat() : undefined, children: [(0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__header', children: [(0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__header__title", children: [logo ? (0, jsx_runtime_1.jsx)(Image_1.Image, { className: "ss__chat__header__title__logo", src: logo, alt: title || 'Chat logo' }) : null, (0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__header__title__text", children: [title ? (0, jsx_runtime_1.jsx)("div", { className: "ss__chat__header__title__text__primary", children: title }) : null, subtitle ? (0, jsx_runtime_1.jsx)("div", { className: "ss__chat__header__title__text__secondary", children: subtitle }) : null] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__header__buttons", children: [(0, jsx_runtime_1.jsx)(Button_1.Button, { className: "ss__chat__header__button--new", "aria-label": (0, Chat_lang_1.langAttrOf)(lang.newChatButton, 'aria-label'), icon: { icon: controller.store.initChatLoading ? 'spinner' : 'plus-rounded', title: (0, Chat_lang_1.langAttrOf)(lang.newChatButton, 'title') }, onClick: () => controller.store.createChat() }), store.chats.length > 1 && (0, jsx_runtime_1.jsx)(ChatHistory_1.ChatHistory, { ...subProps.history, controller: controller }), (0, jsx_runtime_1.jsx)(Button_1.Button, { className: "ss__chat__header__button--close", "aria-label": (0, Chat_lang_1.langAttrOf)(lang.closeChatButton, 'aria-label'), icon: { icon: 'close-rounded', title: (0, Chat_lang_1.langAttrOf)(lang.closeChatButton, 'title') }, onClick: () => controller.handlers.button.click() })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__content", children: [(0, jsx_runtime_1.jsx)(ChatSessionFeedback_1.ChatSessionFeedback, { ...subProps.sessionFeedback, controller: controller }), (0, jsx_runtime_1.jsx)("div", { ref: headerRef, className: (0, classnames_1.default)('ss__chat__content__header', {
619
+ onClickCapture: isMobile && shouldShowSideChat ? () => dismissSideChat() : undefined, children: [(0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__header', children: [(0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__header__title", children: [logo ? ((0, jsx_runtime_1.jsx)(Image_1.Image, { className: "ss__chat__header__title__logo", src: logo, alt: title || (0, Chat_lang_1.langAttrOf)(lang.headerLogo, 'alt') || '' })) : null, (0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__header__title__text", children: [title ? (0, jsx_runtime_1.jsx)("div", { className: "ss__chat__header__title__text__primary", children: title }) : null, subtitle ? (0, jsx_runtime_1.jsx)("div", { className: "ss__chat__header__title__text__secondary", children: subtitle }) : null] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__header__buttons", children: [(0, jsx_runtime_1.jsx)(Button_1.Button, { className: "ss__chat__header__button--new", "aria-label": (0, Chat_lang_1.langAttrOf)(lang.newChatButton, 'aria-label'), icon: { icon: controller.store.initChatLoading ? 'spinner' : 'plus-rounded', title: (0, Chat_lang_1.langAttrOf)(lang.newChatButton, 'title') }, onClick: () => controller.store.createChat() }), store.chats.length > 1 && (0, jsx_runtime_1.jsx)(ChatHistory_1.ChatHistory, { ...subProps.history, controller: controller }), (0, jsx_runtime_1.jsx)(Button_1.Button, { className: "ss__chat__header__button--close", "aria-label": (0, Chat_lang_1.langAttrOf)(lang.closeChatButton, 'aria-label'), icon: { icon: 'close-rounded', title: (0, Chat_lang_1.langAttrOf)(lang.closeChatButton, 'title') }, onClick: () => controller.handlers.button.click() })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__content", children: [(0, jsx_runtime_1.jsx)(ChatSessionFeedback_1.ChatSessionFeedback, { ...subProps.sessionFeedback, controller: controller }), (0, jsx_runtime_1.jsx)("div", { ref: headerRef, className: (0, classnames_1.default)('ss__chat__content__header', {
613
620
  'ss__chat__content__header--overlay': messagesOverflow,
614
621
  }), children: (0, jsx_runtime_1.jsx)(ChatComparisonsTray_1.ChatComparisonsTray, { ...subProps.comparisonsTray, controller: controller }) }), (0, jsx_runtime_1.jsx)(ChatMessages_1.ChatMessages, { ...subProps.messages, controller: controller, messagesContainerRef: messagesContainerRef, messagesEndRef: messagesEndRef, mobile: isMobile, avatarCharacter: avatarCharacter, avatarImage: avatarImage, sideChatOpen: !!shouldShowSideChat, onProductQuickView: () => setMobileProductInfoOpen(true), scrollToBottom: scrollToBottom, scrollToBottomIfNear: scrollToBottomIfNear, showNewMessages: showNewMessages, setShowNewMessages: setShowNewMessages, messagesOverflow: messagesOverflow }), (0, jsx_runtime_1.jsx)(ChatLoadingIndicator_1.ChatLoadingIndicator, { ...subProps.loadingIndicator, loading: store.loading, verbs: loadingVerbs }), !store.currentChat?.isExpired ? ((0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__content__footer", ref: footerRef, ...dragHandlers, children: [(store.error || store.chatEnabled === false) && ((0, jsx_runtime_1.jsx)("div", { className: "ss__chat__error", children: store.error?.message || (0, Chat_lang_1.langTextOf)(lang.chatUnavailableMessage) })), (0, jsx_runtime_1.jsx)(ChatTopicDrift_1.ChatTopicDrift, { ...subProps.topicDrift, controller: controller, variant: "sessionLimit" }), (0, jsx_runtime_1.jsx)(ChatFacetsBar_1.ChatFacetsBar, { ...subProps.facetsBar, controller: controller, chatRef: chatRef, multiselectFacets: multiselectFacets }), (0, jsx_runtime_1.jsx)(ChatAttachments_1.ChatAttachments, { ...subProps.attachments, controller: controller, activeMessage: activeMessage, sideChatOpen: !!shouldShowSideChat, mobile: isMobile, onProductQuickView: () => setMobileProductInfoOpen(true), onProductAttachmentsRemoved: () => setMobileProductInfoOpen(false) }), (0, jsx_runtime_1.jsx)(ChatTopicDrift_1.ChatTopicDrift, { ...subProps.topicDrift, controller: controller, variant: "drift" }), (0, jsx_runtime_1.jsx)(ChatComposer_1.ChatComposer, { ...subProps.composer, controller: controller, fileInputRef: fileInputRef, onUserSend: () => {
615
622
  if (isMobile && mobileProductInfoOpen) {
@@ -10,6 +10,9 @@ exports.chatDefaultLang = {
10
10
  closeChatButton: {
11
11
  attributes: { 'aria-label': 'Close chat', title: 'Close Chat' },
12
12
  },
13
+ headerLogo: {
14
+ attributes: { alt: 'Chat logo' },
15
+ },
13
16
  newChatButton: {
14
17
  attributes: { 'aria-label': 'New chat', title: 'New Chat' },
15
18
  },
@@ -69,6 +72,7 @@ exports.chatDefaultLang = {
69
72
  attachmentCompareTitle: { value: 'Compare these products' },
70
73
  attachmentAskProductTitle: { value: 'Ask about this product' },
71
74
  attachmentImageSimilarTitle: { value: 'Find products similar to this image:' },
75
+ attachmentImageName: { value: 'Image' },
72
76
  topicDriftScopeMessage: { value: "I'm here to help with shopping" },
73
77
  topicDriftScopeSubMessage: { value: 'Try asking about products, comparisons, or recommendations' },
74
78
  topicDriftMessage: { value: 'Looking for something new?' },
@@ -89,6 +93,7 @@ exports.chatDefaultLang = {
89
93
  attributes: { 'aria-label': 'Send Message', title: 'Send Message' },
90
94
  },
91
95
  dropOverlayText: { value: 'Drop image to upload' },
96
+ poweredByText: { value: 'Powered by Athos Commerce.' },
92
97
  disclaimerText: { value: 'AI-powered assistant. It sometimes makes mistakes. Avoid sharing personal data.' },
93
98
  privacyPolicyLinkText: { value: 'Privacy Policy' },
94
99
  expiredMessage: { value: 'This chat is expired. Please start a new chat.' },
@@ -69,7 +69,8 @@ exports.ChatAttachments = (0, mobx_react_lite_1.observer)((props) => {
69
69
  const dismissProductAttachment = (id) => {
70
70
  store.currentChat?.attachments.remove(id);
71
71
  props.onProductAttachmentsRemoved && props.onProductAttachmentsRemoved();
72
- store.currentChat?.dismissSideChat();
72
+ // dismiss through the controller so a product quickview closes with the window
73
+ controller.dismissSideChat();
73
74
  };
74
75
  const productItems = productAttachments.map((item) => {
75
76
  const remove = () => dismissProductAttachment(item.id);
@@ -83,7 +84,7 @@ exports.ChatAttachments = (0, mobx_react_lite_1.observer)((props) => {
83
84
  });
84
85
  const imageItems = imageAttachments.map((item) => ({
85
86
  id: item.id,
86
- name: item.fileName || 'Image',
87
+ name: item.fileName || (0, Chat_lang_1.langTextOf)(lang.attachmentImageName) || '',
87
88
  imageUrl: item.base64 || item.thumbnailUrl || '',
88
89
  isLoading: item.state === 'loading',
89
90
  hasError: !!item.error,
@@ -95,10 +96,10 @@ exports.ChatAttachments = (0, mobx_react_lite_1.observer)((props) => {
95
96
  const imageTitle = (imageItems.length > 0 && !hasImageError ? (0, Chat_lang_1.langTextOf)(lang.attachmentImageSimilarTitle) : '') || '';
96
97
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [comparisonItems.length > 0 && ((0, jsx_runtime_1.jsx)(ChatAttachmentContext_1.ChatAttachmentContext, { ...subProps.attachmentContext, title: (0, Chat_lang_1.langTextOf)(lang.attachmentCompareTitle) || '', items: comparisonItems, onClose: () => {
97
98
  store.currentChat?.comparisons.resetCommitted();
98
- store.currentChat?.dismissSideChat();
99
+ controller.dismissSideChat();
99
100
  } })), productItems.length > 0 && ((0, jsx_runtime_1.jsx)(ChatAttachmentContext_1.ChatAttachmentContext, { ...subProps.attachmentContext, title: productTitle, items: productItems, onClose: () => {
100
101
  productAttachments.forEach((item) => store.currentChat?.attachments.remove(item.id));
101
102
  props.onProductAttachmentsRemoved && props.onProductAttachmentsRemoved();
102
- store.currentChat?.dismissSideChat();
103
+ controller.dismissSideChat();
103
104
  } })), imageItems.length > 0 && (0, jsx_runtime_1.jsx)(ChatAttachmentContext_1.ChatAttachmentContext, { ...subProps.attachmentContext, title: imageTitle, items: imageItems })] }));
104
105
  });
@@ -43,7 +43,8 @@ const defaultStyles = ({ primaryColorBg, primaryColorFg }) => {
43
43
  'input[type="text"]': {
44
44
  padding: '0.5em 0',
45
45
  margin: '0 0 0 1em',
46
- flex: '1 0 auto',
46
+ flex: '1 1 0%',
47
+ minWidth: 0,
47
48
  border: 'none',
48
49
  backgroundColor: 'transparent',
49
50
  '&::placeholder': {
@@ -113,7 +114,6 @@ exports.ChatComposer = (0, mobx_react_lite_1.observer)((properties) => {
113
114
  const globalTheme = (0, providers_1.useTheme)();
114
115
  const globalTreePath = (0, providers_1.useTreePath)();
115
116
  const defaultProps = {
116
- poweredByText: 'Powered by Athos Commerce.',
117
117
  treePath: globalTreePath,
118
118
  };
119
119
  const props = (0, utilities_1.mergeProps)('chatComposer', globalTheme, defaultProps, properties);
@@ -162,5 +162,5 @@ exports.ChatComposer = (0, mobx_react_lite_1.observer)((properties) => {
162
162
  return;
163
163
  controller.search();
164
164
  onUserSend && onUserSend();
165
- } }) })] }), (0, jsx_runtime_1.jsx)("div", { className: 'ss__chat__disclaimer', children: (0, jsx_runtime_1.jsxs)("i", { children: [poweredByText, " ", (0, Chat_lang_1.langTextOf)(lang.disclaimerText), privacyPolicyUrl && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [' ', (0, jsx_runtime_1.jsx)("a", { href: privacyPolicyUrl, target: "_blank", rel: "noopener noreferrer", children: (0, Chat_lang_1.langTextOf)(lang.privacyPolicyLinkText) })] }))] }) })] }) }));
165
+ } }) })] }), (0, jsx_runtime_1.jsx)("div", { className: 'ss__chat__disclaimer', children: (0, jsx_runtime_1.jsxs)("i", { children: [poweredByText ?? (0, Chat_lang_1.langTextOf)(lang.poweredByText), " ", (0, Chat_lang_1.langTextOf)(lang.disclaimerText), privacyPolicyUrl && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [' ', (0, jsx_runtime_1.jsx)("a", { href: privacyPolicyUrl, target: "_blank", rel: "noopener noreferrer", children: (0, Chat_lang_1.langTextOf)(lang.privacyPolicyLinkText) })] }))] }) })] }) }));
166
166
  });
@@ -16,7 +16,7 @@ const hooks_2 = require("../../../../hooks");
16
16
  const Button_1 = require("../../../Atoms/Button");
17
17
  const ChatInspirationResultMessage_1 = require("../../../Molecules/ChatInspirationResultMessage");
18
18
  const ChatProductComparisonMessage_1 = require("../../../Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage");
19
- const ChatProductQueryMessage_1 = require("../../../Molecules/ChatProductQueryMessage/ChatProductQueryMessage");
19
+ const ChatQuickview_1 = require("../../../Molecules/ChatQuickview/ChatQuickview");
20
20
  const useChatGestures_1 = require("../hooks/useChatGestures");
21
21
  const Chat_lang_1 = require("../Chat.lang");
22
22
  const defaultStyles = ({ mobile, footerHeight, primaryColorBg }) => {
@@ -135,7 +135,7 @@ exports.ChatSideChat = (0, mobx_react_lite_1.observer)((properties) => {
135
135
  theme: props.theme,
136
136
  treePath,
137
137
  },
138
- productQueryMessage: {
138
+ quickview: {
139
139
  disableStyles,
140
140
  theme: props.theme,
141
141
  treePath,
@@ -158,7 +158,7 @@ exports.ChatSideChat = (0, mobx_react_lite_1.observer)((properties) => {
158
158
  case 'productComparison':
159
159
  return ((0, jsx_runtime_1.jsx)(ChatProductComparisonMessage_1.ChatProductComparisonMessage, { ...subProps.productComparisonMessage, chatItem: activeMessage, controller: controller }));
160
160
  case 'productQuery':
161
- return ((0, jsx_runtime_1.jsx)(ChatProductQueryMessage_1.ChatProductQueryMessage, { ...subProps.productQueryMessage, chatItem: activeMessage, controller: controller, displayFields: controller.config.settings?.quickview?.displayFields, primaryColor: primaryColorBg, primaryColorText: primaryColorFg }));
161
+ return ((0, jsx_runtime_1.jsx)(ChatQuickview_1.ChatQuickview, { ...subProps.quickview, chatItem: activeMessage, controller: controller, primaryColor: primaryColorBg, primaryColorText: primaryColorFg }));
162
162
  default:
163
163
  return null;
164
164
  }
@@ -4,7 +4,7 @@ exports.chatAccentThemeComponents = void 0;
4
4
  const utilities_1 = require("../../../../utilities");
5
5
  /**
6
6
  * Accent styling for buttons living inside child components (ChatResult's cart /
7
- * inquire icons and ChatProductQueryMessage's action buttons) — injected through
7
+ * inquire icons and ChatQuickview's action buttons) — injected through
8
8
  * the theme so each child applies it via its own style pipeline instead of the
9
9
  * organism reaching in with `!important` overrides.
10
10
  */
@@ -30,27 +30,29 @@ const chatAccentThemeComponents = ({ primaryAccentColorBg, primaryAccentColorFg,
30
30
  },
31
31
  },
32
32
  },
33
- chatProductQueryMessage: {
33
+ chatQuickview: {
34
34
  style: {
35
- '.ss__chat-product-query-message__header__product__actions': {
36
- '.ss__chat-product-query-message__header__product__actions__add-to-cart .ss__button': {
37
- background: primaryAccentColorBg,
38
- color: primaryAccentColorFg,
39
- svg: {
40
- fill: primaryAccentColorFg,
41
- stroke: primaryAccentColorFg,
42
- },
43
- '&:not(.ss__button--disabled):hover': {
44
- background: new utilities_1.Colour(primaryAccentColorBg).mixBlack(),
45
- },
35
+ '.ss__quickview__add-to-cart.ss__button': {
36
+ background: primaryAccentColorBg,
37
+ color: primaryAccentColorFg,
38
+ svg: {
39
+ fill: primaryAccentColorFg,
40
+ stroke: primaryAccentColorFg,
46
41
  },
47
- '.ss__chat-product-query-message__header__product__actions__show-similar .ss__button, .ss__chat-product-query-message__header__product__actions__discuss-product .ss__button': {
48
- background: secondaryAccentColorBg,
49
- color: secondaryAccentColorFg,
50
- border: `1px solid ${secondaryAccentColorFg}`,
51
- '&:not(.ss__button--disabled):hover': {
52
- background: new utilities_1.Colour(secondaryAccentColorBg).mixBlack(),
53
- },
42
+ '&:not(.ss__button--disabled):hover': {
43
+ background: new utilities_1.Colour(primaryAccentColorBg).mixBlack(),
44
+ },
45
+ },
46
+ '.ss__quickview__more-info.ss__button, .ss__quickview__similar.ss__button, .ss__quickview__discuss.ss__button': {
47
+ background: secondaryAccentColorBg,
48
+ color: secondaryAccentColorFg,
49
+ border: `1px solid ${secondaryAccentColorFg}`,
50
+ svg: {
51
+ fill: secondaryAccentColorFg,
52
+ stroke: secondaryAccentColorFg,
53
+ },
54
+ '&:not(.ss__button--disabled):hover': {
55
+ background: new utilities_1.Colour(secondaryAccentColorBg).mixBlack(),
54
56
  },
55
57
  },
56
58
  },
@@ -258,7 +258,7 @@ exports.QuickviewLayout = (0, mobx_react_lite_1.observer)((properties) => {
258
258
  hideBadge: false,
259
259
  };
260
260
  const props = (0, utilities_1.mergeProps)('quickviewLayout', globalTheme, defaultProps, properties);
261
- const { quickviewManager, className, internalClassName, disableStyles, treePath, hideBadge, column1, column2, column3, column4, recommendation } = props;
261
+ const { quickviewManager, className, internalClassName, disableStyles, treePath, hideBadge, variantDropdownType, column1, column2, column3, column4, recommendation, } = props;
262
262
  // NOTE: the `!shouldRenderDefault` return lives below the last hook call — every hook in this
263
263
  // component must run unconditionally on every render (shouldRenderDefault can flip while
264
264
  // mounted, e.g. when a pending customComponent import resolves or fails).
@@ -281,6 +281,12 @@ exports.QuickviewLayout = (0, mobx_react_lite_1.observer)((properties) => {
281
281
  moreInfoButton: {
282
282
  value: 'More info',
283
283
  },
284
+ similarButton: {
285
+ value: 'Similar',
286
+ },
287
+ discussButton: {
288
+ value: 'Discuss',
289
+ },
284
290
  loadingText: {
285
291
  value: 'Loading…',
286
292
  },
@@ -343,7 +349,8 @@ exports.QuickviewLayout = (0, mobx_react_lite_1.observer)((properties) => {
343
349
  // is within it).
344
350
  (0, hooks_1.useEffect)(() => {
345
351
  const isOpenNow = Boolean(quickviewManager?.store?.isOpen);
346
- if (!shouldRenderDefault || !isOpenNow)
352
+ // inline embeds (e.g. the chat secondary window) are not modal — Escape must not close them
353
+ if (!shouldRenderDefault || !isOpenNow || props.inline)
347
354
  return;
348
355
  const onKey = (e) => {
349
356
  if (e.key === 'Escape' && !galleryOpen) {
@@ -352,7 +359,7 @@ exports.QuickviewLayout = (0, mobx_react_lite_1.observer)((properties) => {
352
359
  };
353
360
  window.addEventListener('keydown', onKey);
354
361
  return () => window.removeEventListener('keydown', onKey);
355
- }, [shouldRenderDefault, quickviewManager?.store?.isOpen, galleryOpen]);
362
+ }, [shouldRenderDefault, quickviewManager?.store?.isOpen, galleryOpen, props.inline]);
356
363
  // Recommendation modules. `findModule` runs inside .map()/recursion and must not call hooks, so
357
364
  // resolve every referenced profile's controller + components here (stable order) and let
358
365
  // findModule read from this map. Mirrors Organisms/NoResults.
@@ -449,12 +456,18 @@ exports.QuickviewLayout = (0, mobx_react_lite_1.observer)((properties) => {
449
456
  };
450
457
  // Dialog semantics + focus trap for the quickview content, following the autocomplete
451
458
  // containers (AutocompleteModal/AutocompleteSlideout): useA11y traps Tab within the
452
- // content and wires Escape to the callback above.
459
+ // content and wires Escape to the callback above. Inline embeds (e.g. the chat secondary
460
+ // window) are part of the surrounding page — no dialog role and no focus trap, which
461
+ // would otherwise stop the shopper tabbing out to the chat composer.
453
462
  const contentProps = {
454
463
  className: 'ss__quickview__content',
455
- role: 'dialog',
456
- 'aria-modal': 'true',
457
- ref: (e) => (0, hooks_2.useA11y)(e, 0, true, handleEscape),
464
+ ...(props.inline
465
+ ? {}
466
+ : {
467
+ role: 'dialog',
468
+ 'aria-modal': 'true',
469
+ ref: (e) => (0, hooks_2.useA11y)(e, 0, true, handleEscape),
470
+ }),
458
471
  ...mergedLang.quickview?.attributes,
459
472
  };
460
473
  // Prefer `product.display` so the displayed name/image/attributes reflect the
@@ -549,17 +562,23 @@ exports.QuickviewLayout = (0, mobx_react_lite_1.observer)((properties) => {
549
562
  // the selection whose field matches (e.g. `variantSelection.color`). The field also matches its
550
563
  // component-name form (`color_family` → `color-family`). A bare `variantSelection` module is
551
564
  // not supported.
565
+ // `variantDropdownType` swaps the component for selections that aren't swatches.
566
+ const renderSelection = (selection) => {
567
+ const isSwatch = selection.type === 'swatch' || selection.type === 'swatches';
568
+ const type = variantDropdownType && !isSwatch ? variantDropdownType : selection.type;
569
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "ss__quickview__variant", children: [(0, jsx_runtime_1.jsx)("div", { className: "ss__quickview__variant-title", children: selection.label || selection.field }), (0, jsx_runtime_1.jsx)(VariantSelection_1.VariantSelection, { selection: selection, type: type, theme: props.theme, treePath: treePath, ...(0, utilities_1.defined)({ disableStyles }) })] }, selection.field));
570
+ };
552
571
  if (module == 'variantSelections') {
553
572
  if (!selections || selections.length === 0)
554
573
  return null;
555
- return ((0, jsx_runtime_1.jsx)("div", { className: "ss__quickview__variants", children: selections.map((selection) => ((0, jsx_runtime_1.jsxs)("div", { className: "ss__quickview__variant", children: [(0, jsx_runtime_1.jsx)("div", { className: "ss__quickview__variant-title", children: selection.label || selection.field }), (0, jsx_runtime_1.jsx)(VariantSelection_1.VariantSelection, { selection: selection, type: selection.type, theme: props.theme, treePath: treePath, ...(0, utilities_1.defined)({ disableStyles }) })] }, selection.field))) }));
574
+ return (0, jsx_runtime_1.jsx)("div", { className: "ss__quickview__variants", children: selections.map((selection) => renderSelection(selection)) });
556
575
  }
557
576
  if (module.startsWith('variantSelection.')) {
558
577
  const name = module.slice('variantSelection.'.length);
559
578
  const selection = selections?.find((selection) => selection.field === name || (0, snap_toolbox_1.fieldNameToComponentName)(selection.field) === name);
560
579
  if (!name || !selection)
561
580
  return null;
562
- return ((0, jsx_runtime_1.jsxs)("div", { className: "ss__quickview__variant", children: [(0, jsx_runtime_1.jsx)("div", { className: "ss__quickview__variant-title", children: selection.label || selection.field }), (0, jsx_runtime_1.jsx)(VariantSelection_1.VariantSelection, { selection: selection, type: selection.type, theme: props.theme, treePath: treePath, ...(0, utilities_1.defined)({ disableStyles }) })] }));
581
+ return renderSelection(selection);
563
582
  }
564
583
  if (module == 'button.add-to-cart') {
565
584
  if (!product)
@@ -569,7 +588,7 @@ exports.QuickviewLayout = (0, mobx_react_lite_1.observer)((properties) => {
569
588
  if (module == 'button.more-info') {
570
589
  if (!url)
571
590
  return null;
572
- return ((0, jsx_runtime_1.jsx)(Button_1.Button, { name: "more-info", internalClassName: "ss__quickview__go-to-product", lang: { button: lang.moreInfoButton }, onClick: (e) => {
591
+ return ((0, jsx_runtime_1.jsx)(Button_1.Button, { name: "more-info", internalClassName: "ss__quickview__more-info", lang: { button: lang.moreInfoButton }, onClick: (e) => {
573
592
  // track the redirect to the product page as a quickview clickThrough
574
593
  // before navigating away (delegated with `quickView: true`)
575
594
  if (product) {
@@ -578,6 +597,20 @@ exports.QuickviewLayout = (0, mobx_react_lite_1.observer)((properties) => {
578
597
  window.location.href = url;
579
598
  }, theme: props.theme, treePath: treePath, ...(0, utilities_1.defined)({ disableStyles }) }));
580
599
  }
600
+ // Chat-only modules: `button.similar` and `button.discuss` forward to the chat controller
601
+ // that opened the quickview. They render nothing for non-chat source controllers, so a
602
+ // layout carrying them stays safe to share across surfaces.
603
+ if (module == 'button.similar' || module == 'button.discuss') {
604
+ const chatController = quickviewManager.sourceController?.type === 'chat' ? quickviewManager.sourceController : undefined;
605
+ if (!product || !chatController)
606
+ return null;
607
+ if (module == 'button.similar') {
608
+ if (!chatController.store.features?.similarProducts?.enabled)
609
+ return null;
610
+ return ((0, jsx_runtime_1.jsx)(Button_1.Button, { name: "similar", internalClassName: "ss__quickview__similar", lang: { button: lang.similarButton }, onClick: () => chatController.productSimilar(product), theme: props.theme, treePath: treePath, ...(0, utilities_1.defined)({ disableStyles }) }));
611
+ }
612
+ return ((0, jsx_runtime_1.jsx)(Button_1.Button, { name: "discuss", internalClassName: "ss__quickview__discuss", lang: { button: lang.discussButton }, onClick: () => chatController.productQuery(product), theme: props.theme, treePath: treePath, ...(0, utilities_1.defined)({ disableStyles }) }));
613
+ }
581
614
  // `quantityPicker` binds to the observable `product.quantity`, which `button.add-to-cart`
582
615
  // (via the cart store) picks up when the product is added.
583
616
  if (module == 'quantityPicker') {
@@ -613,5 +646,5 @@ exports.QuickviewLayout = (0, mobx_react_lite_1.observer)((properties) => {
613
646
  }
614
647
  const topRowCounter = { value: 0 };
615
648
  const closeButton = ((0, jsx_runtime_1.jsx)(Button_1.Button, { name: "close", internalClassName: "ss__quickview__close", icon: "close-thin", lang: { button: lang.closeButton }, onClick: () => onClose(), theme: props.theme, treePath: treePath, ...(0, utilities_1.defined)({ disableStyles }) }));
616
- return ((0, jsx_runtime_1.jsx)(providers_1.CacheProvider, { children: (0, jsx_runtime_1.jsx)("div", { ...styling, className: (0, classnames_1.default)('ss__quickview', className, internalClassName), children: error || loading || product ? ((0, jsx_runtime_1.jsxs)("div", { ...contentProps, children: [closeButton, error ? ((0, jsx_runtime_1.jsx)("div", { className: "ss__quickview__error", role: "alert", children: error.message })) : loading ? ((0, jsx_runtime_1.jsx)("div", { className: "ss__quickview__loading", ...mergedLang.loadingText?.all })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [layout?.map((module) => findModule(module, topRowCounter)), (0, jsx_runtime_1.jsx)(Gallery_1.Gallery, { images: galleryImages, open: galleryOpen, startIndex: galleryIndex, onClose: () => setGalleryOpen(false), alt: name, theme: props.theme, treePath: treePath, ...(0, utilities_1.defined)({ disableStyles }) })] }))] })) : null }) }));
649
+ return ((0, jsx_runtime_1.jsx)(providers_1.CacheProvider, { children: (0, jsx_runtime_1.jsx)("div", { ...styling, className: (0, classnames_1.default)('ss__quickview', className, internalClassName), children: error || loading || product ? ((0, jsx_runtime_1.jsxs)("div", { ...contentProps, children: [!props.inline && closeButton, error ? ((0, jsx_runtime_1.jsx)("div", { className: "ss__quickview__error", role: "alert", children: error.message })) : loading ? ((0, jsx_runtime_1.jsx)("div", { className: "ss__quickview__loading", ...mergedLang.loadingText?.all })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [layout?.map((module) => findModule(module, topRowCounter)), (0, jsx_runtime_1.jsx)(Gallery_1.Gallery, { images: galleryImages, open: galleryOpen, startIndex: galleryIndex, onClose: () => setGalleryOpen(false), alt: name, theme: props.theme, treePath: treePath, ...(0, utilities_1.defined)({ disableStyles }) })] }))] })) : null }) }));
617
650
  });
@@ -44,7 +44,7 @@ __exportStar(require("./components/Molecules/ChatInspirationResultMessage"), exp
44
44
  __exportStar(require("./components/Molecules/ChatMessageText"), exports);
45
45
  __exportStar(require("./components/Molecules/ChatMessageUser"), exports);
46
46
  __exportStar(require("./components/Molecules/ChatProductComparisonMessage"), exports);
47
- __exportStar(require("./components/Molecules/ChatProductQueryMessage"), exports);
47
+ __exportStar(require("./components/Molecules/ChatQuickview"), exports);
48
48
  __exportStar(require("./components/Molecules/ChatResult"), exports);
49
49
  __exportStar(require("./components/Molecules/ChatResultsDisplay"), exports);
50
50
  __exportStar(require("./components/Molecules/ChatSuggestedQuestions"), exports);
@@ -35,7 +35,7 @@ exports.ALL_CUSTOM_COMPONENT_TYPES = [
35
35
  'chatMessageText',
36
36
  'chatMessageUser',
37
37
  'chatProductComparisonMessage',
38
- 'chatProductQueryMessage',
38
+ 'chatQuickview',
39
39
  'chatResult',
40
40
  'chatResultsDisplay',
41
41
  'chatSuggestedQuestions',
@@ -126,7 +126,7 @@ class Snap {
126
126
  profiler: services?.profiler,
127
127
  logger: services?.logger,
128
128
  tracker: services?.tracker || this.tracker,
129
- quickviewManager: services?.quickviewManager || this.quickviewManager,
129
+ quickviewManager: services?.quickviewManager || (type === snap_controller_1.ControllerTypes.chat ? this.chatQuickviewManager : this.quickviewManager),
130
130
  });
131
131
  }
132
132
  if (callback) {
@@ -496,6 +496,18 @@ class Snap {
496
496
  this.logger.error(`Failed to create the Quickview Manager.`, err);
497
497
  }
498
498
  }
499
+ // Create the chat quickview manager whenever chat controllers are configured — even
500
+ // without a `quickview` config, since chat needs no component target (the productQuery
501
+ // panel renders a QuickviewLayout inline). Settings inherit from the quickview config
502
+ // when one exists so displayFields/imagesField behave consistently across both surfaces.
503
+ if (this.config.controllers?.chat?.length) {
504
+ try {
505
+ this.chatQuickviewManager = new snap_controller_1.QuickviewManager({}, { ...(this.config.quickview?.config || {}), id: 'chat-quickview' });
506
+ }
507
+ catch (err) {
508
+ this.logger.error(`Failed to create the chat Quickview Manager.`, err);
509
+ }
510
+ }
499
511
  // create controllers
500
512
  Object.keys(this.config?.controllers || {}).forEach((type) => {
501
513
  switch (type) {
@@ -41,7 +41,7 @@ class LibraryStore {
41
41
  chatMessageText: {},
42
42
  chatMessageUser: {},
43
43
  chatProductComparisonMessage: {},
44
- chatProductQueryMessage: {},
44
+ chatQuickview: {},
45
45
  chatResult: {},
46
46
  chatResultsDisplay: {},
47
47
  chatSuggestedQuestions: {},
@@ -262,7 +262,7 @@ class LibraryStore {
262
262
  chatMessageText: {},
263
263
  chatMessageUser: {},
264
264
  chatProductComparisonMessage: {},
265
- chatProductQueryMessage: {},
265
+ chatQuickview: {},
266
266
  chatResult: {},
267
267
  chatResultsDisplay: {},
268
268
  chatSuggestedQuestions: {},