@athoscommerce/snap-preact 1.7.0 → 1.7.1-beta.129

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 (367) hide show
  1. package/dist/cjs/components/src/components/Atoms/Button/Button.d.ts +1 -1
  2. package/dist/cjs/components/src/components/Atoms/Button/Button.d.ts.map +1 -1
  3. package/dist/cjs/components/src/components/Atoms/ChatLoadingIndicator/ChatLoadingIndicator.d.ts +7 -0
  4. package/dist/cjs/components/src/components/Atoms/ChatLoadingIndicator/ChatLoadingIndicator.d.ts.map +1 -0
  5. package/dist/cjs/components/src/components/Atoms/ChatLoadingIndicator/ChatLoadingIndicator.js +85 -0
  6. package/dist/cjs/components/src/components/Atoms/ChatLoadingIndicator/index.d.ts +2 -0
  7. package/dist/cjs/components/src/components/Atoms/ChatLoadingIndicator/index.d.ts.map +1 -0
  8. package/dist/cjs/components/src/components/Atoms/ChatLoadingIndicator/index.js +17 -0
  9. package/dist/cjs/components/src/components/Atoms/Dropdown/Dropdown.d.ts +4 -0
  10. package/dist/cjs/components/src/components/Atoms/Dropdown/Dropdown.d.ts.map +1 -1
  11. package/dist/cjs/components/src/components/Atoms/Dropdown/Dropdown.js +51 -14
  12. package/dist/cjs/components/src/components/Atoms/Icon/paths.d.ts +21 -0
  13. package/dist/cjs/components/src/components/Atoms/Icon/paths.d.ts.map +1 -1
  14. package/dist/cjs/components/src/components/Atoms/Icon/paths.js +21 -0
  15. package/dist/cjs/components/src/components/Molecules/CalloutBadge/CalloutBadge.js +3 -3
  16. package/dist/cjs/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.d.ts +20 -0
  17. package/dist/cjs/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.d.ts.map +1 -0
  18. package/dist/cjs/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.js +187 -0
  19. package/dist/cjs/components/src/components/Molecules/ChatAttachmentContext/index.d.ts +2 -0
  20. package/dist/cjs/components/src/components/Molecules/ChatAttachmentContext/index.d.ts.map +1 -0
  21. package/dist/cjs/components/src/components/Molecules/ChatAttachmentContext/index.js +17 -0
  22. package/dist/cjs/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.d.ts +18 -0
  23. package/dist/cjs/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.d.ts.map +1 -0
  24. package/dist/cjs/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.js +175 -0
  25. package/dist/cjs/components/src/components/Molecules/ChatInspirationResultMessage/index.d.ts +2 -0
  26. package/dist/cjs/components/src/components/Molecules/ChatInspirationResultMessage/index.d.ts.map +1 -0
  27. package/dist/cjs/components/src/components/Molecules/ChatInspirationResultMessage/index.js +17 -0
  28. package/dist/cjs/components/src/components/Molecules/ChatMessageText/ChatMessageText.d.ts +21 -0
  29. package/dist/cjs/components/src/components/Molecules/ChatMessageText/ChatMessageText.d.ts.map +1 -0
  30. package/dist/cjs/components/src/components/Molecules/ChatMessageText/ChatMessageText.js +211 -0
  31. package/dist/cjs/components/src/components/Molecules/ChatMessageText/index.d.ts +2 -0
  32. package/dist/cjs/components/src/components/Molecules/ChatMessageText/index.d.ts.map +1 -0
  33. package/dist/cjs/components/src/components/Molecules/ChatMessageText/index.js +17 -0
  34. package/dist/cjs/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.d.ts +16 -0
  35. package/dist/cjs/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.d.ts.map +1 -0
  36. package/dist/cjs/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.js +255 -0
  37. package/dist/cjs/components/src/components/Molecules/ChatMessageUser/index.d.ts +2 -0
  38. package/dist/cjs/components/src/components/Molecules/ChatMessageUser/index.d.ts.map +1 -0
  39. package/dist/cjs/components/src/components/Molecules/ChatMessageUser/index.js +17 -0
  40. package/dist/cjs/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.d.ts +17 -0
  41. package/dist/cjs/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.d.ts.map +1 -0
  42. package/dist/cjs/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.js +143 -0
  43. package/dist/cjs/components/src/components/Molecules/ChatProductComparisonMessage/index.d.ts +2 -0
  44. package/dist/cjs/components/src/components/Molecules/ChatProductComparisonMessage/index.d.ts.map +1 -0
  45. package/dist/cjs/components/src/components/Molecules/ChatProductComparisonMessage/index.js +17 -0
  46. package/dist/cjs/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.d.ts +25 -0
  47. package/dist/cjs/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.d.ts.map +1 -0
  48. package/dist/cjs/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.js +487 -0
  49. package/dist/cjs/components/src/components/Molecules/ChatProductQueryMessage/index.d.ts +2 -0
  50. package/dist/cjs/components/src/components/Molecules/ChatProductQueryMessage/index.d.ts.map +1 -0
  51. package/dist/cjs/components/src/components/Molecules/ChatProductQueryMessage/index.js +17 -0
  52. package/dist/cjs/components/src/components/Molecules/ChatResult/ChatResult.d.ts +11 -0
  53. package/dist/cjs/components/src/components/Molecules/ChatResult/ChatResult.d.ts.map +1 -0
  54. package/dist/cjs/components/src/components/Molecules/ChatResult/ChatResult.js +200 -0
  55. package/dist/cjs/components/src/components/Molecules/ChatResult/index.d.ts +2 -0
  56. package/dist/cjs/components/src/components/Molecules/ChatResult/index.d.ts.map +1 -0
  57. package/dist/cjs/components/src/components/Molecules/ChatResult/index.js +17 -0
  58. package/dist/cjs/components/src/components/Molecules/ChatResultsDisplay/ChatResultsDisplay.d.ts +12 -0
  59. package/dist/cjs/components/src/components/Molecules/ChatResultsDisplay/ChatResultsDisplay.d.ts.map +1 -0
  60. package/dist/cjs/components/src/components/Molecules/ChatResultsDisplay/ChatResultsDisplay.js +123 -0
  61. package/dist/cjs/components/src/components/Molecules/ChatResultsDisplay/index.d.ts +2 -0
  62. package/dist/cjs/components/src/components/Molecules/ChatResultsDisplay/index.d.ts.map +1 -0
  63. package/dist/cjs/components/src/components/Molecules/ChatResultsDisplay/index.js +17 -0
  64. package/dist/cjs/components/src/components/Molecules/ChatSuggestedQuestions/ChatSuggestedQuestions.d.ts +15 -0
  65. package/dist/cjs/components/src/components/Molecules/ChatSuggestedQuestions/ChatSuggestedQuestions.d.ts.map +1 -0
  66. package/dist/cjs/components/src/components/Molecules/ChatSuggestedQuestions/ChatSuggestedQuestions.js +99 -0
  67. package/dist/cjs/components/src/components/Molecules/ChatSuggestedQuestions/index.d.ts +2 -0
  68. package/dist/cjs/components/src/components/Molecules/ChatSuggestedQuestions/index.d.ts.map +1 -0
  69. package/dist/cjs/components/src/components/Molecules/ChatSuggestedQuestions/index.js +17 -0
  70. package/dist/cjs/components/src/components/Molecules/OverlayBadge/OverlayBadge.js +2 -2
  71. package/dist/cjs/components/src/components/Molecules/Result/Result.d.ts +5 -3
  72. package/dist/cjs/components/src/components/Molecules/Result/Result.d.ts.map +1 -1
  73. package/dist/cjs/components/src/components/Molecules/Result/Result.js +15 -9
  74. package/dist/cjs/components/src/components/Molecules/SearchInput/SearchInput.d.ts +2 -0
  75. package/dist/cjs/components/src/components/Molecules/SearchInput/SearchInput.d.ts.map +1 -1
  76. package/dist/cjs/components/src/components/Molecules/SearchInput/SearchInput.js +19 -2
  77. package/dist/cjs/components/src/components/Molecules/Slideout/Slideout.d.ts.map +1 -1
  78. package/dist/cjs/components/src/components/Molecules/Slideout/Slideout.js +21 -26
  79. package/dist/cjs/components/src/components/Molecules/Slideshow/Slideshow.d.ts.map +1 -1
  80. package/dist/cjs/components/src/components/Molecules/Slideshow/Slideshow.js +5 -1
  81. package/dist/cjs/components/src/components/Organisms/Chat/Chat.d.ts +30 -0
  82. package/dist/cjs/components/src/components/Organisms/Chat/Chat.d.ts.map +1 -0
  83. package/dist/cjs/components/src/components/Organisms/Chat/Chat.js +1047 -0
  84. package/dist/cjs/components/src/components/Organisms/Chat/Chat.styles.d.ts +16 -0
  85. package/dist/cjs/components/src/components/Organisms/Chat/Chat.styles.d.ts.map +1 -0
  86. package/dist/cjs/components/src/components/Organisms/Chat/Chat.styles.js +1186 -0
  87. package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatFileUpload.d.ts +32 -0
  88. package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatFileUpload.d.ts.map +1 -0
  89. package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatFileUpload.js +104 -0
  90. package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatGestures.d.ts +40 -0
  91. package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatGestures.d.ts.map +1 -0
  92. package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatGestures.js +98 -0
  93. package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatOverflow.d.ts +44 -0
  94. package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatOverflow.d.ts.map +1 -0
  95. package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatOverflow.js +116 -0
  96. package/dist/cjs/components/src/components/Organisms/Chat/index.d.ts +2 -0
  97. package/dist/cjs/components/src/components/Organisms/Chat/index.d.ts.map +1 -0
  98. package/dist/cjs/components/src/components/Organisms/Chat/index.js +17 -0
  99. package/dist/cjs/components/src/components/Organisms/Facet/Facet.js +2 -1
  100. package/dist/cjs/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.js +2 -1
  101. package/dist/cjs/components/src/components/Organisms/Results/Results.js +1 -1
  102. package/dist/cjs/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.d.ts +1 -1
  103. package/dist/cjs/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.d.ts.map +1 -1
  104. package/dist/cjs/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.js +3 -1
  105. package/dist/cjs/components/src/components/Templates/AutocompleteModal/AutocompleteModal.d.ts +1 -1
  106. package/dist/cjs/components/src/components/Templates/AutocompleteModal/AutocompleteModal.d.ts.map +1 -1
  107. package/dist/cjs/components/src/components/Templates/AutocompleteModal/AutocompleteModal.js +3 -1
  108. package/dist/cjs/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.d.ts +1 -1
  109. package/dist/cjs/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.d.ts.map +1 -1
  110. package/dist/cjs/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.js +3 -1
  111. package/dist/cjs/components/src/components/Templates/Chat/Chat.d.ts +12 -0
  112. package/dist/cjs/components/src/components/Templates/Chat/Chat.d.ts.map +1 -0
  113. package/dist/cjs/components/src/components/Templates/Chat/Chat.js +55 -0
  114. package/dist/cjs/components/src/components/Templates/Chat/index.d.ts +2 -0
  115. package/dist/cjs/components/src/components/Templates/Chat/index.d.ts.map +1 -0
  116. package/dist/cjs/components/src/components/Templates/Chat/index.js +17 -0
  117. package/dist/cjs/components/src/index.d.ts +11 -0
  118. package/dist/cjs/components/src/index.d.ts.map +1 -1
  119. package/dist/cjs/components/src/index.js +13 -1
  120. package/dist/cjs/components/src/providers/withTracking.d.ts +2 -2
  121. package/dist/cjs/components/src/providers/withTracking.d.ts.map +1 -1
  122. package/dist/cjs/components/src/setupTests.js +17 -0
  123. package/dist/cjs/components/src/themes/base/components/templates/chat.d.ts +4 -0
  124. package/dist/cjs/components/src/themes/base/components/templates/chat.d.ts.map +1 -0
  125. package/dist/cjs/components/src/themes/base/components/templates/chat.js +6 -0
  126. package/dist/cjs/components/src/themes/base/components/templates/index.d.ts.map +1 -1
  127. package/dist/cjs/components/src/themes/base/components/templates/index.js +5 -4
  128. package/dist/cjs/components/src/themes/bocachica/components/templates/chat.d.ts +4 -0
  129. package/dist/cjs/components/src/themes/bocachica/components/templates/chat.d.ts.map +1 -0
  130. package/dist/cjs/components/src/themes/bocachica/components/templates/chat.js +6 -0
  131. package/dist/cjs/components/src/themes/bocachica/components/templates/index.d.ts.map +1 -1
  132. package/dist/cjs/components/src/themes/bocachica/components/templates/index.js +5 -4
  133. package/dist/cjs/components/src/themes/pike/components/templates/chat.d.ts +4 -0
  134. package/dist/cjs/components/src/themes/pike/components/templates/chat.d.ts.map +1 -0
  135. package/dist/cjs/components/src/themes/pike/components/templates/chat.js +6 -0
  136. package/dist/cjs/components/src/themes/pike/components/templates/index.d.ts.map +1 -1
  137. package/dist/cjs/components/src/themes/pike/components/templates/index.js +5 -4
  138. package/dist/cjs/components/src/themes/snapnco/components/templates/chat.d.ts +4 -0
  139. package/dist/cjs/components/src/themes/snapnco/components/templates/chat.d.ts.map +1 -0
  140. package/dist/cjs/components/src/themes/snapnco/components/templates/chat.js +6 -0
  141. package/dist/cjs/components/src/themes/snapnco/components/templates/index.d.ts.map +1 -1
  142. package/dist/cjs/components/src/themes/snapnco/components/templates/index.js +5 -4
  143. package/dist/cjs/components/src/themes/snappy/components/templates/chat.d.ts +4 -0
  144. package/dist/cjs/components/src/themes/snappy/components/templates/chat.d.ts.map +1 -0
  145. package/dist/cjs/components/src/themes/snappy/components/templates/chat.js +6 -0
  146. package/dist/cjs/components/src/themes/snappy/components/templates/index.d.ts.map +1 -1
  147. package/dist/cjs/components/src/themes/snappy/components/templates/index.js +5 -4
  148. package/dist/cjs/components/src/themes/themeComponents/chat.d.ts +4 -0
  149. package/dist/cjs/components/src/themes/themeComponents/chat.d.ts.map +1 -0
  150. package/dist/cjs/components/src/themes/themeComponents/chat.js +14 -0
  151. package/dist/cjs/components/src/utilities/Colour/Colour.d.ts +11 -0
  152. package/dist/cjs/components/src/utilities/Colour/Colour.d.ts.map +1 -1
  153. package/dist/cjs/components/src/utilities/Colour/Colour.js +32 -0
  154. package/dist/cjs/components/src/utilities/snapify.d.ts +3 -2
  155. package/dist/cjs/components/src/utilities/snapify.d.ts.map +1 -1
  156. package/dist/cjs/components/src/utilities/snapify.js +48 -0
  157. package/dist/cjs/src/Snap.d.ts +2 -1
  158. package/dist/cjs/src/Snap.d.ts.map +1 -1
  159. package/dist/cjs/src/Snap.js +134 -24
  160. package/dist/cjs/src/Templates/SnapTemplates.d.ts +2 -1
  161. package/dist/cjs/src/Templates/SnapTemplates.d.ts.map +1 -1
  162. package/dist/cjs/src/Templates/SnapTemplates.js +67 -5
  163. package/dist/cjs/src/Templates/Stores/LibraryStore.d.ts +2 -0
  164. package/dist/cjs/src/Templates/Stores/LibraryStore.d.ts.map +1 -1
  165. package/dist/cjs/src/Templates/Stores/LibraryStore.js +19 -0
  166. package/dist/cjs/src/Templates/Stores/TemplateStore.d.ts +19 -4
  167. package/dist/cjs/src/Templates/Stores/TemplateStore.d.ts.map +1 -1
  168. package/dist/cjs/src/Templates/Stores/TemplateStore.js +2 -1
  169. package/dist/cjs/src/Templates/Stores/library/components/Chat.d.ts +2 -0
  170. package/dist/cjs/src/Templates/Stores/library/components/Chat.d.ts.map +1 -0
  171. package/dist/cjs/src/Templates/Stores/library/components/Chat.js +5 -0
  172. package/dist/cjs/src/Templates/Stores/library/languages/es.d.ts.map +1 -1
  173. package/dist/cjs/src/Templates/Stores/library/languages/es.js +5 -0
  174. package/dist/cjs/src/Templates/Stores/library/languages/fr.d.ts.map +1 -1
  175. package/dist/cjs/src/Templates/Stores/library/languages/fr.js +5 -0
  176. package/dist/cjs/src/create/createChatController.d.ts +5 -0
  177. package/dist/cjs/src/create/createChatController.d.ts.map +1 -0
  178. package/dist/cjs/src/create/createChatController.js +43 -0
  179. package/dist/cjs/src/setupEvents.d.ts +13 -0
  180. package/dist/cjs/src/setupEvents.d.ts.map +1 -1
  181. package/dist/cjs/src/setupEvents.js +87 -0
  182. package/dist/cjs/src/types.d.ts +15 -3
  183. package/dist/cjs/src/types.d.ts.map +1 -1
  184. package/dist/esm/components/src/components/Atoms/Button/Button.d.ts +1 -1
  185. package/dist/esm/components/src/components/Atoms/Button/Button.d.ts.map +1 -1
  186. package/dist/esm/components/src/components/Atoms/ChatLoadingIndicator/ChatLoadingIndicator.d.ts +7 -0
  187. package/dist/esm/components/src/components/Atoms/ChatLoadingIndicator/ChatLoadingIndicator.d.ts.map +1 -0
  188. package/dist/esm/components/src/components/Atoms/ChatLoadingIndicator/ChatLoadingIndicator.js +67 -0
  189. package/dist/esm/components/src/components/Atoms/ChatLoadingIndicator/index.d.ts +2 -0
  190. package/dist/esm/components/src/components/Atoms/ChatLoadingIndicator/index.d.ts.map +1 -0
  191. package/dist/esm/components/src/components/Atoms/ChatLoadingIndicator/index.js +1 -0
  192. package/dist/esm/components/src/components/Atoms/Dropdown/Dropdown.d.ts +4 -0
  193. package/dist/esm/components/src/components/Atoms/Dropdown/Dropdown.d.ts.map +1 -1
  194. package/dist/esm/components/src/components/Atoms/Dropdown/Dropdown.js +53 -11
  195. package/dist/esm/components/src/components/Atoms/Icon/paths.d.ts +21 -0
  196. package/dist/esm/components/src/components/Atoms/Icon/paths.d.ts.map +1 -1
  197. package/dist/esm/components/src/components/Atoms/Icon/paths.js +21 -0
  198. package/dist/esm/components/src/components/Molecules/CalloutBadge/CalloutBadge.js +1 -1
  199. package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.d.ts +20 -0
  200. package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.d.ts.map +1 -0
  201. package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.js +169 -0
  202. package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/index.d.ts +2 -0
  203. package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/index.d.ts.map +1 -0
  204. package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/index.js +1 -0
  205. package/dist/esm/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.d.ts +18 -0
  206. package/dist/esm/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.d.ts.map +1 -0
  207. package/dist/esm/components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.js +170 -0
  208. package/dist/esm/components/src/components/Molecules/ChatInspirationResultMessage/index.d.ts +2 -0
  209. package/dist/esm/components/src/components/Molecules/ChatInspirationResultMessage/index.d.ts.map +1 -0
  210. package/dist/esm/components/src/components/Molecules/ChatInspirationResultMessage/index.js +1 -0
  211. package/dist/esm/components/src/components/Molecules/ChatMessageText/ChatMessageText.d.ts +21 -0
  212. package/dist/esm/components/src/components/Molecules/ChatMessageText/ChatMessageText.d.ts.map +1 -0
  213. package/dist/esm/components/src/components/Molecules/ChatMessageText/ChatMessageText.js +192 -0
  214. package/dist/esm/components/src/components/Molecules/ChatMessageText/index.d.ts +2 -0
  215. package/dist/esm/components/src/components/Molecules/ChatMessageText/index.d.ts.map +1 -0
  216. package/dist/esm/components/src/components/Molecules/ChatMessageText/index.js +1 -0
  217. package/dist/esm/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.d.ts +16 -0
  218. package/dist/esm/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.d.ts.map +1 -0
  219. package/dist/esm/components/src/components/Molecules/ChatMessageUser/ChatMessageUser.js +223 -0
  220. package/dist/esm/components/src/components/Molecules/ChatMessageUser/index.d.ts +2 -0
  221. package/dist/esm/components/src/components/Molecules/ChatMessageUser/index.d.ts.map +1 -0
  222. package/dist/esm/components/src/components/Molecules/ChatMessageUser/index.js +1 -0
  223. package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.d.ts +17 -0
  224. package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.d.ts.map +1 -0
  225. package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.js +121 -0
  226. package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/index.d.ts +2 -0
  227. package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/index.d.ts.map +1 -0
  228. package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/index.js +1 -0
  229. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.d.ts +25 -0
  230. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.d.ts.map +1 -0
  231. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.js +460 -0
  232. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/index.d.ts +2 -0
  233. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/index.d.ts.map +1 -0
  234. package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/index.js +1 -0
  235. package/dist/esm/components/src/components/Molecules/ChatResult/ChatResult.d.ts +11 -0
  236. package/dist/esm/components/src/components/Molecules/ChatResult/ChatResult.d.ts.map +1 -0
  237. package/dist/esm/components/src/components/Molecules/ChatResult/ChatResult.js +184 -0
  238. package/dist/esm/components/src/components/Molecules/ChatResult/index.d.ts +2 -0
  239. package/dist/esm/components/src/components/Molecules/ChatResult/index.d.ts.map +1 -0
  240. package/dist/esm/components/src/components/Molecules/ChatResult/index.js +1 -0
  241. package/dist/esm/components/src/components/Molecules/ChatResultsDisplay/ChatResultsDisplay.d.ts +12 -0
  242. package/dist/esm/components/src/components/Molecules/ChatResultsDisplay/ChatResultsDisplay.d.ts.map +1 -0
  243. package/dist/esm/components/src/components/Molecules/ChatResultsDisplay/ChatResultsDisplay.js +102 -0
  244. package/dist/esm/components/src/components/Molecules/ChatResultsDisplay/index.d.ts +2 -0
  245. package/dist/esm/components/src/components/Molecules/ChatResultsDisplay/index.d.ts.map +1 -0
  246. package/dist/esm/components/src/components/Molecules/ChatResultsDisplay/index.js +1 -0
  247. package/dist/esm/components/src/components/Molecules/ChatSuggestedQuestions/ChatSuggestedQuestions.d.ts +15 -0
  248. package/dist/esm/components/src/components/Molecules/ChatSuggestedQuestions/ChatSuggestedQuestions.d.ts.map +1 -0
  249. package/dist/esm/components/src/components/Molecules/ChatSuggestedQuestions/ChatSuggestedQuestions.js +80 -0
  250. package/dist/esm/components/src/components/Molecules/ChatSuggestedQuestions/index.d.ts +2 -0
  251. package/dist/esm/components/src/components/Molecules/ChatSuggestedQuestions/index.d.ts.map +1 -0
  252. package/dist/esm/components/src/components/Molecules/ChatSuggestedQuestions/index.js +1 -0
  253. package/dist/esm/components/src/components/Molecules/OverlayBadge/OverlayBadge.js +1 -1
  254. package/dist/esm/components/src/components/Molecules/Result/Result.d.ts +5 -3
  255. package/dist/esm/components/src/components/Molecules/Result/Result.d.ts.map +1 -1
  256. package/dist/esm/components/src/components/Molecules/Result/Result.js +12 -7
  257. package/dist/esm/components/src/components/Molecules/SearchInput/SearchInput.d.ts +2 -0
  258. package/dist/esm/components/src/components/Molecules/SearchInput/SearchInput.d.ts.map +1 -1
  259. package/dist/esm/components/src/components/Molecules/SearchInput/SearchInput.js +35 -2
  260. package/dist/esm/components/src/components/Molecules/Slideout/Slideout.d.ts.map +1 -1
  261. package/dist/esm/components/src/components/Molecules/Slideout/Slideout.js +22 -27
  262. package/dist/esm/components/src/components/Molecules/Slideshow/Slideshow.d.ts.map +1 -1
  263. package/dist/esm/components/src/components/Molecules/Slideshow/Slideshow.js +5 -1
  264. package/dist/esm/components/src/components/Organisms/Chat/Chat.d.ts +30 -0
  265. package/dist/esm/components/src/components/Organisms/Chat/Chat.d.ts.map +1 -0
  266. package/dist/esm/components/src/components/Organisms/Chat/Chat.js +956 -0
  267. package/dist/esm/components/src/components/Organisms/Chat/Chat.styles.d.ts +16 -0
  268. package/dist/esm/components/src/components/Organisms/Chat/Chat.styles.d.ts.map +1 -0
  269. package/dist/esm/components/src/components/Organisms/Chat/Chat.styles.js +1227 -0
  270. package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatFileUpload.d.ts +32 -0
  271. package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatFileUpload.d.ts.map +1 -0
  272. package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatFileUpload.js +54 -0
  273. package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatGestures.d.ts +40 -0
  274. package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatGestures.d.ts.map +1 -0
  275. package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatGestures.js +92 -0
  276. package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatOverflow.d.ts +44 -0
  277. package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatOverflow.d.ts.map +1 -0
  278. package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatOverflow.js +110 -0
  279. package/dist/esm/components/src/components/Organisms/Chat/index.d.ts +2 -0
  280. package/dist/esm/components/src/components/Organisms/Chat/index.d.ts.map +1 -0
  281. package/dist/esm/components/src/components/Organisms/Chat/index.js +1 -0
  282. package/dist/esm/components/src/components/Organisms/Facet/Facet.js +1 -1
  283. package/dist/esm/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.js +1 -1
  284. package/dist/esm/components/src/components/Organisms/Results/Results.js +1 -1
  285. package/dist/esm/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.d.ts +1 -1
  286. package/dist/esm/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.d.ts.map +1 -1
  287. package/dist/esm/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.js +4 -1
  288. package/dist/esm/components/src/components/Templates/AutocompleteModal/AutocompleteModal.d.ts +1 -1
  289. package/dist/esm/components/src/components/Templates/AutocompleteModal/AutocompleteModal.d.ts.map +1 -1
  290. package/dist/esm/components/src/components/Templates/AutocompleteModal/AutocompleteModal.js +4 -1
  291. package/dist/esm/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.d.ts +1 -1
  292. package/dist/esm/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.d.ts.map +1 -1
  293. package/dist/esm/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.js +4 -1
  294. package/dist/esm/components/src/components/Templates/Chat/Chat.d.ts +12 -0
  295. package/dist/esm/components/src/components/Templates/Chat/Chat.d.ts.map +1 -0
  296. package/dist/esm/components/src/components/Templates/Chat/Chat.js +42 -0
  297. package/dist/esm/components/src/components/Templates/Chat/index.d.ts +2 -0
  298. package/dist/esm/components/src/components/Templates/Chat/index.d.ts.map +1 -0
  299. package/dist/esm/components/src/components/Templates/Chat/index.js +1 -0
  300. package/dist/esm/components/src/index.d.ts +11 -0
  301. package/dist/esm/components/src/index.d.ts.map +1 -1
  302. package/dist/esm/components/src/index.js +11 -0
  303. package/dist/esm/components/src/providers/withTracking.d.ts +2 -2
  304. package/dist/esm/components/src/providers/withTracking.d.ts.map +1 -1
  305. package/dist/esm/components/src/setupTests.js +14 -0
  306. package/dist/esm/components/src/themes/base/components/templates/chat.d.ts +4 -0
  307. package/dist/esm/components/src/themes/base/components/templates/chat.d.ts.map +1 -0
  308. package/dist/esm/components/src/themes/base/components/templates/chat.js +3 -0
  309. package/dist/esm/components/src/themes/base/components/templates/index.d.ts.map +1 -1
  310. package/dist/esm/components/src/themes/base/components/templates/index.js +5 -0
  311. package/dist/esm/components/src/themes/bocachica/components/templates/chat.d.ts +4 -0
  312. package/dist/esm/components/src/themes/bocachica/components/templates/chat.d.ts.map +1 -0
  313. package/dist/esm/components/src/themes/bocachica/components/templates/chat.js +3 -0
  314. package/dist/esm/components/src/themes/bocachica/components/templates/index.d.ts.map +1 -1
  315. package/dist/esm/components/src/themes/bocachica/components/templates/index.js +5 -0
  316. package/dist/esm/components/src/themes/pike/components/templates/chat.d.ts +4 -0
  317. package/dist/esm/components/src/themes/pike/components/templates/chat.d.ts.map +1 -0
  318. package/dist/esm/components/src/themes/pike/components/templates/chat.js +3 -0
  319. package/dist/esm/components/src/themes/pike/components/templates/index.d.ts.map +1 -1
  320. package/dist/esm/components/src/themes/pike/components/templates/index.js +5 -0
  321. package/dist/esm/components/src/themes/snapnco/components/templates/chat.d.ts +4 -0
  322. package/dist/esm/components/src/themes/snapnco/components/templates/chat.d.ts.map +1 -0
  323. package/dist/esm/components/src/themes/snapnco/components/templates/chat.js +3 -0
  324. package/dist/esm/components/src/themes/snapnco/components/templates/index.d.ts.map +1 -1
  325. package/dist/esm/components/src/themes/snapnco/components/templates/index.js +5 -0
  326. package/dist/esm/components/src/themes/snappy/components/templates/chat.d.ts +4 -0
  327. package/dist/esm/components/src/themes/snappy/components/templates/chat.d.ts.map +1 -0
  328. package/dist/esm/components/src/themes/snappy/components/templates/chat.js +3 -0
  329. package/dist/esm/components/src/themes/snappy/components/templates/index.d.ts.map +1 -1
  330. package/dist/esm/components/src/themes/snappy/components/templates/index.js +5 -0
  331. package/dist/esm/components/src/themes/themeComponents/chat.d.ts +4 -0
  332. package/dist/esm/components/src/themes/themeComponents/chat.d.ts.map +1 -0
  333. package/dist/esm/components/src/themes/themeComponents/chat.js +11 -0
  334. package/dist/esm/components/src/utilities/Colour/Colour.d.ts +11 -0
  335. package/dist/esm/components/src/utilities/Colour/Colour.d.ts.map +1 -1
  336. package/dist/esm/components/src/utilities/Colour/Colour.js +30 -0
  337. package/dist/esm/components/src/utilities/snapify.d.ts +3 -2
  338. package/dist/esm/components/src/utilities/snapify.d.ts.map +1 -1
  339. package/dist/esm/components/src/utilities/snapify.js +29 -2
  340. package/dist/esm/src/Snap.d.ts +2 -1
  341. package/dist/esm/src/Snap.d.ts.map +1 -1
  342. package/dist/esm/src/Snap.js +72 -0
  343. package/dist/esm/src/Templates/SnapTemplates.d.ts +2 -1
  344. package/dist/esm/src/Templates/SnapTemplates.d.ts.map +1 -1
  345. package/dist/esm/src/Templates/SnapTemplates.js +55 -0
  346. package/dist/esm/src/Templates/Stores/LibraryStore.d.ts +2 -0
  347. package/dist/esm/src/Templates/Stores/LibraryStore.d.ts.map +1 -1
  348. package/dist/esm/src/Templates/Stores/LibraryStore.js +6 -0
  349. package/dist/esm/src/Templates/Stores/TemplateStore.d.ts +19 -4
  350. package/dist/esm/src/Templates/Stores/TemplateStore.d.ts.map +1 -1
  351. package/dist/esm/src/Templates/Stores/TemplateStore.js +2 -1
  352. package/dist/esm/src/Templates/Stores/library/components/Chat.d.ts +2 -0
  353. package/dist/esm/src/Templates/Stores/library/components/Chat.d.ts.map +1 -0
  354. package/dist/esm/src/Templates/Stores/library/components/Chat.js +1 -0
  355. package/dist/esm/src/Templates/Stores/library/languages/es.d.ts.map +1 -1
  356. package/dist/esm/src/Templates/Stores/library/languages/es.js +5 -0
  357. package/dist/esm/src/Templates/Stores/library/languages/fr.d.ts.map +1 -1
  358. package/dist/esm/src/Templates/Stores/library/languages/fr.js +5 -0
  359. package/dist/esm/src/create/createChatController.d.ts +5 -0
  360. package/dist/esm/src/create/createChatController.d.ts.map +1 -0
  361. package/dist/esm/src/create/createChatController.js +29 -0
  362. package/dist/esm/src/setupEvents.d.ts +13 -0
  363. package/dist/esm/src/setupEvents.d.ts.map +1 -1
  364. package/dist/esm/src/setupEvents.js +40 -0
  365. package/dist/esm/src/types.d.ts +15 -3
  366. package/dist/esm/src/types.d.ts.map +1 -1
  367. package/package.json +14 -12
@@ -0,0 +1,956 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
2
+ import classnames from 'classnames';
3
+ import deepmerge from 'deepmerge';
4
+ import { observer } from 'mobx-react-lite';
5
+ import { useTheme, CacheProvider, useTreePath } from '../../../providers';
6
+ import { Colour, mergeProps, mergeStyles } from '../../../utilities';
7
+ import { chatDefaultStyles } from './Chat.styles';
8
+ import { useChatGestures } from './hooks/useChatGestures';
9
+ import { useChatOverflow } from './hooks/useChatOverflow';
10
+ import { useChatFileUpload } from './hooks/useChatFileUpload';
11
+ import { Button } from '../../Atoms/Button';
12
+ import { useRef, useEffect, useMemo, useState } from 'preact/hooks';
13
+ import { ChatMessageUser } from '../../Molecules/ChatMessageUser';
14
+ import { ChatMessageText } from '../../Molecules/ChatMessageText';
15
+ import { ChatSuggestedQuestions } from '../../Molecules/ChatSuggestedQuestions';
16
+ import { ChatAttachmentContext } from '../../Molecules/ChatAttachmentContext';
17
+ import { Image } from '../../Atoms/Image';
18
+ import { ChatLoadingIndicator } from '../../Atoms/ChatLoadingIndicator';
19
+ import { Dropdown, FacetSlider, Icon, Overlay, useMediaQuery } from '../../..';
20
+ import { ChatInspirationResultMessage } from '../../Molecules/ChatInspirationResultMessage';
21
+ import { ChatProductComparisonMessage, } from '../../Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage';
22
+ import { ChatProductQueryMessage, } from '../../Molecules/ChatProductQueryMessage/ChatProductQueryMessage';
23
+ // Fallback footer copy when chat becomes disabled mid-session and store.error has
24
+ // been cleared (e.g. by createChat) — mirrors the controller's unavailable message.
25
+ const CHAT_UNAVAILABLE_MESSAGE = 'Service is temporarily unavailable. In the meantime, feel free to use the search bar above to find what you need!';
26
+ export const ChatOrganism = observer((properties) => {
27
+ const globalTheme = useTheme();
28
+ const globalTreePath = useTreePath();
29
+ const isMobile = useMediaQuery('(max-width: 767px)');
30
+ const defaultProps = {
31
+ treePath: globalTreePath,
32
+ logo: 'https://cdn.athoscommerce.net/snap/images/Athos%20Commerce_Icon_white.svg',
33
+ title: 'Athos Conversational Assistant',
34
+ subtitle: 'Your Guided Discovery Expert',
35
+ multiselectFacets: false,
36
+ disableBubbleSuggestedQuestions: isMobile ? true : false,
37
+ primaryColorBg: '#253B80',
38
+ primaryColorFg: '#fff',
39
+ primaryAccentColorBg: '#feeeae',
40
+ primaryAccentColorFg: '#000000',
41
+ secondaryAccentColorBg: '#000000',
42
+ secondaryAccentColorFg: '#ffffff',
43
+ position: 'right',
44
+ hideMessageTypeIndicatorText: false,
45
+ buttonBelowMessage: false,
46
+ };
47
+ let props = mergeProps('chat', globalTheme, defaultProps, properties);
48
+ const { className, internalClassName, controller, logo, title, subtitle, avatar, offset, multiselectFacets, disableBubbleSuggestedQuestions, primaryColorBg, primaryColorFg, primaryAccentColorBg, primaryAccentColorFg, secondaryAccentColorBg, secondaryAccentColorFg, position, hideMessageTypeIndicatorText, buttonBelowMessage, disableStyles, treePath, } = props;
49
+ const colorPrimary = primaryColorBg;
50
+ const colorPrimaryText = primaryColorFg;
51
+ const colorPrimaryAccent = primaryAccentColorBg;
52
+ const colorPrimaryAccentText = primaryAccentColorFg;
53
+ const colorSecondaryAccent = secondaryAccentColorBg;
54
+ const colorSecondaryAccentText = secondaryAccentColorFg;
55
+ const chatPosition = position === 'right' ? 'right' : 'left';
56
+ const isValidImageUrl = (value) => {
57
+ try {
58
+ const { protocol } = new URL(value);
59
+ return protocol === 'http:' || protocol === 'https:' || protocol === 'data:';
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ };
65
+ // A single-character avatar renders as a capitalized letter; a longer value renders
66
+ // as an image when it's a valid image URL. Anything else renders no avatar.
67
+ const avatarCharacter = avatar && avatar.length === 1 ? avatar.toUpperCase() : undefined;
68
+ const avatarImage = avatar && avatar.length > 1 && isValidImageUrl(avatar) ? avatar : undefined;
69
+ const { store } = controller;
70
+ // Track that the widget has been visible so a mid-session disable (status check
71
+ // flips chatEnabled to false) keeps it mounted with the unavailable message
72
+ // instead of vanishing. A disabled status at bootstrap still renders nothing.
73
+ const wasVisibleRef = useRef(false);
74
+ const themeDefaults = {
75
+ components: {},
76
+ };
77
+ // merge deeply the themeDefaults with the theme props and the displaySettings theme props (do not merge arrays, but replace them)
78
+ const theme = deepmerge(themeDefaults, props?.theme || {}, { arrayMerge: (destinationArray, sourceArray) => sourceArray });
79
+ props = {
80
+ ...props,
81
+ theme,
82
+ };
83
+ const subProps = {
84
+ messageUser: {
85
+ disableStyles,
86
+ theme: props.theme,
87
+ treePath,
88
+ primaryColor: colorPrimary,
89
+ primaryColorText: colorPrimaryText,
90
+ hideMessageTypeIndicatorText,
91
+ },
92
+ messageText: {
93
+ disableStyles,
94
+ theme: props.theme,
95
+ treePath,
96
+ primaryColor: colorPrimary,
97
+ primaryColorText: colorPrimaryText,
98
+ primaryAccentColor: colorPrimaryAccent,
99
+ primaryAccentColorText: colorPrimaryAccentText,
100
+ buttonBelowMessage,
101
+ },
102
+ suggestedQuestions: {
103
+ disableStyles,
104
+ theme: props.theme,
105
+ treePath,
106
+ primaryColor: colorPrimary,
107
+ },
108
+ attachmentContext: {
109
+ disableStyles,
110
+ theme: props.theme,
111
+ treePath,
112
+ },
113
+ loadingIndicator: {
114
+ disableStyles,
115
+ theme: props.theme,
116
+ treePath,
117
+ },
118
+ inspirationResultMessage: {
119
+ disableStyles,
120
+ theme: props.theme,
121
+ treePath,
122
+ },
123
+ productComparisonMessage: {
124
+ disableStyles,
125
+ theme: props.theme,
126
+ treePath,
127
+ },
128
+ productQueryMessage: {
129
+ disableStyles,
130
+ theme: props.theme,
131
+ treePath,
132
+ primaryColor: colorPrimary,
133
+ primaryColorText: colorPrimaryText,
134
+ },
135
+ };
136
+ const messagesEndRef = useRef(null);
137
+ const messagesContainerRef = useRef(null);
138
+ const headerRef = useRef(null);
139
+ const footerRef = useRef(null);
140
+ const chatRef = useRef(null);
141
+ // Ref for the mobile secondary panel — needed for swipe-to-dismiss measurements
142
+ const secondaryRef = useRef(null);
143
+ const [mobileProductInfoOpen, setMobileProductInfoOpen] = useState(false);
144
+ const [footerHeight, setFooterHeight] = useState(0);
145
+ const dropEnabled = store.features.imageSearch.enabled && !store.loading && !store.blocked && !store.currentChat?.sessionLimitReached;
146
+ const { fileInputRef, isDraggingFile, dragHandlers } = useChatFileUpload({
147
+ enabled: !!dropEnabled,
148
+ onUpload: (files) => controller.upload(files),
149
+ });
150
+ // productQuery messages are filtered out of the main chat render (they only drive the side-chat panel),
151
+ // so don't auto-scroll when one is added — otherwise clicking a product in the side chat scrolls the main thread.
152
+ const visibleChat = (store.currentChat?.chat || []).filter((m) => m.messageType !== 'productQuery');
153
+ const visibleChatLength = visibleChat.length;
154
+ const lastVisibleMessage = visibleChat[visibleChat.length - 1];
155
+ const { showNewMessages, setShowNewMessages, messagesOverflow, scrollToBottom, scrollToBottomIfNear } = useChatOverflow({
156
+ messagesContainerRef,
157
+ headerRef,
158
+ open: store.open,
159
+ loading: store.loading,
160
+ visibleChatLength,
161
+ lastVisibleMessage,
162
+ });
163
+ // Re-focus the chat input on desktop after a search completes.
164
+ // The input is disabled while loading, which causes the browser to drop focus.
165
+ // On mobile we intentionally skip this so the virtual keyboard dismisses.
166
+ // Only fire on the loading true → false transition — running on mount steals
167
+ // focus away from the Storybook controls whenever the story re-renders.
168
+ const prevLoadingRef = useRef(store.loading);
169
+ useEffect(() => {
170
+ if (prevLoadingRef.current && !store.loading && !isMobile && store.open) {
171
+ controller.focusInput();
172
+ }
173
+ prevLoadingRef.current = store.loading;
174
+ }, [store.loading]);
175
+ // const subProps: ChatSubProps = {};
176
+ const activeMessage = store.currentChat?.activeMessage;
177
+ // On mobile, only auto-open the secondary panel for the first productComparison
178
+ // message in the chat session. Subsequent comparison results show a "Show Details"
179
+ // button instead (handled in MessageText via sideChatLabel toggle).
180
+ const isFirstMobileComparison = (() => {
181
+ if (!isMobile || activeMessage?.messageType !== 'productComparison')
182
+ return true;
183
+ // If the user explicitly activated a comparison (via "Show Details" or the
184
+ // view-side-chat button), always allow it regardless of position in the chat
185
+ if (store.currentChat?.activeMessageId)
186
+ return true;
187
+ const comparisonMessages = (store.currentChat?.chat || []).filter((m) => m.messageType === 'productComparison');
188
+ return comparisonMessages.length <= 1;
189
+ })();
190
+ const sideChatTypes = isMobile
191
+ ? ['inspirationResult', ...(isFirstMobileComparison ? ['productComparison'] : []), ...(mobileProductInfoOpen ? ['productQuery'] : [])]
192
+ : ['inspirationResult', 'productComparison', 'productQuery'];
193
+ const shouldShowSideChat = activeMessage && sideChatTypes.includes(activeMessage?.messageType) && store.currentChat?.dismissedSideChatMessageId !== activeMessage.id;
194
+ const hasSideChat = !!shouldShowSideChat;
195
+ const styling = useMemo(() => mergeStyles({
196
+ mobile: isMobile,
197
+ offset,
198
+ hasSideChat,
199
+ footerHeight,
200
+ primaryColorBg: colorPrimary,
201
+ primaryColorFg: colorPrimaryText,
202
+ primaryAccentColorBg: colorPrimaryAccent,
203
+ primaryAccentColorFg: colorPrimaryAccentText,
204
+ secondaryAccentColorBg: colorSecondaryAccent,
205
+ secondaryAccentColorFg: colorSecondaryAccentText,
206
+ position: chatPosition,
207
+ }, chatDefaultStyles), [
208
+ isMobile,
209
+ offset,
210
+ hasSideChat,
211
+ footerHeight,
212
+ colorPrimary,
213
+ colorPrimaryText,
214
+ colorPrimaryAccent,
215
+ colorPrimaryAccentText,
216
+ colorSecondaryAccent,
217
+ colorSecondaryAccentText,
218
+ chatPosition,
219
+ ]);
220
+ // Lock body scroll while chat is open so touch/wheel scrolls don't leak to the page behind
221
+ useEffect(() => {
222
+ if (!store.open)
223
+ return;
224
+ const body = document.body;
225
+ const previousOverflow = body.style.overflow;
226
+ const previousOverscroll = body.style.overscrollBehavior;
227
+ body.style.overflow = 'hidden';
228
+ body.style.overscrollBehavior = 'contain';
229
+ return () => {
230
+ body.style.overflow = previousOverflow;
231
+ body.style.overscrollBehavior = previousOverscroll;
232
+ };
233
+ }, [store.open]);
234
+ // Close chat on Escape key (or dismiss side chat first when it's open)
235
+ useEffect(() => {
236
+ if (!store.open)
237
+ return;
238
+ const onKeyDown = (e) => {
239
+ if (e.key !== 'Escape')
240
+ return;
241
+ if (store.currentChat?.activeMessage && shouldShowSideChat) {
242
+ store.currentChat?.dismissSideChat();
243
+ }
244
+ else {
245
+ controller.handlers.button.click();
246
+ }
247
+ };
248
+ document.addEventListener('keydown', onKeyDown);
249
+ return () => document.removeEventListener('keydown', onKeyDown);
250
+ }, [store.open, shouldShowSideChat]);
251
+ // Track the primary footer height so the mobile secondary panel can sit above it
252
+ useEffect(() => {
253
+ const el = footerRef.current;
254
+ if (!el)
255
+ return;
256
+ const observer = new ResizeObserver((entries) => {
257
+ for (const entry of entries) {
258
+ setFooterHeight(entry.borderBoxSize?.[0]?.blockSize ?? entry.target.getBoundingClientRect().height);
259
+ }
260
+ });
261
+ observer.observe(el);
262
+ return () => observer.disconnect();
263
+ }, [store.open, store.currentChat?.isExpired]);
264
+ // Prevent the background page from scrolling while the chat is open on touch
265
+ // devices. iOS Safari (real iPad/iPhone) rubber-band-scrolls the body when a
266
+ // touchmove inside `.ss__chat__messages` reaches the top/bottom — and
267
+ // `overscroll-behavior: contain` is ignored there.
268
+ //
269
+ // We don't touch body styles (locking via `position: fixed` on `<body>` leaves
270
+ // iPad Safari in a stuck viewport state where the page can't scroll after the
271
+ // lock is released). Instead we install a `touchmove` handler that:
272
+ // - allows the touchmove if it's inside a scrollable region of the chat
273
+ // and that region isn't at its scroll edge in the swipe direction;
274
+ // - calls `preventDefault()` otherwise — which is what blocks both
275
+ // background scrolling and iOS rubber-band overscroll.
276
+ // Cleanup just removes the listeners, so nothing can leak into the page.
277
+ useEffect(() => {
278
+ if (!store.open)
279
+ return;
280
+ if (typeof document === 'undefined')
281
+ return;
282
+ let startX = 0;
283
+ let startY = 0;
284
+ let scrollEl = null;
285
+ // Walk up from the touch target to find the first ancestor inside the chat
286
+ // that is actually scrollable in either axis. Stop at the chat root so we
287
+ // never consider elements outside the chat.
288
+ const findScrollableInChat = (start) => {
289
+ const chatRoot = chatRef.current;
290
+ if (!chatRoot)
291
+ return null;
292
+ let el = start;
293
+ while (el && chatRoot.contains(el)) {
294
+ const style = getComputedStyle(el);
295
+ const scrollableY = (style.overflowY === 'auto' || style.overflowY === 'scroll') && el.scrollHeight > el.clientHeight;
296
+ const scrollableX = (style.overflowX === 'auto' || style.overflowX === 'scroll') && el.scrollWidth > el.clientWidth;
297
+ if (scrollableY || scrollableX) {
298
+ return el;
299
+ }
300
+ if (el === chatRoot)
301
+ break;
302
+ el = el.parentElement;
303
+ }
304
+ return null;
305
+ };
306
+ const onTouchStart = (e) => {
307
+ if (!e.touches[0])
308
+ return;
309
+ startX = e.touches[0].clientX;
310
+ startY = e.touches[0].clientY;
311
+ scrollEl = findScrollableInChat(e.target);
312
+ };
313
+ const onTouchMove = (e) => {
314
+ const target = e.target;
315
+ const chatRoot = chatRef.current;
316
+ const inChat = !!(chatRoot && target && chatRoot.contains(target));
317
+ // Touches outside the chat shouldn't scroll the background.
318
+ if (!inChat) {
319
+ if (e.cancelable)
320
+ e.preventDefault();
321
+ return;
322
+ }
323
+ // Inside the chat but no scrollable container — block to prevent body scroll.
324
+ if (!scrollEl) {
325
+ if (e.cancelable)
326
+ e.preventDefault();
327
+ return;
328
+ }
329
+ // Inside a scrollable container — only block when at the edge in the
330
+ // swipe direction, so internal scrolling continues to work. Detect the
331
+ // dominant axis so horizontally-scrollable rows (e.g. the facets row)
332
+ // also get to handle their own touch gestures.
333
+ const currentX = e.touches[0]?.clientX ?? startX;
334
+ const currentY = e.touches[0]?.clientY ?? startY;
335
+ const deltaX = currentX - startX;
336
+ const deltaY = currentY - startY;
337
+ const horizontal = Math.abs(deltaX) > Math.abs(deltaY);
338
+ if (horizontal) {
339
+ const scrollsX = scrollEl.scrollWidth > scrollEl.clientWidth;
340
+ if (!scrollsX) {
341
+ if (e.cancelable)
342
+ e.preventDefault();
343
+ return;
344
+ }
345
+ const atLeft = scrollEl.scrollLeft <= 0;
346
+ const atRight = scrollEl.scrollLeft + scrollEl.clientWidth >= scrollEl.scrollWidth - 1;
347
+ if ((atLeft && deltaX > 0) || (atRight && deltaX < 0)) {
348
+ if (e.cancelable)
349
+ e.preventDefault();
350
+ }
351
+ }
352
+ else {
353
+ const scrollsY = scrollEl.scrollHeight > scrollEl.clientHeight;
354
+ if (!scrollsY) {
355
+ if (e.cancelable)
356
+ e.preventDefault();
357
+ return;
358
+ }
359
+ const atTop = scrollEl.scrollTop <= 0;
360
+ const atBottom = scrollEl.scrollTop + scrollEl.clientHeight >= scrollEl.scrollHeight - 1;
361
+ if ((atTop && deltaY > 0) || (atBottom && deltaY < 0)) {
362
+ if (e.cancelable)
363
+ e.preventDefault();
364
+ }
365
+ }
366
+ };
367
+ document.addEventListener('touchstart', onTouchStart, { passive: true });
368
+ document.addEventListener('touchmove', onTouchMove, { passive: false });
369
+ return () => {
370
+ document.removeEventListener('touchstart', onTouchStart);
371
+ document.removeEventListener('touchmove', onTouchMove);
372
+ };
373
+ }, [store.open]);
374
+ const HistoryButton = (props) => (_jsx(Button, { className: "ss__chat__header__button--history", disabled: props.disabled, icon: {
375
+ icon: 'history',
376
+ title: 'Chat History',
377
+ } }));
378
+ const HistoryPopup = (props) => (_jsxs("div", { className: "ss__chat__history", children: [_jsxs("div", { className: "ss__chat__history__header", children: [_jsx("h4", { children: "History" }), _jsx("div", { className: "ss__chat__history__header__buttons", children: _jsx(Button, { content: "clear", disabled: store.loading || store.blocked, onClick: () => {
379
+ controller.store.clearHistory();
380
+ props.toggleOpen && props.toggleOpen();
381
+ } }) })] }), store.chats.length > 0 ? (_jsx("div", { className: "ss__chat__history__chats", children: store.chats
382
+ .slice()
383
+ .reverse()
384
+ .map((chat) => (_jsx("div", { className: "ss__chat__history__chats__chat", children: _jsxs(Button, { className: "ss__chat__history__chat__button", onClick: () => {
385
+ controller.store.switchChat(chat.id);
386
+ }, disabled: chat.id === store.currentChatId || store.loading || store.blocked, children: [_jsx("div", { className: "ss__chat__history__chat__button__text", children: (() => {
387
+ const lastUserMessage = [...chat.chat].reverse().find((message) => message.messageType === 'user');
388
+ if (!lastUserMessage)
389
+ return 'New Chat';
390
+ const text = lastUserMessage.text;
391
+ return text.length > 50 ? `${text.slice(0, 50)}...` : text;
392
+ })() }), _jsx("div", { className: "ss__chat__history__chat__button__date", children: chat.createdAt.toLocaleString() })] }) }, chat.id))) })) : null] }));
393
+ const FacetButton = (props) => _jsx(Button, { icon: props.open ? 'angle-down' : 'angle-up', children: props.label });
394
+ const getFacetButtonLabel = (facet) => {
395
+ const base = facet.label || facet.field;
396
+ // Slider facets show the active low-high range in the button when narrowed.
397
+ if (facet.type === 'range') {
398
+ const rangeFacet = facet;
399
+ const active = rangeFacet.active;
400
+ const range = rangeFacet.range;
401
+ if (active && range && (active.low !== range.low || active.high !== range.high)) {
402
+ return `${base} (${active.low ?? '*'}-${active.high ?? '*'})`;
403
+ }
404
+ return base;
405
+ }
406
+ // Count current selections from the urlManager (source of truth for live state).
407
+ // `value.filtered` reflects the server's snapshot at response time and goes stale
408
+ // once the user deselects locally.
409
+ const applied = (facet.values || []).filter((value) => {
410
+ if (!value)
411
+ return false;
412
+ const optionValue = 'low' in value && 'high' in value
413
+ ? `${value.low ?? '*'}:${value.high ?? '*'}`
414
+ : value.value || value.label;
415
+ return controller.store.isFacetSelected(facet.field, optionValue);
416
+ }).length;
417
+ return applied > 0 ? `${base} (${applied})` : base;
418
+ };
419
+ // Slider dropdown grows to fill the remaining chat width from its anchor,
420
+ // so the price range slider isn't cramped inside a 150px-wide dropdown.
421
+ const SliderFacetDropdown = (props) => {
422
+ const anchorRef = useRef(null);
423
+ const [width, setWidth] = useState(null);
424
+ useEffect(() => {
425
+ const compute = () => {
426
+ if (!anchorRef.current || !chatRef.current)
427
+ return;
428
+ const anchor = anchorRef.current.getBoundingClientRect();
429
+ const chat = chatRef.current.getBoundingClientRect();
430
+ const remaining = chat.right - anchor.left - 16;
431
+ setWidth(Math.max(220, remaining));
432
+ };
433
+ compute();
434
+ const ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(compute) : null;
435
+ if (ro && chatRef.current)
436
+ ro.observe(chatRef.current);
437
+ window.addEventListener('resize', compute);
438
+ return () => {
439
+ if (ro)
440
+ ro.disconnect();
441
+ window.removeEventListener('resize', compute);
442
+ };
443
+ }, []);
444
+ return (_jsx("div", { ref: anchorRef, className: "ss__chat__actions__facet ss__chat__actions__facet--range", children: _jsx(Dropdown, { usePortal: true, dropUp: true, button: _jsx(FacetButton, { label: props.label }), style: {
445
+ '.ss__dropdown__content': {
446
+ width: width ? `${width}px` : 'auto',
447
+ background: 'white',
448
+ boxShadow: '0px 3px 6px 0px rgba(0, 0, 0, 0.2)',
449
+ borderRadius: '6px',
450
+ },
451
+ }, children: _jsx("div", { className: "ss__chat__actions__facet__options", children: _jsx("div", { className: "ss__chat__actions__facet__slider", style: { padding: '12px 16px' }, children: _jsx(FacetSlider, { facet: props.facet, onChange: () => {
452
+ if (!multiselectFacets) {
453
+ // FacetSlider fires onChange before its urlManager update; defer
454
+ // so controller.search() reads the updated filter state. Force
455
+ // productSearch with the current filters so a slider tweak doesn't
456
+ // fall through to `general` when hasPendingFacetChanges happens to
457
+ // be false (e.g. the slider returned to the seeded range).
458
+ queueMicrotask(() => controller.search({
459
+ data: { requestType: 'productSearch', searchFilters: controller.store.searchFilters },
460
+ }));
461
+ }
462
+ } }) }) }) }) }));
463
+ };
464
+ // TODO: if starting a new chat and it's expired, this button would then disappear
465
+ if (controller.store.chatEnabled) {
466
+ wasVisibleRef.current = true;
467
+ }
468
+ // Hide the widget entirely when chat is disabled at bootstrap (silent disable).
469
+ // When chat becomes disabled mid-session, keep the widget mounted so the footer
470
+ // unavailable message stays visible (with the input disabled).
471
+ if (!controller.store.chatEnabled && !wasVisibleRef.current) {
472
+ return _jsx(_Fragment, {});
473
+ }
474
+ // Dismiss the secondary panel and clear any product attachments tied to the side-chat
475
+ // (discuss product flow), while preserving productSimilar/productComparison attachments.
476
+ const dismissSideChat = () => {
477
+ const productAttachmentsToRemove = (store.currentChat?.attachments.attached || []).filter((item) => item.type === 'product' && item.requestType !== 'productSimilar' && item.requestType !== 'productComparison');
478
+ productAttachmentsToRemove.forEach((item) => store.currentChat?.attachments.remove(item.id));
479
+ setMobileProductInfoOpen(false);
480
+ store.currentChat?.dismissSideChat();
481
+ };
482
+ const { swipeOffset, swipeAnimating, swipeHandlers } = useChatGestures({
483
+ panelRef: secondaryRef,
484
+ shouldShowSideChat: !!shouldShowSideChat,
485
+ activeMessageId: activeMessage?.id,
486
+ onDismiss: dismissSideChat,
487
+ });
488
+ const requestType = store.currentChat?.requestType;
489
+ const loadingVerbs = useMemo(() => {
490
+ switch (requestType) {
491
+ case 'productQuery':
492
+ return ['Thinking', 'Searching', 'Analyzing', 'Gathering details'];
493
+ case 'productSearch':
494
+ return ['Searching', 'Browsing catalog', 'Finding products', 'Curating results'];
495
+ case 'productComparison':
496
+ return ['Comparing', 'Analyzing', 'Evaluating', 'Weighing options'];
497
+ case 'imageSearch':
498
+ return ['Analyzing image', 'Identifying', 'Searching', 'Matching'];
499
+ case 'productSimilar':
500
+ return ['Finding similar items', 'Searching', 'Matching', 'Curating'];
501
+ case 'inspirationRequest':
502
+ return ['Brainstorming', 'Imagining', 'Curating', 'Inspiring'];
503
+ case 'general':
504
+ default:
505
+ return undefined;
506
+ }
507
+ }, [requestType]);
508
+ const isWelcomeState = (!store.currentChat?.chat || store.currentChat.chat.length === 0) && !!store.welcomeMessage && !store.currentChat?.isExpired;
509
+ return (_jsx(CacheProvider, { children: _jsxs(_Fragment, { children: [_jsxs("div", { ref: chatRef, className: classnames('ss__chat', {
510
+ 'ss__chat--open': store.open,
511
+ 'ss__chat--minimized': !store.open,
512
+ 'ss__chat--mobile': isMobile,
513
+ 'ss__chat--welcome': isWelcomeState,
514
+ }, className, internalClassName), ...styling, children: [!disableBubbleSuggestedQuestions && !store.open && !store.currentChat && store.suggestedQuestions?.length > 0 && (_jsx("div", { className: "ss__chat__suggested-questions", children: store.suggestedQuestions.map((question) => (_jsx("div", { className: "ss__chat__suggested-questions__item", onClick: () => {
515
+ controller.openChat(question);
516
+ }, children: question }, question))) })), _jsx("button", { type: "button", className: 'ss__chat__bubble', "aria-label": store.open ? 'Close chat' : 'Open chat', "aria-expanded": store.open, onClick: () => controller.handlers.button.click(), children: _jsx(Icon, { icon: "chat", title: "Open Chat" }) }), store.open && shouldShowSideChat && activeMessage ? (_jsxs("div", { ref: secondaryRef, className: classnames('ss__chat__secondary'), role: "region", "aria-label": "Conversation details", style: isMobile
517
+ ? {
518
+ // Touch swipe animations need to be inline to prevent visual jumps
519
+ transform: swipeOffset > 0 ? `translateY(${swipeOffset}px)` : undefined,
520
+ transition: swipeAnimating ? 'transform 0.3s ease-out' : 'none',
521
+ }
522
+ : undefined, children: [isMobile && (_jsx("div", { className: "ss__chat__secondary__drag-handle", ...swipeHandlers, children: _jsx("div", { className: "ss__chat__secondary__drag-handle__indicator" }) })), _jsxs("div", { className: 'ss__chat__header', onTouchStart: isMobile ? swipeHandlers.onTouchStart : undefined, onTouchMove: isMobile ? swipeHandlers.onTouchMove : undefined, onTouchEnd: isMobile ? swipeHandlers.onTouchEnd : undefined, children: [_jsxs("div", { className: "ss__chat__header__title", children: [_jsx("div", { className: "ss__chat__header__title__primary", children: {
523
+ inspirationResult: 'Inspiration Scenarios',
524
+ productComparison: 'Product Comparison',
525
+ productQuery: '',
526
+ }[activeMessage.messageType] || null }), _jsx("div", { className: "ss__chat__header__title__secondary", children: {
527
+ inspirationResult: 'Choose a style direction to explore',
528
+ productComparison: `Comparing ${activeMessage?.searchResults?.length || ''} products`,
529
+ productQuery: '',
530
+ }[activeMessage.messageType] || null })] }), _jsx("div", { className: "ss__chat__header__buttons", children: _jsx(Button, { className: "ss__chat__header__button--close", "aria-label": "Close chat", icon: { icon: 'close2', title: 'Close Chat' }, onClick: () => dismissSideChat() }) })] }), _jsx("div", { className: "ss__chat__content", children: _jsx("div", { className: 'ss__chat__messages', children: {
531
+ inspirationResult: (_jsx(ChatInspirationResultMessage, { ...subProps.inspirationResultMessage, chatItem: activeMessage, controller: controller, onProductQuickView: isMobile ? () => setMobileProductInfoOpen(true) : undefined })),
532
+ productComparison: (_jsx(ChatProductComparisonMessage, { ...subProps.productComparisonMessage, chatItem: activeMessage, controller: controller })),
533
+ productQuery: (_jsx(ChatProductQueryMessage, { ...subProps.productQueryMessage, chatItem: activeMessage, controller: controller, displayFields: controller.config.settings?.quickview?.displayFields, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
534
+ }[activeMessage.messageType] || null }) })] })) : null, store.open ? (_jsxs("div", { className: 'ss__chat__primary',
535
+ // On mobile, interacting with the primary chat (header or anywhere within)
536
+ // dismisses the secondary panel. Capture phase so it fires even when an
537
+ // inner control stops propagation.
538
+ onClickCapture: isMobile && shouldShowSideChat ? () => dismissSideChat() : undefined, children: [_jsxs("div", { className: 'ss__chat__header', children: [_jsxs("div", { className: "ss__chat__header__title", children: [logo ? _jsx(Image, { className: "ss__chat__header__title__logo", src: logo, alt: title || 'Chat logo' }) : null, _jsxs("div", { className: "ss__chat__header__title__text", children: [title ? _jsx("div", { className: "ss__chat__header__title__text__primary", children: title }) : null, subtitle ? _jsx("div", { className: "ss__chat__header__title__text__secondary", children: subtitle }) : null] })] }), _jsxs("div", { className: "ss__chat__header__buttons", children: [_jsx(Button
539
+ // disabled={store.currentChat?.chat && store.currentChat.chat.length <= 1}
540
+ , {
541
+ // disabled={store.currentChat?.chat && store.currentChat.chat.length <= 1}
542
+ className: "ss__chat__header__button--new", "aria-label": "New chat", icon: { icon: controller.store.initChatLoading ? 'spinner' : 'plus2', title: 'New Chat' }, onClick: () => controller.store.createChat() }), store.chats.length > 1 && (_jsx(Dropdown, { disabled: store.loading || store.blocked, className: "ss__chat__header__dropdown-history", button: _jsx(HistoryButton, {}), children: _jsx(HistoryPopup, {}) })), _jsx(Button, { className: "ss__chat__header__button--close", "aria-label": "Close chat", icon: { icon: 'close2', title: 'Close Chat' }, onClick: () => controller.handlers.button.click() })] })] }), _jsxs("div", { className: "ss__chat__content", children: [(() => {
543
+ const feedbackAfterMessages = controller.config.settings?.feedbackAfterMessages;
544
+ const systemMessages = (store.currentChat?.chat || []).filter((msg) => msg.messageType !== 'user' && msg.messageType !== 'productQuery');
545
+ const currentRating = store.currentChat?.feedback.rating;
546
+ const hasRated = !!currentRating;
547
+ const shouldShowFeedback = feedbackAfterMessages &&
548
+ systemMessages.length >= feedbackAfterMessages &&
549
+ !store.currentChat?.feedback.dismissed &&
550
+ (!hasRated || store.currentChat?.feedback.justGiven);
551
+ return shouldShowFeedback ? (_jsxs("div", { className: "ss__chat__session-feedback", children: [_jsx("div", { className: "ss__chat__session-feedback__icon", children: _jsx(Icon, { icon: "chat", size: "16px" }) }), _jsx("span", { className: "ss__chat__session-feedback__label", children: hasRated ? 'Thank you for your feedback' : "How's your experience so far?" }), _jsxs("div", { className: `ss__chat__session-feedback__actions${hasRated ? ' ss__chat__session-feedback__actions--rated' : ''}`, children: [(!hasRated || currentRating === 'UP') && (_jsx("span", { onClick: () => !hasRated && controller.handleFeedback('UP'), children: _jsx(Icon, { icon: 'thumbs-up', size: "16px", title: 'Thumbs Up' }) })), (!hasRated || currentRating === 'DOWN') && (_jsx("span", { onClick: () => !hasRated && controller.handleFeedback('DOWN'), children: _jsx(Icon, { icon: 'thumbs-down', size: "16px", title: 'Thumbs Down' }) }))] }), !hasRated && (_jsx("span", { className: "ss__chat__session-feedback__close", onClick: () => {
552
+ if (store.currentChat) {
553
+ store.currentChat.feedback.dismissed = true;
554
+ store.currentChat.save();
555
+ }
556
+ }, children: _jsx(Icon, { icon: "close-thin", size: "14px" }) }))] })) : null;
557
+ })(), _jsx("div", { ref: headerRef, className: classnames('ss__chat__content__header', {
558
+ 'ss__chat__content__header--overlay': messagesOverflow,
559
+ }), children: store.currentChat?.comparisons.compared && store.currentChat.comparisons.compared.length > 0 && (_jsxs("div", { className: 'ss__chat__content__header__comparisons', children: [_jsxs("div", { className: 'ss__chat__content__header__comparisons__header', children: [_jsxs("div", { className: 'ss__chat__content__header__comparisons__header__title', children: [_jsx(Icon, { className: 'ss__chat__content__header__comparisons__header__title__icon', icon: 'clipboard' }), _jsxs("span", { className: 'ss__chat__content__header__comparisons__header__title__text', children: ["Compare Products (", store.currentChat?.comparisons.compared.length, "/", store.currentChat?.comparisons.maxItems, ")"] })] }), _jsx("div", { className: 'ss__chat__content__header__comparisons__header__actions', children: _jsx(Button, { onClick: () => store.currentChat?.comparisons.reset(), children: "clear" }) })] }), _jsxs("div", { className: 'ss__chat__content__header__comparisons__content', children: [_jsx("div", { className: 'ss__chat__content__header__comparisons__content__items', children: Array.from({ length: store.currentChat?.comparisons.maxItems }).map((_, index) => {
560
+ const comparisonItem = store.currentChat?.comparisons.compared[index];
561
+ return (_jsx("div", { className: classnames('ss__chat__content__header__comparisons__content__comparison', {
562
+ 'ss__chat__content__header__comparisons__content__comparison--placeholder': !comparisonItem,
563
+ }), children: comparisonItem ? (_jsxs(_Fragment, { children: [_jsx(Image
564
+ // onClick={() => {
565
+ // controller?.productQuickView(product as any);
566
+ // }}
567
+ , {
568
+ // onClick={() => {
569
+ // controller?.productQuickView(product as any);
570
+ // }}
571
+ alt: (comparisonItem?.result?.display || comparisonItem?.result)?.mappings?.core?.name || '', src: (comparisonItem?.result?.display || comparisonItem?.result)?.mappings?.core?.imageUrl ||
572
+ (comparisonItem?.result?.display || comparisonItem?.result)?.mappings?.core?.parentImageUrl ||
573
+ '' }), _jsx("div", { className: "ss__chat__content__header__comparisons__content__comparison__remove", onClick: () => {
574
+ store.currentChat?.comparisons.remove(comparisonItem.result.id);
575
+ }, children: _jsx(Icon, { icon: 'close-thin', size: '12px' }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Icon, { icon: 'plus-thin' }), _jsx("div", { className: 'ss__chat__content__header__comparisons__content__comparison--placeholder__text', children: "Add" })] })) }, index));
576
+ }) }), _jsx("div", { className: classnames('ss__chat__content__header__comparisons__action', {
577
+ 'ss__chat__content__header__comparisons__action--hidden': (store.currentChat?.comparisons.compared.length || 0) < 2,
578
+ }), children: _jsx(Button, { onClick: () => controller.search(), icon: { icon: 'compare', title: 'Compare' }, children: "Compare" }) })] })] })) }), _jsxs("div", { className: 'ss__chat__messages', ref: messagesContainerRef, role: "log", "aria-live": "polite", "aria-relevant": "additions", "aria-label": "Chat messages", style: visibleChatLength ? { scrollbarGutter: 'stable' } : undefined, children: [(!store.currentChat?.chat || store.currentChat.chat.length === 0) && store.welcomeMessage && !store.currentChat?.isExpired && (_jsxs("div", { className: "ss__chat__welcome", children: [_jsx("div", { className: "ss__chat__welcome__message", children: store.welcomeMessage }), _jsx(ChatSuggestedQuestions, { ...subProps.suggestedQuestions, questions: store.suggestedQuestions, controller: controller })] })), store.currentChat?.chat
579
+ .filter((chatItem) => chatItem.messageType !== 'productQuery')
580
+ .map((chatItem) => {
581
+ const showAvatar = !!(avatarCharacter || avatarImage) && chatItem.messageType !== 'user';
582
+ const messageContent = {
583
+ user: (_jsx(ChatMessageUser, { ...subProps.messageUser, chatItem: chatItem, controller: controller, onProductQuickView: isMobile ? () => setMobileProductInfoOpen(true) : undefined, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
584
+ text: (_jsx(ChatMessageText, { ...subProps.messageText, chatItem: chatItem, controller: controller, scrollToBottom: scrollToBottomIfNear, onProductQuickView: isMobile ? () => setMobileProductInfoOpen(true) : undefined, sideChatOpen: !!shouldShowSideChat, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
585
+ content: (_jsx(ChatMessageText, { ...subProps.messageText, chatItem: chatItem, controller: controller, scrollToBottom: scrollToBottomIfNear, onProductQuickView: isMobile ? () => setMobileProductInfoOpen(true) : undefined, sideChatOpen: !!shouldShowSideChat, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
586
+ productSearchResult: (_jsx(ChatMessageText, { ...subProps.messageText, chatItem: chatItem, controller: controller, scrollToBottom: scrollToBottomIfNear, onProductQuickView: isMobile ? () => setMobileProductInfoOpen(true) : undefined, sideChatOpen: !!shouldShowSideChat, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
587
+ inspirationResult: (_jsx(ChatMessageText, { ...subProps.messageText, chatItem: chatItem, controller: controller, scrollToBottom: scrollToBottomIfNear, onProductQuickView: isMobile ? () => setMobileProductInfoOpen(true) : undefined, sideChatOpen: !!shouldShowSideChat, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
588
+ productAnswer: (_jsx(ChatMessageText, { ...subProps.messageText, chatItem: chatItem, controller: controller, scrollToBottom: scrollToBottomIfNear, onProductQuickView: isMobile ? () => setMobileProductInfoOpen(true) : undefined, sideChatOpen: !!shouldShowSideChat, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
589
+ productComparison: (() => {
590
+ // On mobile, only the first productComparison in the session
591
+ // auto-opens the secondary panel. Subsequent ones get a
592
+ // prominent "Show Details" button instead.
593
+ const comparisonMessages = (store.currentChat?.chat || []).filter((m) => m.messageType === 'productComparison');
594
+ const isFirst = comparisonMessages.length > 0 && comparisonMessages[0].id === chatItem.id;
595
+ return (_jsx(ChatMessageText, { ...subProps.messageText, chatItem: chatItem, controller: controller, scrollToBottom: scrollToBottomIfNear, onProductQuickView: isMobile ? () => setMobileProductInfoOpen(true) : undefined, showDetailsButton: isMobile && !isFirst, sideChatOpen: !!shouldShowSideChat, primaryColor: colorPrimary, primaryColorText: colorPrimaryText }));
596
+ })(),
597
+ productRecommendation: (_jsx(ChatMessageText, { ...subProps.messageText, chatItem: chatItem, controller: controller, scrollToBottom: scrollToBottomIfNear, onProductQuickView: isMobile ? () => setMobileProductInfoOpen(true) : undefined, sideChatOpen: !!shouldShowSideChat, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
598
+ actions: (_jsx(ChatSuggestedQuestions, { actions: chatItem.actions, controller: controller })),
599
+ errorResponse: (_jsx(ChatMessageText, { ...subProps.messageText, chatItem: chatItem, controller: controller, scrollToBottom: scrollToBottomIfNear, sideChatOpen: !!shouldShowSideChat, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
600
+ topicDrift: (_jsx(ChatMessageText, { ...subProps.messageText, chatItem: chatItem, controller: controller, scrollToBottom: scrollToBottomIfNear, sideChatOpen: !!shouldShowSideChat, primaryColor: colorPrimary, primaryColorText: colorPrimaryText })),
601
+ productQuery: null,
602
+ }[chatItem.messageType] || null;
603
+ return (_jsxs("div", { className: classnames(`ss__chat__message`, `ss__chat__message--${chatItem.messageType}`, {
604
+ 'ss__chat__message--with-avatar': showAvatar,
605
+ }), children: [showAvatar && (_jsx("div", { className: classnames('ss__chat__message__avatar', {
606
+ 'ss__chat__message__avatar--image': !!avatarImage,
607
+ }), "aria-hidden": "true", children: avatarImage ? _jsx(Image, { src: avatarImage, alt: "" }) : avatarCharacter })), showAvatar ? _jsx("div", { className: "ss__chat__message__content", children: messageContent }) : messageContent] }, chatItem.id));
608
+ }), _jsx("div", { className: "ss__chat__messages__end", ref: messagesEndRef }), showNewMessages && messagesOverflow && (_jsxs("div", { className: "ss__chat__new-messages", onClick: () => {
609
+ scrollToBottom();
610
+ setShowNewMessages(false);
611
+ }, children: [_jsx(Icon, { icon: "angle-down", size: "12px" }), _jsx("span", { children: "New messages" })] }))] }), _jsx(ChatLoadingIndicator, { ...subProps.loadingIndicator, loading: store.loading, verbs: loadingVerbs }), !store.currentChat?.isExpired ? (_jsxs("div", { className: "ss__chat__content__footer", ref: footerRef, ...dragHandlers, children: [(store.error || store.chatEnabled === false) && (_jsx("div", { className: "ss__chat__error", children: store.error?.message || CHAT_UNAVAILABLE_MESSAGE })), store.currentChat?.sessionLimitReached && (_jsxs("div", { className: 'ss__chat__topic-drift', children: [_jsx(Icon, { icon: "info", size: "18px", className: 'ss__chat__topic-drift__icon--info' }), _jsxs("div", { className: 'ss__chat__topic-drift__text', children: [_jsx("span", { children: "Chat is currently unavailable due to high volume." }), _jsx("span", { children: "In the meantime, feel free to use the search bar above to find what you need!" })] }), _jsx(Button, { className: 'ss__chat__topic-drift__button', onClick: () => {
612
+ controller.store.createChat();
613
+ }, children: "New Session" })] })), store.facets && store.facets.length > 0 && (_jsx("div", { className: 'ss__chat__actions', children: _jsxs("div", { className: "ss__chat__actions__wrap", children: [_jsxs("div", { className: "ss__chat__actions__facets-header", children: [_jsx("div", { className: "ss__chat__actions--title", children: "Filter by:" }), multiselectFacets && store.hasPendingFacetChanges && (_jsx("div", { className: 'ss__chat__actions__facets-apply ss__chat__actions__facets-apply--active', children: _jsx(Button, { onClick: () => {
614
+ controller.search();
615
+ }, children: store.pendingFacetCount > 0 ? `Apply (${store.pendingFacetCount})` : 'Clear facets' }) }))] }), _jsx("div", { className: "ss__chat__actions--facets", children: store.facets.slice(0, 10).map((facet, idx) => {
616
+ // range/slider facets render via FacetSlider; everything else needs at least one value to be useful
617
+ if (facet.type !== 'range' && !facet.values?.length)
618
+ return null;
619
+ if (facet.type === 'range') {
620
+ return _jsx(SliderFacetDropdown, { facet: facet, label: getFacetButtonLabel(facet) }, idx);
621
+ }
622
+ return (_jsx("div", { className: `ss__chat__actions__facet ss__chat__actions__facet--${facet.type}`, children: _jsx(Dropdown, { usePortal: true, dropUp: true, boundaryRef: chatRef, button: _jsx(FacetButton, { label: getFacetButtonLabel(facet) }), style: {
623
+ '.ss__dropdown__content': {
624
+ width: '150px',
625
+ maxHeight: '200px',
626
+ overflowY: 'auto',
627
+ background: 'white',
628
+ boxShadow: '0px 3px 6px 0px rgba(0, 0, 0, 0.2)',
629
+ borderRadius: '6px',
630
+ ...(multiselectFacets
631
+ ? {
632
+ '.ss__chat__actions__facet__option--checkbox': {
633
+ display: 'flex',
634
+ alignItems: 'center',
635
+ gap: '8px',
636
+ padding: '6px 10px',
637
+ cursor: 'pointer',
638
+ width: '100%',
639
+ boxSizing: 'border-box',
640
+ background: '#fff',
641
+ border: 'none',
642
+ borderBottom: '1px solid #f0f0f0',
643
+ '&:hover': {
644
+ background: new Colour(colorPrimary).lightenHex(0.95),
645
+ },
646
+ '&:last-child': {
647
+ borderBottom: 'none',
648
+ },
649
+ '.ss__chat__actions__facet__option__checkbox': {
650
+ width: '16px',
651
+ height: '16px',
652
+ borderRadius: '3px',
653
+ border: '2px solid #ccc',
654
+ display: 'flex',
655
+ alignItems: 'center',
656
+ justifyContent: 'center',
657
+ flexShrink: 0,
658
+ '&.ss__chat__actions__facet__option__checkbox--checked': {
659
+ background: colorPrimary,
660
+ borderColor: colorPrimary,
661
+ color: colorPrimaryText,
662
+ svg: {
663
+ fill: colorPrimaryText,
664
+ stroke: colorPrimaryText,
665
+ },
666
+ },
667
+ },
668
+ '.ss__chat__actions__facet__option__label': {
669
+ fontSize: '14px',
670
+ color: '#333',
671
+ flex: '1 1 auto',
672
+ textAlign: 'left',
673
+ },
674
+ },
675
+ }
676
+ : {
677
+ '.ss__button': {
678
+ width: '100%',
679
+ border: 'none',
680
+ borderRadius: 0,
681
+ boxSizing: 'border-box',
682
+ background: '#fff',
683
+ '&:hover': {
684
+ background: new Colour(colorPrimary).lightenHex(0.95),
685
+ },
686
+ '&.ss__chat__actions__facet__option--selected': {
687
+ fontWeight: 'bold',
688
+ },
689
+ },
690
+ }),
691
+ },
692
+ }, children: _jsx("div", { className: "ss__chat__actions__facet__options", children: facet.type === 'range-buckets'
693
+ ? facet.values.map((option) => {
694
+ const rangeOption = option;
695
+ const optionValue = `${rangeOption.low ?? '*'}:${rangeOption.high ?? '*'}`;
696
+ if (multiselectFacets) {
697
+ const isSelected = controller.store.isFacetSelected(facet.field, optionValue);
698
+ return (_jsxs("div", { className: "ss__chat__actions__facet__option--checkbox", onClick: () => {
699
+ if (isSelected) {
700
+ controller.store.removeFacet(facet.field, optionValue);
701
+ }
702
+ else {
703
+ controller.store.addFacet({
704
+ key: facet.field,
705
+ value: optionValue,
706
+ });
707
+ }
708
+ }, children: [_jsx("div", { className: classnames('ss__chat__actions__facet__option__checkbox', {
709
+ 'ss__chat__actions__facet__option__checkbox--checked': isSelected,
710
+ }), children: isSelected && _jsx(Icon, { icon: "check-thin", size: "10px" }) }), _jsx("span", { className: "ss__chat__actions__facet__option__label", children: rangeOption.label })] }, optionValue));
711
+ }
712
+ return (_jsx(Button, { className: classnames({
713
+ 'ss__chat__actions__facet__option--selected': controller.store.isFacetSelected(facet.field, optionValue),
714
+ }), onClick: () => {
715
+ // Non-multiselect: clicking an already-selected value toggles it off.
716
+ // `addFacet` is idempotent against an existing urlManager value, so without
717
+ // the toggle the state wouldn't change, `hasPendingFacetChanges` would stay
718
+ // false, and the params getter would fall through to `general`.
719
+ if (controller.store.isFacetSelected(facet.field, optionValue)) {
720
+ controller.store.removeFacet(facet.field, optionValue);
721
+ }
722
+ else {
723
+ controller.store.addFacet({
724
+ key: facet.field,
725
+ value: optionValue,
726
+ });
727
+ }
728
+ // Force productSearch with the current filter state rather than relying
729
+ // on the params getter's hasPendingFacetChanges promotion — a facet click
730
+ // in the chat is unambiguously a search intent.
731
+ controller.search({
732
+ data: { requestType: 'productSearch', searchFilters: controller.store.searchFilters },
733
+ });
734
+ }, children: rangeOption.label }, optionValue));
735
+ })
736
+ : facet.values.map((option) => {
737
+ const valueOption = option;
738
+ const optionValue = valueOption.value || valueOption.label;
739
+ if (multiselectFacets) {
740
+ const isSelected = controller.store.isFacetSelected(facet.field, optionValue);
741
+ return (_jsxs("div", { className: "ss__chat__actions__facet__option--checkbox", onClick: () => {
742
+ if (isSelected) {
743
+ controller.store.removeFacet(facet.field, optionValue);
744
+ }
745
+ else {
746
+ controller.store.addFacet({
747
+ key: facet.field,
748
+ value: optionValue,
749
+ });
750
+ }
751
+ }, children: [_jsx("div", { className: classnames('ss__chat__actions__facet__option__checkbox', {
752
+ 'ss__chat__actions__facet__option__checkbox--checked': isSelected,
753
+ }), children: isSelected && _jsx(Icon, { icon: "check-thin", size: "10px" }) }), _jsx("span", { className: "ss__chat__actions__facet__option__label", children: valueOption.label })] }, optionValue));
754
+ }
755
+ return (_jsx(Button, { className: classnames({
756
+ 'ss__chat__actions__facet__option--selected': controller.store.isFacetSelected(facet.field, optionValue),
757
+ }), onClick: () => {
758
+ // Non-multiselect: clicking an already-selected value toggles it off.
759
+ // `addFacet` is idempotent against an existing urlManager value, so without
760
+ // the toggle the state wouldn't change, `hasPendingFacetChanges` would stay
761
+ // false, and the params getter would fall through to `general`.
762
+ if (controller.store.isFacetSelected(facet.field, optionValue)) {
763
+ controller.store.removeFacet(facet.field, optionValue);
764
+ }
765
+ else {
766
+ controller.store.addFacet({
767
+ key: facet.field,
768
+ value: optionValue,
769
+ });
770
+ }
771
+ // Force productSearch with the current filter state rather than relying
772
+ // on the params getter's hasPendingFacetChanges promotion — a facet click
773
+ // in the chat is unambiguously a search intent.
774
+ controller.search({
775
+ data: { requestType: 'productSearch', searchFilters: controller.store.searchFilters },
776
+ });
777
+ }, children: valueOption.label }, optionValue));
778
+ }) }) }, facet.field) }, idx));
779
+ }) })] }) })), (() => {
780
+ const activeComparisonSearchResults = shouldShowSideChat && activeMessage?.messageType === 'productComparison'
781
+ ? activeMessage.searchResults || []
782
+ : null;
783
+ const showCommittedComparisons = !activeComparisonSearchResults &&
784
+ store.currentChat?.comparisons.committed &&
785
+ store.currentChat.comparisons.committed.length > 0 &&
786
+ (activeMessage?.messageType === 'user' ||
787
+ activeMessage?.messageType === 'productComparison' ||
788
+ activeMessage?.messageType === 'productQuery');
789
+ const visibleAttachments = store.currentChat?.attachments.attached.filter((item) => item.state === 'attached' || item.state === 'active' || item.state === 'loading' || item.state === 'error') || [];
790
+ const productAttachments = visibleAttachments.filter((item) => item.type === 'product' &&
791
+ item.requestType !== 'productSimilar' &&
792
+ item.requestType !== 'productComparison');
793
+ const imageAttachments = visibleAttachments.filter((item) => item.type === 'image');
794
+ const comparisonItems = activeComparisonSearchResults
795
+ ? activeComparisonSearchResults.map((result) => {
796
+ const d = result?.display || result;
797
+ return {
798
+ id: result?.id,
799
+ name: d?.mappings?.core?.name || '',
800
+ imageUrl: d?.mappings?.core?.thumbnailImageUrl || d?.mappings?.core?.imageUrl || d?.mappings?.core?.parentImageUrl || '',
801
+ onClick: () => {
802
+ controller.productQuickView(result);
803
+ if (isMobile)
804
+ setMobileProductInfoOpen(true);
805
+ },
806
+ };
807
+ })
808
+ : showCommittedComparisons
809
+ ? (store.currentChat?.comparisons.committed || []).map((comparisonItem) => {
810
+ const d = comparisonItem?.result?.display || comparisonItem?.result;
811
+ return {
812
+ id: comparisonItem.result?.id,
813
+ name: d?.mappings?.core?.name || '',
814
+ imageUrl: d?.mappings?.core?.thumbnailImageUrl || d?.mappings?.core?.imageUrl || d?.mappings?.core?.parentImageUrl || '',
815
+ onClick: () => {
816
+ controller.productQuickView(comparisonItem.result);
817
+ if (isMobile)
818
+ setMobileProductInfoOpen(true);
819
+ },
820
+ };
821
+ })
822
+ : [];
823
+ const productItems = productAttachments.map((item) => {
824
+ const remove = () => {
825
+ store.currentChat?.attachments.remove(item.id);
826
+ setMobileProductInfoOpen(false);
827
+ store.currentChat?.dismissSideChat();
828
+ };
829
+ return {
830
+ id: item.id,
831
+ name: item.name || '',
832
+ imageUrl: item.thumbnailUrl || '',
833
+ onClick: remove,
834
+ onRemove: remove,
835
+ };
836
+ });
837
+ const imageItems = imageAttachments.map((item) => ({
838
+ id: item.id,
839
+ name: item.fileName || 'Image',
840
+ imageUrl: item.base64 || item.thumbnailUrl || '',
841
+ isLoading: item.state === 'loading',
842
+ hasError: !!item.error,
843
+ errorMessage: item.error?.message,
844
+ onRemove: () => store.currentChat?.attachments.remove(item.id),
845
+ }));
846
+ const productTitle = productItems.length > 1 ? 'Compare these products' : 'Ask about this product';
847
+ const hasImageError = imageItems.some((item) => item.hasError);
848
+ const imageTitle = imageItems.length > 0 && !hasImageError ? 'Find products similar to this image:' : '';
849
+ return (_jsxs(_Fragment, { children: [comparisonItems.length > 0 && (_jsx(ChatAttachmentContext, { ...subProps.attachmentContext, title: 'Compare these products', items: comparisonItems, onClose: () => {
850
+ store.currentChat?.comparisons.resetCommitted();
851
+ store.currentChat?.dismissSideChat();
852
+ } })), productItems.length > 0 && (_jsx(ChatAttachmentContext, { ...subProps.attachmentContext, title: productTitle, items: productItems, onClose: () => {
853
+ productAttachments.forEach((item) => store.currentChat?.attachments.remove(item.id));
854
+ setMobileProductInfoOpen(false);
855
+ store.currentChat?.dismissSideChat();
856
+ } })), imageItems.length > 0 && _jsx(ChatAttachmentContext, { ...subProps.attachmentContext, title: imageTitle, items: imageItems })] }));
857
+ })(), (() => {
858
+ const drift = store.currentChat?.topicDrift;
859
+ if (!drift)
860
+ return null;
861
+ // recommendedAction is the prescription; driftType is the diagnosis.
862
+ // Hide the banner when the backend says to keep flowing, or when no drift was detected.
863
+ if (drift.recommendedAction === 'CONTINUE' || drift.driftType === 'NO_DRIFT')
864
+ return null;
865
+ const isScopeRedirect = drift.recommendedAction === 'SCOPE_REDIRECT';
866
+ const primaryText = isScopeRedirect ? "I'm here to help with shopping" : 'Looking for something new?';
867
+ const secondaryText = isScopeRedirect
868
+ ? 'Try asking about products, comparisons, or recommendations'
869
+ : 'Start a fresh session for better assistance, or keep going in this one?';
870
+ const buttonText = isScopeRedirect ? '' : 'New Session';
871
+ return (_jsxs("div", { className: 'ss__chat__topic-drift', children: [_jsx(Icon, { icon: "info", size: "18px", className: 'ss__chat__topic-drift__icon--info' }), _jsxs("div", { className: 'ss__chat__topic-drift__text', children: [_jsx("span", { children: primaryText }), _jsx("span", { children: secondaryText })] }), buttonText && (_jsx(Button, { className: 'ss__chat__topic-drift__button', onClick: () => {
872
+ if (isScopeRedirect) {
873
+ store.currentChat?.dismissTopicDrift();
874
+ return;
875
+ }
876
+ // Capture image attachments from the current chat before handleTopicDrift /
877
+ // createChat tear down the conversation — an imageSearch that drifted needs
878
+ // the same image attached to the carried-over message in the new session,
879
+ // otherwise params would fall back to a `general` request without the image.
880
+ const previousImageAttachments = (store.currentChat?.attachments.attached || [])
881
+ .filter((item) => item.type === 'image' && item.state !== 'error')
882
+ .map((item) => {
883
+ const img = item;
884
+ return {
885
+ type: 'image',
886
+ base64: img.base64,
887
+ fileName: img.fileName,
888
+ imageId: img.imageId,
889
+ imageUrl: img.imageUrl,
890
+ thumbnailUrl: img.thumbnailUrl,
891
+ // Already uploaded — skip the 'loading' default state.
892
+ state: 'attached',
893
+ };
894
+ });
895
+ const messageText = store.currentChat?.handleTopicDrift();
896
+ if (messageText) {
897
+ controller.store.createChat();
898
+ previousImageAttachments.forEach((cfg) => {
899
+ controller.store.currentChat?.attachments.add(cfg);
900
+ });
901
+ controller.search({ data: { message: messageText } });
902
+ }
903
+ }, children: buttonText })), _jsx("span", { onClick: () => {
904
+ store.currentChat?.dismissTopicDrift();
905
+ }, children: _jsx(Icon, { icon: "close-thin", size: "14px", className: 'ss__chat__topic-drift__icon--close' }) })] }));
906
+ })(), _jsxs("div", { className: 'ss__chat__input', children: [_jsxs("div", { className: 'ss__chat__input__input', children: [_jsx("input", { type: "text", name: "ss-chat-input", disabled: store.loading || store.blocked || store.currentChat?.sessionLimitReached || store.chatEnabled === false, placeholder: (() => {
907
+ const comparedCount = store.currentChat?.comparisons.compared.length || 0;
908
+ const committedCount = store.currentChat?.comparisons.committed.length || 0;
909
+ const attached = store.currentChat?.attachments.attached.filter((item) => item.state === 'attached' || item.state === 'active') || [];
910
+ const attachedProducts = attached.filter((item) => item.type === 'product');
911
+ const attachedImages = attached.filter((item) => item.type === 'image' && !item.error);
912
+ if (attachedProducts.length === 1) {
913
+ return 'Ask about this product...';
914
+ }
915
+ if (comparedCount > 1 || attachedProducts.length > 1) {
916
+ return 'What would you like to compare?';
917
+ }
918
+ if (committedCount > 0) {
919
+ return 'Ask about the compared products...';
920
+ }
921
+ if (attachedImages.length > 0) {
922
+ return 'Ask about this image...';
923
+ }
924
+ if (comparedCount === 1) {
925
+ return 'Add another product to compare...';
926
+ }
927
+ return 'Type your message...';
928
+ })(), onInput: (e) => controller.handlers.input.input(e), onKeyDown: (e) => {
929
+ controller.handlers.input.enterKey(e);
930
+ if (e.keyCode === 13 && isMobile && mobileProductInfoOpen) {
931
+ setMobileProductInfoOpen(false);
932
+ }
933
+ }, value: controller.store.inputValue }), store.features.imageSearch.enabled && (_jsxs(_Fragment, { children: [_jsx(Button, { className: 'ss__chat__upload-button', disabled: store.loading || store.blocked || store.currentChat?.sessionLimitReached || store.chatEnabled === false, onClick: () => fileInputRef.current?.click(), icon: { icon: 'image', title: 'Upload Image' } }), _jsx("input", { ref: fileInputRef, onChange: async (e) => {
934
+ await controller.upload(e.target.files);
935
+ // reset value
936
+ e.target.value = '';
937
+ }, type: "file", accept: "image/*", className: "ss__chat__input__input__file" })] }))] }), _jsx("div", { className: 'ss__chat__input__actions', children: (() => {
938
+ const hasImageAttachment = (store.currentChat?.attachments.attached || []).some((item) => item.type === 'image' && !item.error);
939
+ const messageEmpty = !controller.store.inputValue.trim();
940
+ const sendDisabled = store.blocked ||
941
+ store.currentChat?.sessionLimitReached ||
942
+ store.chatEnabled === false ||
943
+ (hasImageAttachment && messageEmpty) ||
944
+ messageEmpty;
945
+ return (_jsx(Button, { className: "ss__chat__send-button", icon: { icon: 'send', title: 'Send Message' }, disabled: sendDisabled, onClick: () => {
946
+ if (sendDisabled)
947
+ return;
948
+ controller.search();
949
+ if (isMobile && mobileProductInfoOpen) {
950
+ setMobileProductInfoOpen(false);
951
+ }
952
+ } }));
953
+ })() })] }), _jsx("div", { className: 'ss__chat__disclaimer', children: _jsxs("i", { children: ["Powered by Athos Commerce. AI-powered assistant. It sometimes make mistakes. Avoid sharing personal data.", ' ', _jsx("a", { href: "https://athoscommerce.com/legal/privacy-policy/", target: "_blank", rel: "noopener noreferrer", children: "Privacy Policy" })] }) }), isDraggingFile && (_jsxs("div", { className: "ss__chat__content__footer__drop-overlay", children: [_jsx(Icon, { icon: "image", size: "24px" }), _jsx("span", { children: "Drop image to upload" })] }))] })) : (_jsxs("div", { className: 'ss__chat__expired', children: [_jsx("div", { className: 'ss__chat__expired__message', children: "This chat is expired. Please start a new chat." }), _jsx(Button, { className: 'ss__chat__expired__button', onClick: () => {
954
+ controller.store.createChat();
955
+ }, children: "New Session" })] }))] })] })) : null] }), _jsx(Overlay, { style: { zIndex: 1001 }, color: "transparent", active: store.open, onClick: () => controller.handlers.button.click() })] }) }));
956
+ });