@cossistant/react 0.0.26 → 0.0.29

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 (247) hide show
  1. package/README.md +1 -1
  2. package/api.d.ts +1 -1
  3. package/api.d.ts.map +1 -1
  4. package/checks.d.ts +1 -1
  5. package/checks.d.ts.map +1 -1
  6. package/coerce.d.ts +1 -1
  7. package/coerce.d.ts.map +1 -1
  8. package/conversation.d.ts +6 -3
  9. package/conversation.d.ts.map +1 -1
  10. package/core.d.ts +1 -1
  11. package/core.d.ts.map +1 -1
  12. package/errors.d.ts +12 -3
  13. package/errors.d.ts.map +1 -1
  14. package/errors2.d.ts +1 -1
  15. package/errors2.d.ts.map +1 -1
  16. package/hooks/index.d.ts +3 -2
  17. package/hooks/index.js +6 -5
  18. package/hooks/private/store/use-website-store.js +2 -1
  19. package/hooks/private/store/use-website-store.js.map +1 -1
  20. package/hooks/private/use-client-query.d.ts +6 -0
  21. package/hooks/private/use-client-query.d.ts.map +1 -1
  22. package/hooks/private/use-client-query.js +26 -3
  23. package/hooks/private/use-client-query.js.map +1 -1
  24. package/hooks/private/use-grouped-messages.d.ts +8 -5
  25. package/hooks/private/use-grouped-messages.d.ts.map +1 -1
  26. package/hooks/private/use-grouped-messages.js +44 -11
  27. package/hooks/private/use-grouped-messages.js.map +1 -1
  28. package/hooks/private/use-multimodal-input.d.ts.map +1 -1
  29. package/hooks/private/use-multimodal-input.js +7 -5
  30. package/hooks/private/use-multimodal-input.js.map +1 -1
  31. package/hooks/private/use-visitor-typing-reporter.d.ts +18 -1
  32. package/hooks/private/use-visitor-typing-reporter.d.ts.map +1 -1
  33. package/hooks/private/use-visitor-typing-reporter.js +34 -4
  34. package/hooks/private/use-visitor-typing-reporter.js.map +1 -1
  35. package/hooks/use-conversation-page.d.ts +1 -0
  36. package/hooks/use-conversation-page.d.ts.map +1 -1
  37. package/hooks/use-conversation-page.js +6 -1
  38. package/hooks/use-conversation-page.js.map +1 -1
  39. package/hooks/use-conversation-preview.d.ts +2 -1
  40. package/hooks/use-conversation-preview.d.ts.map +1 -1
  41. package/hooks/use-conversation-preview.js +1 -1
  42. package/hooks/use-conversation-preview.js.map +1 -1
  43. package/hooks/use-conversation-seen.js +1 -1
  44. package/hooks/use-conversation-seen.js.map +1 -1
  45. package/hooks/use-conversation-timeline-items.js +2 -1
  46. package/hooks/use-conversation-timeline-items.js.map +1 -1
  47. package/hooks/use-conversation-timeline.d.ts.map +1 -1
  48. package/hooks/use-conversation-timeline.js +1 -3
  49. package/hooks/use-conversation-timeline.js.map +1 -1
  50. package/hooks/use-conversation.js +2 -1
  51. package/hooks/use-conversation.js.map +1 -1
  52. package/hooks/use-conversations.js +1 -0
  53. package/hooks/use-conversations.js.map +1 -1
  54. package/hooks/use-create-conversation.d.ts.map +1 -1
  55. package/hooks/use-file-upload.d.ts +55 -0
  56. package/hooks/use-file-upload.d.ts.map +1 -0
  57. package/hooks/use-file-upload.js +100 -0
  58. package/hooks/use-file-upload.js.map +1 -0
  59. package/hooks/use-message-composer.d.ts +11 -0
  60. package/hooks/use-message-composer.d.ts.map +1 -1
  61. package/hooks/use-message-composer.js +7 -3
  62. package/hooks/use-message-composer.js.map +1 -1
  63. package/hooks/use-send-message.d.ts +1 -0
  64. package/hooks/use-send-message.d.ts.map +1 -1
  65. package/hooks/use-send-message.js +63 -11
  66. package/hooks/use-send-message.js.map +1 -1
  67. package/index.d.ts +7 -4
  68. package/index.js +13 -10
  69. package/json-schema.d.ts +70 -0
  70. package/json-schema.d.ts.map +1 -0
  71. package/package.json +4 -3
  72. package/parse.d.ts +1 -1
  73. package/parse.d.ts.map +1 -1
  74. package/primitives/avatar/fallback.d.ts.map +1 -1
  75. package/primitives/avatar/fallback.js +1 -1
  76. package/primitives/avatar/fallback.js.map +1 -1
  77. package/primitives/conversation-timeline.d.ts.map +1 -1
  78. package/primitives/conversation-timeline.js +10 -5
  79. package/primitives/conversation-timeline.js.map +1 -1
  80. package/primitives/day-separator.d.ts +76 -0
  81. package/primitives/day-separator.d.ts.map +1 -0
  82. package/primitives/day-separator.js +111 -0
  83. package/primitives/day-separator.js.map +1 -0
  84. package/primitives/index.d.ts +5 -3
  85. package/primitives/index.js +17 -5
  86. package/primitives/index.parts.d.ts +4 -2
  87. package/primitives/index.parts.js +5 -3
  88. package/primitives/timeline-item-attachments.d.ts +100 -0
  89. package/primitives/timeline-item-attachments.d.ts.map +1 -0
  90. package/primitives/timeline-item-attachments.js +151 -0
  91. package/primitives/timeline-item-attachments.js.map +1 -0
  92. package/primitives/timeline-item-group.d.ts.map +1 -1
  93. package/primitives/timeline-item-group.js +1 -1
  94. package/primitives/timeline-item-group.js.map +1 -1
  95. package/primitives/timeline-item.js +1 -1
  96. package/primitives/timeline-item.js.map +1 -1
  97. package/primitives/trigger.d.ts +91 -0
  98. package/primitives/trigger.d.ts.map +1 -0
  99. package/primitives/trigger.js +74 -0
  100. package/primitives/trigger.js.map +1 -0
  101. package/primitives/window.d.ts +22 -1
  102. package/primitives/window.d.ts.map +1 -1
  103. package/primitives/window.js +91 -5
  104. package/primitives/window.js.map +1 -1
  105. package/provider.d.ts.map +1 -1
  106. package/provider.js +8 -3
  107. package/provider.js.map +1 -1
  108. package/realtime/index.js +1 -1
  109. package/realtime/provider.js +1 -1
  110. package/realtime/support-provider.js +5 -1
  111. package/realtime/support-provider.js.map +1 -1
  112. package/realtime-events.d.ts +165 -2
  113. package/realtime-events.d.ts.map +1 -1
  114. package/registries.d.ts +1 -1
  115. package/registries.d.ts.map +1 -1
  116. package/schemas.d.ts +305 -7
  117. package/schemas.d.ts.map +1 -1
  118. package/schemas2.d.ts +29 -4
  119. package/schemas2.d.ts.map +1 -1
  120. package/schemas3.d.ts +2 -1
  121. package/schemas3.d.ts.map +1 -1
  122. package/standard-schema.d.ts +83 -21
  123. package/standard-schema.d.ts.map +1 -1
  124. package/support/components/button.d.ts +1 -1
  125. package/support/components/content.d.ts +30 -0
  126. package/support/components/content.d.ts.map +1 -0
  127. package/support/components/content.js +282 -0
  128. package/support/components/content.js.map +1 -0
  129. package/support/components/conversation-button-link.js +1 -1
  130. package/support/components/conversation-timeline.d.ts +5 -0
  131. package/support/components/conversation-timeline.d.ts.map +1 -1
  132. package/support/components/conversation-timeline.js +25 -5
  133. package/support/components/conversation-timeline.js.map +1 -1
  134. package/support/components/header.js +1 -1
  135. package/support/components/image-lightbox.d.ts +49 -0
  136. package/support/components/image-lightbox.d.ts.map +1 -0
  137. package/support/components/image-lightbox.js +142 -0
  138. package/support/components/image-lightbox.js.map +1 -0
  139. package/support/components/index.d.ts +5 -4
  140. package/support/components/index.js +4 -4
  141. package/support/components/multimodal-input.d.ts +4 -1
  142. package/support/components/multimodal-input.d.ts.map +1 -1
  143. package/support/components/multimodal-input.js +71 -45
  144. package/support/components/multimodal-input.js.map +1 -1
  145. package/support/components/navigation-tab.js +1 -1
  146. package/support/components/root.d.ts +23 -0
  147. package/support/components/root.d.ts.map +1 -0
  148. package/support/components/root.js +36 -0
  149. package/support/components/root.js.map +1 -0
  150. package/support/components/timeline-message-item.d.ts.map +1 -1
  151. package/support/components/timeline-message-item.js +82 -18
  152. package/support/components/timeline-message-item.js.map +1 -1
  153. package/support/components/trigger.d.ts +14 -0
  154. package/support/components/trigger.d.ts.map +1 -0
  155. package/support/components/{bubble.js → trigger.js} +16 -12
  156. package/support/components/trigger.js.map +1 -0
  157. package/support/components/typing-indicator.d.ts.map +1 -1
  158. package/support/components/typing-indicator.js +1 -0
  159. package/support/components/typing-indicator.js.map +1 -1
  160. package/support/context/controlled-state.d.ts +46 -0
  161. package/support/context/controlled-state.d.ts.map +1 -0
  162. package/support/context/controlled-state.js +34 -0
  163. package/support/context/controlled-state.js.map +1 -0
  164. package/support/context/events.d.ts +103 -0
  165. package/support/context/events.d.ts.map +1 -0
  166. package/support/context/events.js +139 -0
  167. package/support/context/events.js.map +1 -0
  168. package/support/context/handle.d.ts +90 -0
  169. package/support/context/handle.d.ts.map +1 -0
  170. package/support/context/handle.js +79 -0
  171. package/support/context/handle.js.map +1 -0
  172. package/support/context/positioning.d.ts +17 -0
  173. package/support/context/positioning.d.ts.map +1 -0
  174. package/support/context/positioning.js +26 -0
  175. package/support/context/positioning.js.map +1 -0
  176. package/support/context/slots.d.ts +85 -0
  177. package/support/context/slots.d.ts.map +1 -0
  178. package/support/context/slots.js +115 -0
  179. package/support/context/slots.js.map +1 -0
  180. package/support/context/websocket.d.ts +8 -1
  181. package/support/context/websocket.d.ts.map +1 -1
  182. package/support/context/websocket.js +8 -1
  183. package/support/context/websocket.js.map +1 -1
  184. package/support/index.d.ts +239 -54
  185. package/support/index.d.ts.map +1 -1
  186. package/support/index.js +254 -33
  187. package/support/index.js.map +1 -1
  188. package/support/pages/articles.d.ts.map +1 -1
  189. package/support/pages/articles.js +3 -4
  190. package/support/pages/articles.js.map +1 -1
  191. package/support/pages/conversation-history.js +2 -2
  192. package/support/pages/conversation.js +6 -5
  193. package/support/pages/conversation.js.map +1 -1
  194. package/support/pages/home.js +2 -2
  195. package/support/router.d.ts +52 -12
  196. package/support/router.d.ts.map +1 -1
  197. package/support/router.js +78 -30
  198. package/support/router.js.map +1 -1
  199. package/support/store/index.d.ts +2 -2
  200. package/support/store/support-store.d.ts +26 -20
  201. package/support/store/support-store.d.ts.map +1 -1
  202. package/support/store/support-store.js +47 -6
  203. package/support/store/support-store.js.map +1 -1
  204. package/support/{support-D2EgfIts.css → support-C7Xaw-N6.css} +1 -2
  205. package/support/support-C7Xaw-N6.css.map +1 -0
  206. package/support/text/index.d.ts +1 -1
  207. package/support/text/index.d.ts.map +1 -1
  208. package/support/text/index.js.map +1 -1
  209. package/support/types.d.ts +75 -12
  210. package/support/types.d.ts.map +1 -1
  211. package/support.css +2 -2
  212. package/tailwind.css +0 -1
  213. package/timeline-item.d.ts +68 -2
  214. package/timeline-item.d.ts.map +1 -1
  215. package/to-json-schema.d.ts +96 -0
  216. package/to-json-schema.d.ts.map +1 -0
  217. package/util.d.ts +6 -2
  218. package/util.d.ts.map +1 -1
  219. package/utils/index.d.ts +2 -1
  220. package/utils/index.js +2 -1
  221. package/utils/merge-refs.d.ts +30 -0
  222. package/utils/merge-refs.d.ts.map +1 -0
  223. package/utils/merge-refs.js +46 -0
  224. package/utils/merge-refs.js.map +1 -0
  225. package/utils/use-render-element.d.ts.map +1 -1
  226. package/utils/use-render-element.js +36 -8
  227. package/utils/use-render-element.js.map +1 -1
  228. package/versions.d.ts +2 -2
  229. package/versions.d.ts.map +1 -1
  230. package/zod-extensions.d.ts +1 -1
  231. package/zod-extensions.d.ts.map +1 -1
  232. package/primitives/bubble.d.ts +0 -38
  233. package/primitives/bubble.d.ts.map +0 -1
  234. package/primitives/bubble.js +0 -57
  235. package/primitives/bubble.js.map +0 -1
  236. package/support/components/bubble.d.ts +0 -10
  237. package/support/components/bubble.d.ts.map +0 -1
  238. package/support/components/bubble.js.map +0 -1
  239. package/support/components/container.d.ts +0 -13
  240. package/support/components/container.d.ts.map +0 -1
  241. package/support/components/container.js +0 -109
  242. package/support/components/container.js.map +0 -1
  243. package/support/components/support-content.d.ts +0 -22
  244. package/support/components/support-content.d.ts.map +0 -1
  245. package/support/components/support-content.js +0 -48
  246. package/support/components/support-content.js.map +0 -1
  247. package/support/support-D2EgfIts.css.map +0 -1
@@ -0,0 +1,36 @@
1
+ "use client";
2
+
3
+
4
+ import { cn } from "../utils/index.js";
5
+ import { TriggerRefProvider } from "../context/positioning.js";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { motion } from "motion/react";
8
+
9
+ //#region src/support/components/root.tsx
10
+ /**
11
+ * Root wrapper component that provides the positioning context.
12
+ * Contains the trigger and content as siblings.
13
+ *
14
+ * @example
15
+ * <Support.Root>
16
+ * <Support.Trigger>Help</Support.Trigger>
17
+ * <Support.Content>
18
+ * <Support.Router />
19
+ * </Support.Content>
20
+ * </Support.Root>
21
+ */
22
+ const Root = ({ className, children }) => /* @__PURE__ */ jsx(TriggerRefProvider, { children: /* @__PURE__ */ jsx(motion.div, {
23
+ animate: { opacity: 1 },
24
+ className: cn("cossistant relative", className),
25
+ initial: { opacity: 0 },
26
+ layout: "position",
27
+ transition: {
28
+ default: { ease: "anticipate" },
29
+ layout: { duration: .3 }
30
+ },
31
+ children
32
+ }) });
33
+
34
+ //#endregion
35
+ export { Root };
36
+ //# sourceMappingURL=root.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root.js","names":["Root: React.FC<RootProps>"],"sources":["../../../src/support/components/root.tsx"],"sourcesContent":["\"use client\";\n\nimport { motion } from \"motion/react\";\nimport type * as React from \"react\";\nimport { TriggerRefProvider } from \"../context/positioning\";\nimport { cn } from \"../utils\";\n\nexport type RootProps = {\n\tclassName?: string;\n\tchildren: React.ReactNode;\n};\n\n/**\n * Root wrapper component that provides the positioning context.\n * Contains the trigger and content as siblings.\n *\n * @example\n * <Support.Root>\n * <Support.Trigger>Help</Support.Trigger>\n * <Support.Content>\n * <Support.Router />\n * </Support.Content>\n * </Support.Root>\n */\nexport const Root: React.FC<RootProps> = ({ className, children }) => (\n\t<TriggerRefProvider>\n\t\t<motion.div\n\t\t\tanimate={{ opacity: 1 }}\n\t\t\tclassName={cn(\"cossistant relative\", className)}\n\t\t\tinitial={{ opacity: 0 }}\n\t\t\tlayout=\"position\"\n\t\t\ttransition={{\n\t\t\t\tdefault: { ease: \"anticipate\" },\n\t\t\t\tlayout: { duration: 0.3 },\n\t\t\t}}\n\t\t>\n\t\t\t{children}\n\t\t</motion.div>\n\t</TriggerRefProvider>\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwBA,MAAaA,QAA6B,EAAE,WAAW,eACtD,oBAAC,gCACA,oBAAC,OAAO;CACP,SAAS,EAAE,SAAS,GAAG;CACvB,WAAW,GAAG,uBAAuB,UAAU;CAC/C,SAAS,EAAE,SAAS,GAAG;CACvB,QAAO;CACP,YAAY;EACX,SAAS,EAAE,MAAM,cAAc;EAC/B,QAAQ,EAAE,UAAU,IAAK;EACzB;CAEA;EACW,GACO"}
@@ -1 +1 @@
1
- {"version":3,"file":"timeline-message-item.d.ts","names":[],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":[],"mappings":";;;;KAUY,wBAAA;QACL;EADK,MAAA,CAAA,EAAA,OAAA;EAUI,cAAA,CAAA,EAAA,OAAmB;CAClC;;;;;AAG+C,iBAJhC,mBAAA,CAIgC;EAAA,IAAA;EAAA,MAAA;EAAA;AAAA,CAAA,EAA7C,wBAA6C,CAAA,EAAlB,KAAA,CAAM,YAAY"}
1
+ {"version":3,"file":"timeline-message-item.d.ts","names":[],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":[],"mappings":";;;;KAkBY,wBAAA;QACL;EADK,MAAA,CAAA,EAAA,OAAA;EAUI,cAAA,CAAA,EAAA,OAAmB;CAClC;;;;;AAG+C,iBAJhC,mBAAA,CAIgC;EAAA,IAAA;EAAA,MAAA;EAAA;AAAA,CAAA,EAA7C,wBAA6C,CAAA,EAAlB,KAAA,CAAM,YAAY"}
@@ -1,6 +1,11 @@
1
1
  import { cn } from "../utils/index.js";
2
2
  import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "../../primitives/timeline-item.js";
3
+ import { extractFileParts, extractImageParts } from "../../primitives/timeline-item-attachments.js";
4
+ import icons_default from "./icons.js";
3
5
  import { useSupportText } from "../text/index.js";
6
+ import { ImageLightbox } from "./image-lightbox.js";
7
+ import { useState } from "react";
8
+ import { formatFileSize } from "@cossistant/core";
4
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
10
 
6
11
  //#region src/support/components/timeline-message-item.tsx
@@ -10,7 +15,17 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
15
  */
11
16
  function TimelineMessageItem({ item, isLast = false, isSentByViewer = false }) {
12
17
  const text = useSupportText();
13
- return /* @__PURE__ */ jsx(TimelineItem, {
18
+ const [lightboxOpen, setLightboxOpen] = useState(false);
19
+ const [lightboxIndex, setLightboxIndex] = useState(0);
20
+ const images = extractImageParts(item.parts);
21
+ const files = extractFileParts(item.parts);
22
+ const hasAttachments = images.length > 0 || files.length > 0;
23
+ const hasText = item.text && item.text.trim().length > 0;
24
+ const openLightbox = (index) => {
25
+ setLightboxIndex(index);
26
+ setLightboxOpen(true);
27
+ };
28
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(TimelineItem, {
14
29
  item,
15
30
  children: ({ isAI, timestamp }) => {
16
31
  const isSentByViewerFinal = isSentByViewer;
@@ -18,27 +33,76 @@ function TimelineMessageItem({ item, isLast = false, isSentByViewer = false }) {
18
33
  className: cn("flex w-full gap-2", isSentByViewerFinal && "flex-row-reverse", !isSentByViewerFinal && "flex-row"),
19
34
  children: /* @__PURE__ */ jsxs("div", {
20
35
  className: cn("flex w-full min-w-0 flex-1 flex-col gap-1", isSentByViewerFinal && "items-end"),
21
- children: [/* @__PURE__ */ jsx(TimelineItemContent, {
22
- className: cn("block min-w-0 max-w-[300px] whitespace-pre-wrap break-words rounded-lg px-3.5 py-2.5 text-sm", {
23
- "bg-co-background-300 text-co-foreground dark:bg-co-background-600": !isSentByViewerFinal,
24
- "bg-co-primary text-co-primary-foreground": isSentByViewerFinal,
25
- "rounded-br-sm": isLast && isSentByViewerFinal,
26
- "rounded-bl-sm": isLast && !isSentByViewerFinal
36
+ children: [
37
+ hasText && /* @__PURE__ */ jsx(TimelineItemContent, {
38
+ className: cn("block min-w-0 max-w-[300px] whitespace-pre-wrap break-words rounded-lg px-3.5 py-2.5 text-sm", {
39
+ "bg-co-background-300 text-co-foreground dark:bg-co-background-600": !isSentByViewerFinal,
40
+ "bg-co-primary text-co-primary-foreground": isSentByViewerFinal,
41
+ "rounded-br-sm": isLast && isSentByViewerFinal && !hasAttachments,
42
+ "rounded-bl-sm": isLast && !isSentByViewerFinal && !hasAttachments
43
+ }),
44
+ renderMarkdown: true,
45
+ text: item.text
27
46
  }),
28
- renderMarkdown: true,
29
- text: item.text
30
- }), isLast && /* @__PURE__ */ jsx(TimelineItemTimestamp, {
31
- className: "px-1 text-co-muted-foreground text-xs",
32
- timestamp,
33
- children: () => /* @__PURE__ */ jsxs(Fragment, { children: [timestamp.toLocaleTimeString([], {
34
- hour: "2-digit",
35
- minute: "2-digit"
36
- }), isAI && ` ${text("component.message.timestamp.aiIndicator")}`] })
37
- })]
47
+ images.length > 0 && /* @__PURE__ */ jsx("div", {
48
+ className: cn("flex flex-wrap gap-2", isSentByViewerFinal && "justify-end"),
49
+ children: images.map((image, index) => /* @__PURE__ */ jsx("button", {
50
+ className: "group relative overflow-hidden rounded-lg focus:outline-none focus:ring-2 focus:ring-co-primary/50",
51
+ onClick: () => openLightbox(index),
52
+ type: "button",
53
+ children: /* @__PURE__ */ jsx("img", {
54
+ alt: image.fileName || `Image ${index + 1}`,
55
+ className: "max-h-[150px] max-w-[200px] cursor-pointer rounded-lg object-cover transition-transform group-hover:scale-105",
56
+ loading: "lazy",
57
+ src: image.url
58
+ })
59
+ }, image.url))
60
+ }),
61
+ files.length > 0 && /* @__PURE__ */ jsx("div", {
62
+ className: "flex flex-col gap-1",
63
+ children: files.map((file) => /* @__PURE__ */ jsxs("a", {
64
+ className: cn("flex items-center gap-2 rounded-lg px-3 py-2 text-xs transition-colors", {
65
+ "bg-co-background-300 text-co-foreground hover:bg-co-background-400 dark:bg-co-background-600 dark:hover:bg-co-background-500": !isSentByViewerFinal,
66
+ "bg-co-primary/80 text-co-primary-foreground hover:bg-co-primary": isSentByViewerFinal
67
+ }),
68
+ download: file.fileName,
69
+ href: file.url,
70
+ rel: "noopener noreferrer",
71
+ target: "_blank",
72
+ children: [
73
+ /* @__PURE__ */ jsx(icons_default, {
74
+ className: "h-4 w-4 shrink-0",
75
+ name: "file"
76
+ }),
77
+ /* @__PURE__ */ jsx("span", {
78
+ className: "flex-1 truncate font-medium",
79
+ children: file.fileName || "Download file"
80
+ }),
81
+ file.size && /* @__PURE__ */ jsx("span", {
82
+ className: "text-co-muted-foreground opacity-70",
83
+ children: formatFileSize(file.size)
84
+ })
85
+ ]
86
+ }, file.url))
87
+ }),
88
+ isLast && /* @__PURE__ */ jsx(TimelineItemTimestamp, {
89
+ className: "px-1 text-co-muted-foreground text-xs",
90
+ timestamp,
91
+ children: () => /* @__PURE__ */ jsxs(Fragment, { children: [timestamp.toLocaleTimeString([], {
92
+ hour: "2-digit",
93
+ minute: "2-digit"
94
+ }), isAI && ` ${text("component.message.timestamp.aiIndicator")}`] })
95
+ })
96
+ ]
38
97
  })
39
98
  });
40
99
  }
41
- });
100
+ }), images.length > 0 && /* @__PURE__ */ jsx(ImageLightbox, {
101
+ images,
102
+ initialIndex: lightboxIndex,
103
+ isOpen: lightboxOpen,
104
+ onClose: () => setLightboxOpen(false)
105
+ })] });
42
106
  }
43
107
 
44
108
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"timeline-message-item.js","names":["PrimitiveTimelineItem"],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":["import type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport {\n\tTimelineItem as PrimitiveTimelineItem,\n\tTimelineItemContent,\n\tTimelineItemTimestamp,\n} from \"../../primitives/timeline-item\";\nimport { useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\n\nexport type TimelineMessageItemProps = {\n\titem: TimelineItem;\n\tisLast?: boolean;\n\tisSentByViewer?: boolean;\n};\n\n/**\n * Message bubble renderer that adapts layout depending on whether the visitor\n * or an agent sent the message.\n */\nexport function TimelineMessageItem({\n\titem,\n\tisLast = false,\n\tisSentByViewer = false,\n}: TimelineMessageItemProps): React.ReactElement {\n\tconst text = useSupportText();\n\treturn (\n\t\t<PrimitiveTimelineItem item={item}>\n\t\t\t{({ isAI, timestamp }) => {\n\t\t\t\t// isSentByViewer defaults to false, meaning messages are treated as received\n\t\t\t\t// (left side with background) unless explicitly marked as sent by viewer\n\t\t\t\tconst isSentByViewerFinal = isSentByViewer;\n\n\t\t\t\treturn (\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"flex w-full gap-2\",\n\t\t\t\t\t\t\tisSentByViewerFinal && \"flex-row-reverse\",\n\t\t\t\t\t\t\t!isSentByViewerFinal && \"flex-row\"\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"flex w-full min-w-0 flex-1 flex-col gap-1\",\n\t\t\t\t\t\t\t\tisSentByViewerFinal && \"items-end\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<TimelineItemContent\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\"block min-w-0 max-w-[300px] whitespace-pre-wrap break-words rounded-lg px-3.5 py-2.5 text-sm\",\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground dark:bg-co-background-600\":\n\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\"bg-co-primary text-co-primary-foreground\":\n\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\"rounded-br-sm\": isLast && isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\"rounded-bl-sm\": isLast && !isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\trenderMarkdown\n\t\t\t\t\t\t\t\ttext={item.text}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t{isLast && (\n\t\t\t\t\t\t\t\t<TimelineItemTimestamp\n\t\t\t\t\t\t\t\t\tclassName=\"px-1 text-co-muted-foreground text-xs\"\n\t\t\t\t\t\t\t\t\ttimestamp={timestamp}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{() => (\n\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t{timestamp.toLocaleTimeString([], {\n\t\t\t\t\t\t\t\t\t\t\t\thour: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t\tminute: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t{isAI &&\n\t\t\t\t\t\t\t\t\t\t\t\t` ${text(\"component.message.timestamp.aiIndicator\")}`}\n\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</TimelineItemTimestamp>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t);\n\t\t\t}}\n\t\t</PrimitiveTimelineItem>\n\t);\n}\n"],"mappings":";;;;;;;;;;AAoBA,SAAgB,oBAAoB,EACnC,MACA,SAAS,OACT,iBAAiB,SAC+B;CAChD,MAAM,OAAO,gBAAgB;AAC7B,QACC,oBAACA;EAA4B;aAC1B,EAAE,MAAM,gBAAgB;GAGzB,MAAM,sBAAsB;AAE5B,UACC,oBAAC;IACA,WAAW,GACV,qBACA,uBAAuB,oBACvB,CAAC,uBAAuB,WACxB;cAED,qBAAC;KACA,WAAW,GACV,6CACA,uBAAuB,YACvB;gBAED,oBAAC;MACA,WAAW,GACV,gGACA;OACC,qEACC,CAAC;OACF,4CACC;OACD,iBAAiB,UAAU;OAC3B,iBAAiB,UAAU,CAAC;OAC5B,CACD;MACD;MACA,MAAM,KAAK;OACV,EACD,UACA,oBAAC;MACA,WAAU;MACC;sBAGV,4CACE,UAAU,mBAAmB,EAAE,EAAE;OACjC,MAAM;OACN,QAAQ;OACR,CAAC,EACD,QACA,IAAI,KAAK,0CAA0C,MAClD;OAEmB;MAEpB;KACD;;GAGe"}
1
+ {"version":3,"file":"timeline-message-item.js","names":["PrimitiveTimelineItem","Icon"],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":["import { formatFileSize } from \"@cossistant/core\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport { useState } from \"react\";\nimport {\n\tTimelineItem as PrimitiveTimelineItem,\n\tTimelineItemContent,\n\tTimelineItemTimestamp,\n} from \"../../primitives/timeline-item\";\nimport {\n\textractFileParts,\n\textractImageParts,\n} from \"../../primitives/timeline-item-attachments\";\nimport { useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\nimport { ImageLightbox } from \"./image-lightbox\";\n\nexport type TimelineMessageItemProps = {\n\titem: TimelineItem;\n\tisLast?: boolean;\n\tisSentByViewer?: boolean;\n};\n\n/**\n * Message bubble renderer that adapts layout depending on whether the visitor\n * or an agent sent the message.\n */\nexport function TimelineMessageItem({\n\titem,\n\tisLast = false,\n\tisSentByViewer = false,\n}: TimelineMessageItemProps): React.ReactElement {\n\tconst text = useSupportText();\n\tconst [lightboxOpen, setLightboxOpen] = useState(false);\n\tconst [lightboxIndex, setLightboxIndex] = useState(0);\n\n\t// Extract image and file parts\n\tconst images = extractImageParts(item.parts);\n\tconst files = extractFileParts(item.parts);\n\tconst hasAttachments = images.length > 0 || files.length > 0;\n\tconst hasText = item.text && item.text.trim().length > 0;\n\n\tconst openLightbox = (index: number) => {\n\t\tsetLightboxIndex(index);\n\t\tsetLightboxOpen(true);\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<PrimitiveTimelineItem item={item}>\n\t\t\t\t{({ isAI, timestamp }) => {\n\t\t\t\t\t// isSentByViewer defaults to false, meaning messages are treated as received\n\t\t\t\t\t// (left side with background) unless explicitly marked as sent by viewer\n\t\t\t\t\tconst isSentByViewerFinal = isSentByViewer;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"flex w-full gap-2\",\n\t\t\t\t\t\t\t\tisSentByViewerFinal && \"flex-row-reverse\",\n\t\t\t\t\t\t\t\t!isSentByViewerFinal && \"flex-row\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\"flex w-full min-w-0 flex-1 flex-col gap-1\",\n\t\t\t\t\t\t\t\t\tisSentByViewerFinal && \"items-end\"\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{/* Text content */}\n\t\t\t\t\t\t\t\t{hasText && (\n\t\t\t\t\t\t\t\t\t<TimelineItemContent\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"block min-w-0 max-w-[300px] whitespace-pre-wrap break-words rounded-lg px-3.5 py-2.5 text-sm\",\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground dark:bg-co-background-600\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-primary text-co-primary-foreground\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\"rounded-br-sm\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisLast && isSentByViewerFinal && !hasAttachments,\n\t\t\t\t\t\t\t\t\t\t\t\t\"rounded-bl-sm\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisLast && !isSentByViewerFinal && !hasAttachments,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\trenderMarkdown\n\t\t\t\t\t\t\t\t\t\ttext={item.text}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* Image attachments */}\n\t\t\t\t\t\t\t\t{images.length > 0 && (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"flex flex-wrap gap-2\",\n\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal && \"justify-end\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{images.map((image, index) => (\n\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"group relative overflow-hidden rounded-lg focus:outline-none focus:ring-2 focus:ring-co-primary/50\"\n\t\t\t\t\t\t\t\t\t\t\t\tkey={image.url}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => openLightbox(index)}\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{/* biome-ignore lint/performance/noImgElement: React package, not Next.js specific */}\n\t\t\t\t\t\t\t\t\t\t\t\t{/* biome-ignore lint/nursery/useImageSize: Dynamic image dimensions not known at render time */}\n\t\t\t\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\t\t\t\talt={image.fileName || `Image ${index + 1}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"max-h-[150px] max-w-[200px] cursor-pointer rounded-lg object-cover transition-transform group-hover:scale-105\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tsrc={image.url}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* File attachments */}\n\t\t\t\t\t\t\t\t{files.length > 0 && (\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t\t\t\t\t{files.map((file) => (\n\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"flex items-center gap-2 rounded-lg px-3 py-2 text-xs transition-colors\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground hover:bg-co-background-400 dark:bg-co-background-600 dark:hover:bg-co-background-500\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-primary/80 text-co-primary-foreground hover:bg-co-primary\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tdownload={file.fileName}\n\t\t\t\t\t\t\t\t\t\t\t\thref={file.url}\n\t\t\t\t\t\t\t\t\t\t\t\tkey={file.url}\n\t\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon className=\"h-4 w-4 shrink-0\" name=\"file\" />\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex-1 truncate font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{file.fileName || \"Download file\"}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t{file.size && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-co-muted-foreground opacity-70\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(file.size)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{isLast && (\n\t\t\t\t\t\t\t\t\t<TimelineItemTimestamp\n\t\t\t\t\t\t\t\t\t\tclassName=\"px-1 text-co-muted-foreground text-xs\"\n\t\t\t\t\t\t\t\t\t\ttimestamp={timestamp}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{() => (\n\t\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t\t{timestamp.toLocaleTimeString([], {\n\t\t\t\t\t\t\t\t\t\t\t\t\thour: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tminute: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t{isAI &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t` ${text(\"component.message.timestamp.aiIndicator\")}`}\n\t\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</TimelineItemTimestamp>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t}}\n\t\t\t</PrimitiveTimelineItem>\n\n\t\t\t{/* Lightbox for images */}\n\t\t\t{images.length > 0 && (\n\t\t\t\t<ImageLightbox\n\t\t\t\t\timages={images}\n\t\t\t\t\tinitialIndex={lightboxIndex}\n\t\t\t\t\tisOpen={lightboxOpen}\n\t\t\t\t\tonClose={() => setLightboxOpen(false)}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,SAAgB,oBAAoB,EACnC,MACA,SAAS,OACT,iBAAiB,SAC+B;CAChD,MAAM,OAAO,gBAAgB;CAC7B,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CACvD,MAAM,CAAC,eAAe,oBAAoB,SAAS,EAAE;CAGrD,MAAM,SAAS,kBAAkB,KAAK,MAAM;CAC5C,MAAM,QAAQ,iBAAiB,KAAK,MAAM;CAC1C,MAAM,iBAAiB,OAAO,SAAS,KAAK,MAAM,SAAS;CAC3D,MAAM,UAAU,KAAK,QAAQ,KAAK,KAAK,MAAM,CAAC,SAAS;CAEvD,MAAM,gBAAgB,UAAkB;AACvC,mBAAiB,MAAM;AACvB,kBAAgB,KAAK;;AAGtB,QACC,4CACC,oBAACA;EAA4B;aAC1B,EAAE,MAAM,gBAAgB;GAGzB,MAAM,sBAAsB;AAE5B,UACC,oBAAC;IACA,WAAW,GACV,qBACA,uBAAuB,oBACvB,CAAC,uBAAuB,WACxB;cAED,qBAAC;KACA,WAAW,GACV,6CACA,uBAAuB,YACvB;;MAGA,WACA,oBAAC;OACA,WAAW,GACV,gGACA;QACC,qEACC,CAAC;QACF,4CACC;QACD,iBACC,UAAU,uBAAuB,CAAC;QACnC,iBACC,UAAU,CAAC,uBAAuB,CAAC;QACpC,CACD;OACD;OACA,MAAM,KAAK;QACV;MAIF,OAAO,SAAS,KAChB,oBAAC;OACA,WAAW,GACV,wBACA,uBAAuB,cACvB;iBAEA,OAAO,KAAK,OAAO,UACnB,oBAAC;QACA,WAAU;QAEV,eAAe,aAAa,MAAM;QAClC,MAAK;kBAIL,oBAAC;SACA,KAAK,MAAM,YAAY,SAAS,QAAQ;SACxC,WAAU;SACV,SAAQ;SACR,KAAK,MAAM;UACV;UAXG,MAAM,IAYH,CACR;QACG;MAIN,MAAM,SAAS,KACf,oBAAC;OAAI,WAAU;iBACb,MAAM,KAAK,SACX,qBAAC;QACA,WAAW,GACV,0EACA;SACC,gIACC,CAAC;SACF,mEACC;SACD,CACD;QACD,UAAU,KAAK;QACf,MAAM,KAAK;QAEX,KAAI;QACJ,QAAO;;SAEP,oBAACC;UAAK,WAAU;UAAmB,MAAK;WAAS;SACjD,oBAAC;UAAK,WAAU;oBACd,KAAK,YAAY;WACZ;SACN,KAAK,QACL,oBAAC;UAAK,WAAU;oBACd,eAAe,KAAK,KAAK;WACpB;;UAXH,KAAK,IAaP,CACH;QACG;MAGN,UACA,oBAAC;OACA,WAAU;OACC;uBAGV,4CACE,UAAU,mBAAmB,EAAE,EAAE;QACjC,MAAM;QACN,QAAQ;QACR,CAAC,EACD,QACA,IAAI,KAAK,0CAA0C,MAClD;QAEmB;;MAEpB;KACD;;GAGe,EAGvB,OAAO,SAAS,KAChB,oBAAC;EACQ;EACR,cAAc;EACd,QAAQ;EACR,eAAe,gBAAgB,MAAM;GACpC,IAED"}
@@ -0,0 +1,14 @@
1
+ import * as React$1 from "react";
2
+
3
+ //#region src/support/components/trigger.d.ts
4
+ type DefaultTriggerProps = {
5
+ className?: string;
6
+ };
7
+ /**
8
+ * Default styled trigger button.
9
+ * Used internally when no custom trigger is provided.
10
+ */
11
+ declare const DefaultTrigger: React$1.FC<DefaultTriggerProps>;
12
+ //#endregion
13
+ export { DefaultTrigger, DefaultTriggerProps };
14
+ //# sourceMappingURL=trigger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trigger.d.ts","names":[],"sources":["../../../src/support/components/trigger.tsx"],"sourcesContent":[],"mappings":";;;KA2HY,mBAAA;;AAAZ,CAAA;AAQA;;;;cAAa,gBAAgB,OAAA,CAAM,GAAG"}
@@ -3,26 +3,26 @@
3
3
 
4
4
  import { cn } from "../utils/index.js";
5
5
  import { BouncingDots } from "./typing-indicator.js";
6
- import { SupportBubble } from "../../primitives/bubble.js";
7
- import icons_default from "./icons.js";
6
+ import { SupportTrigger } from "../../primitives/trigger.js";
8
7
  import { useNewMessageSound } from "../../hooks/use-new-message-sound.js";
9
8
  import { useTypingSound } from "../../hooks/use-typing-sound.js";
10
- import { useEffect, useRef } from "react";
9
+ import icons_default from "./icons.js";
10
+ import * as React$1 from "react";
11
11
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
12
  import { AnimatePresence, motion } from "motion/react";
13
13
 
14
- //#region src/support/components/bubble.tsx
15
- const BubbleContent = ({ isOpen, unreadCount, isTyping }) => {
14
+ //#region src/support/components/trigger.tsx
15
+ const TriggerContent = ({ isOpen, unreadCount, isTyping }) => {
16
16
  const playNewMessageSound = useNewMessageSound({
17
17
  volume: .7,
18
18
  playbackRate: 1
19
19
  });
20
- const previousUnreadCountRef = useRef(0);
20
+ const previousUnreadCountRef = React$1.useRef(0);
21
21
  useTypingSound(!isOpen && isTyping, {
22
22
  volume: 1,
23
23
  playbackRate: 1.3
24
24
  });
25
- useEffect(() => {
25
+ React$1.useEffect(() => {
26
26
  if (unreadCount > previousUnreadCountRef.current) playNewMessageSound();
27
27
  previousUnreadCountRef.current = unreadCount;
28
28
  }, [unreadCount, playNewMessageSound]);
@@ -127,10 +127,14 @@ const BubbleContent = ({ isOpen, unreadCount, isTyping }) => {
127
127
  }
128
128
  })] });
129
129
  };
130
- const Bubble = ({ className }) => /* @__PURE__ */ jsx(SupportBubble, {
130
+ /**
131
+ * Default styled trigger button.
132
+ * Used internally when no custom trigger is provided.
133
+ */
134
+ const DefaultTrigger = ({ className }) => /* @__PURE__ */ jsx(SupportTrigger, {
131
135
  asChild: true,
132
136
  children: ({ isOpen, unreadCount, isTyping }) => /* @__PURE__ */ jsx(motion.button, {
133
- className: cn("relative flex size-14 cursor-pointer items-center justify-center rounded-full bg-co-primary text-co-primary-foreground transition-colors hover:bg-co-primary/90 data-[open=true]:bg-co-primary/90", className),
137
+ className: cn("relative z-[9999] flex size-14 cursor-pointer items-center justify-center rounded-full bg-co-primary text-co-primary-foreground transition-colors hover:bg-co-primary/90 data-[open=true]:bg-co-primary/90", className),
134
138
  "data-open": isOpen,
135
139
  transition: {
136
140
  type: "spring",
@@ -139,7 +143,7 @@ const Bubble = ({ className }) => /* @__PURE__ */ jsx(SupportBubble, {
139
143
  },
140
144
  type: "button",
141
145
  whileTap: { scale: .95 },
142
- children: /* @__PURE__ */ jsx(BubbleContent, {
146
+ children: /* @__PURE__ */ jsx(TriggerContent, {
143
147
  isOpen,
144
148
  isTyping,
145
149
  unreadCount
@@ -148,5 +152,5 @@ const Bubble = ({ className }) => /* @__PURE__ */ jsx(SupportBubble, {
148
152
  });
149
153
 
150
154
  //#endregion
151
- export { Bubble };
152
- //# sourceMappingURL=bubble.js.map
155
+ export { DefaultTrigger };
156
+ //# sourceMappingURL=trigger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trigger.js","names":["TriggerContent: React.FC<TriggerContentProps>","React","Icon","DefaultTrigger: React.FC<DefaultTriggerProps>","Primitive.Trigger"],"sources":["../../../src/support/components/trigger.tsx"],"sourcesContent":["\"use client\";\n\nimport { AnimatePresence, motion } from \"motion/react\";\nimport * as React from \"react\";\nimport { useNewMessageSound } from \"../../hooks/use-new-message-sound\";\nimport { useTypingSound } from \"../../hooks/use-typing-sound\";\nimport * as Primitive from \"../../primitives\";\nimport type { TriggerRenderProps } from \"../types\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\nimport { BouncingDots } from \"./typing-indicator\";\n\ntype TriggerContentProps = {\n\tisOpen: boolean;\n\tunreadCount: number;\n\tisTyping: boolean;\n};\n\nconst TriggerContent: React.FC<TriggerContentProps> = ({\n\tisOpen,\n\tunreadCount,\n\tisTyping,\n}) => {\n\tconst playNewMessageSound = useNewMessageSound({\n\t\tvolume: 0.7,\n\t\tplaybackRate: 1.0,\n\t});\n\tconst previousUnreadCountRef = React.useRef(0);\n\n\tuseTypingSound(!isOpen && isTyping, {\n\t\tvolume: 1,\n\t\tplaybackRate: 1.3,\n\t});\n\n\tReact.useEffect(() => {\n\t\tif (unreadCount > previousUnreadCountRef.current) {\n\t\t\tplayNewMessageSound();\n\t\t}\n\t\tpreviousUnreadCountRef.current = unreadCount;\n\t}, [unreadCount, playNewMessageSound]);\n\n\treturn (\n\t\t<>\n\t\t\t<AnimatePresence mode=\"wait\">\n\t\t\t\t{isOpen ? (\n\t\t\t\t\t<motion.div\n\t\t\t\t\t\tanimate={{\n\t\t\t\t\t\t\tscale: 1,\n\t\t\t\t\t\t\trotate: 0,\n\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\ttransition: { duration: 0.2, ease: \"easeOut\" },\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName=\"flex items-center justify-center\"\n\t\t\t\t\t\texit={{\n\t\t\t\t\t\t\tscale: 0.9,\n\t\t\t\t\t\t\trotate: -45,\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\ttransition: { duration: 0.1, ease: \"easeIn\" },\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tinitial={{ scale: 0.9, rotate: 45, opacity: 0 }}\n\t\t\t\t\t\tkey=\"chevron\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon className=\"size-5\" name=\"chevron-down\" />\n\t\t\t\t\t</motion.div>\n\t\t\t\t) : isTyping ? (\n\t\t\t\t\t<motion.span\n\t\t\t\t\t\tanimate={{\n\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\tscale: 1,\n\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\tduration: 0.2,\n\t\t\t\t\t\t\t\tease: \"easeOut\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName=\"pointer-events-none flex items-center rounded-full text-co-primary\"\n\t\t\t\t\t\texit={{\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\tscale: 0.9,\n\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\tduration: 0.1,\n\t\t\t\t\t\t\t\tease: \"easeIn\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tinitial={{ opacity: 0, scale: 0.9 }}\n\t\t\t\t\t\tkey=\"typing-indicator\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<BouncingDots className=\"bg-co-primary-foreground\" />\n\t\t\t\t\t</motion.span>\n\t\t\t\t) : (\n\t\t\t\t\t<motion.div\n\t\t\t\t\t\tanimate={{\n\t\t\t\t\t\t\tscale: 1,\n\t\t\t\t\t\t\trotate: 0,\n\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\ttransition: { duration: 0.2, ease: \"easeOut\" },\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName=\"flex items-center justify-center\"\n\t\t\t\t\t\texit={{\n\t\t\t\t\t\t\tscale: 0.9,\n\t\t\t\t\t\t\trotate: 45,\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\ttransition: { duration: 0.1, ease: \"easeIn\" },\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tinitial={{ scale: 0.9, rotate: -45, opacity: 0 }}\n\t\t\t\t\t\tkey=\"chat\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon className=\"size-6.5\" name=\"chat\" variant=\"filled\" />\n\t\t\t\t\t</motion.div>\n\t\t\t\t)}\n\t\t\t</AnimatePresence>\n\n\t\t\t{unreadCount > 0 && (\n\t\t\t\t<motion.div\n\t\t\t\t\tanimate={{ scale: 1, opacity: 1 }}\n\t\t\t\t\tclassName=\"absolute top-0.5 right-0.5 flex size-2 items-center justify-center rounded-full bg-co-destructive font-medium text-[10px] text-co-destructive-foreground text-white text-xs\"\n\t\t\t\t\texit={{ scale: 0, opacity: 0 }}\n\t\t\t\t\tinitial={{ scale: 0, opacity: 0 }}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n};\n\nexport type DefaultTriggerProps = {\n\tclassName?: string;\n};\n\n/**\n * Default styled trigger button.\n * Used internally when no custom trigger is provided.\n */\nexport const DefaultTrigger: React.FC<DefaultTriggerProps> = ({\n\tclassName,\n}) => (\n\t<Primitive.Trigger asChild>\n\t\t{({ isOpen, unreadCount, isTyping }: TriggerRenderProps) => (\n\t\t\t<motion.button\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"relative z-[9999] flex size-14 cursor-pointer items-center justify-center rounded-full bg-co-primary text-co-primary-foreground transition-colors hover:bg-co-primary/90 data-[open=true]:bg-co-primary/90\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\tdata-open={isOpen}\n\t\t\t\ttransition={{\n\t\t\t\t\ttype: \"spring\",\n\t\t\t\t\tstiffness: 800,\n\t\t\t\t\tdamping: 17,\n\t\t\t\t}}\n\t\t\t\ttype=\"button\"\n\t\t\t\twhileTap={{ scale: 0.95 }}\n\t\t\t>\n\t\t\t\t<TriggerContent\n\t\t\t\t\tisOpen={isOpen}\n\t\t\t\t\tisTyping={isTyping}\n\t\t\t\t\tunreadCount={unreadCount}\n\t\t\t\t/>\n\t\t\t</motion.button>\n\t\t)}\n\t</Primitive.Trigger>\n);\n"],"mappings":";;;;;;;;;;;;;;AAkBA,MAAMA,kBAAiD,EACtD,QACA,aACA,eACK;CACL,MAAM,sBAAsB,mBAAmB;EAC9C,QAAQ;EACR,cAAc;EACd,CAAC;CACF,MAAM,yBAAyBC,QAAM,OAAO,EAAE;AAE9C,gBAAe,CAAC,UAAU,UAAU;EACnC,QAAQ;EACR,cAAc;EACd,CAAC;AAEF,SAAM,gBAAgB;AACrB,MAAI,cAAc,uBAAuB,QACxC,sBAAqB;AAEtB,yBAAuB,UAAU;IAC/B,CAAC,aAAa,oBAAoB,CAAC;AAEtC,QACC,4CACC,oBAAC;EAAgB,MAAK;YACpB,SACA,oBAAC,OAAO;GACP,SAAS;IACR,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;KAAE,UAAU;KAAK,MAAM;KAAW;IAC9C;GACD,WAAU;GACV,MAAM;IACL,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;KAAE,UAAU;KAAK,MAAM;KAAU;IAC7C;GACD,SAAS;IAAE,OAAO;IAAK,QAAQ;IAAI,SAAS;IAAG;aAG/C,oBAACC;IAAK,WAAU;IAAS,MAAK;KAAiB;KAF3C,UAGQ,GACV,WACH,oBAAC,OAAO;GACP,SAAS;IACR,SAAS;IACT,OAAO;IACP,YAAY;KACX,UAAU;KACV,MAAM;KACN;IACD;GACD,WAAU;GACV,MAAM;IACL,SAAS;IACT,OAAO;IACP,YAAY;KACX,UAAU;KACV,MAAM;KACN;IACD;GACD,SAAS;IAAE,SAAS;IAAG,OAAO;IAAK;aAGnC,oBAAC,gBAAa,WAAU,6BAA6B;KAFjD,mBAGS,GAEd,oBAAC,OAAO;GACP,SAAS;IACR,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;KAAE,UAAU;KAAK,MAAM;KAAW;IAC9C;GACD,WAAU;GACV,MAAM;IACL,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;KAAE,UAAU;KAAK,MAAM;KAAU;IAC7C;GACD,SAAS;IAAE,OAAO;IAAK,QAAQ;IAAK,SAAS;IAAG;aAGhD,oBAACA;IAAK,WAAU;IAAW,MAAK;IAAO,SAAQ;KAAW;KAFtD,OAGQ;GAEG,EAEjB,cAAc,KACd,oBAAC,OAAO;EACP,SAAS;GAAE,OAAO;GAAG,SAAS;GAAG;EACjC,WAAU;EACV,MAAM;GAAE,OAAO;GAAG,SAAS;GAAG;EAC9B,SAAS;GAAE,OAAO;GAAG,SAAS;GAAG;GAChC,IAED;;;;;;AAYL,MAAaC,kBAAiD,EAC7D,gBAEA,oBAACC;CAAkB;YAChB,EAAE,QAAQ,aAAa,eACxB,oBAAC,OAAO;EACP,WAAW,GACV,8MACA,UACA;EACD,aAAW;EACX,YAAY;GACX,MAAM;GACN,WAAW;GACX,SAAS;GACT;EACD,MAAK;EACL,UAAU,EAAE,OAAO,KAAM;YAEzB,oBAAC;GACQ;GACE;GACG;IACZ;GACa;EAEE"}
@@ -1 +1 @@
1
- {"version":3,"file":"typing-indicator.d.ts","names":[],"sources":["../../../src/support/components/typing-indicator.tsx"],"sourcesContent":[],"mappings":";;;;KAKY,qBAAA;KAEA,iBAAA;EAFA,EAAA,EAAA,MAAA;EAEA,IAAA,EAEL,qBAFsB;AAK7B,CAAA;AAAwD,KAA5C,oBAAA,GAAuB,OAAA,CAAM,cAAe,CAAA,cAAA,CAAA,GAAA;EAArB,YAAM,EAC1B,iBAD0B,EAAA;EAC1B,iBAAA,CAAA,EACM,gBADN,EAAA;EACM,oBAAA,CAAA,EACG,mBADH,EAAA;EACG,WAAA,CAAA,EAAA,OAAA;CAAmB;AAI9B,cAAA,YAAgB,EAAA,CAAA;EAAA;CAIzB,EAAM;EAuBG,SAAA,CAAA,EAAA,MAuDZ;CAvD2B,EAAA,GAvBxB,OAAA,CAAM,YAuBkB;AAAA,cAAf,eAAe,EAAA,OAAA,CAAA,yBAAA,CAAA,OAAA,CAAA,cAAA,CAAA,cAAA,CAAA,GAAA;EAjCb,YAAA,EAAA,iBAAA,EAAA;EACM,iBAAA,CAAA,EAAA,gBAAA,EAAA;EACG,oBAAA,CAAA,EAAA,mBAAA,EAAA"}
1
+ {"version":3,"file":"typing-indicator.d.ts","names":[],"sources":["../../../src/support/components/typing-indicator.tsx"],"sourcesContent":[],"mappings":";;;;KAKY,qBAAA;KAEA,iBAAA;EAFA,EAAA,EAAA,MAAA;EAEA,IAAA,EAEL,qBAFsB;AAK7B,CAAA;AAAwD,KAA5C,oBAAA,GAAuB,OAAA,CAAM,cAAe,CAAA,cAAA,CAAA,GAAA;EAArB,YAAM,EAC1B,iBAD0B,EAAA;EAC1B,iBAAA,CAAA,EACM,gBADN,EAAA;EACM,oBAAA,CAAA,EACG,mBADH,EAAA;EACG,WAAA,CAAA,EAAA,OAAA;CAAmB;AAI9B,cAAA,YAAgB,EAAA,CAAA;EAAA;CAIzB,EAAM;EAuBG,SAAA,CAAA,EAAA,MAwDZ;CAxD2B,EAAA,GAvBxB,OAAA,CAAM,YAuBkB;AAAA,cAAf,eAAe,EAAA,OAAA,CAAA,yBAAA,CAAA,OAAA,CAAA,cAAA,CAAA,cAAA,CAAA,GAAA;EAjCb,YAAA,EAAA,iBAAA,EAAA;EACM,iBAAA,CAAA,EAAA,gBAAA,EAAA;EACG,oBAAA,CAAA,EAAA,mBAAA,EAAA"}
@@ -24,6 +24,7 @@ const TypingIndicator = React$1.forwardRef(({ participants, availableAIAgents =
24
24
  ...props,
25
25
  children: [withAvatars && /* @__PURE__ */ jsx(AvatarStack, {
26
26
  aiAgents: typingAIAgents,
27
+ hideDefaultAIAgent: typingAIAgents.length === 0,
27
28
  humanAgents: typingHumanAgents,
28
29
  size: 24,
29
30
  spacing: 16
@@ -1 +1 @@
1
- {"version":3,"file":"typing-indicator.js","names":["React"],"sources":["../../../src/support/components/typing-indicator.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport * as React from \"react\";\nimport { cn } from \"../utils\";\nimport { AvatarStack } from \"./avatar-stack\";\n\nexport type TypingParticipantType = \"visitor\" | \"team_member\" | \"ai\";\n\nexport type TypingParticipant = {\n\tid: string;\n\ttype: TypingParticipantType;\n};\n\nexport type TypingIndicatorProps = React.HTMLAttributes<HTMLDivElement> & {\n\tparticipants: TypingParticipant[];\n\tavailableAIAgents?: AvailableAIAgent[];\n\tavailableHumanAgents?: AvailableHumanAgent[];\n\twithAvatars?: boolean;\n};\n\nexport const BouncingDots = ({\n\tclassName,\n}: {\n\tclassName?: string;\n}): React.ReactElement => (\n\t<div className=\"flex gap-1\">\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-1 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-2 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-3 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t</div>\n);\n\nexport const TypingIndicator = React.forwardRef<\n\tHTMLDivElement,\n\tTypingIndicatorProps\n>(\n\t(\n\t\t{\n\t\t\tparticipants,\n\t\t\tavailableAIAgents = [],\n\t\t\tavailableHumanAgents = [],\n\t\t\twithAvatars = true,\n\t\t\tclassName,\n\t\t\t...props\n\t\t},\n\t\tref\n\t) => {\n\t\tif (!participants || participants.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Separate AI and human participants\n\t\tconst humanParticipantIds = participants\n\t\t\t.filter((p) => p.type === \"team_member\")\n\t\t\t.map((p) => p.id);\n\n\t\tconst aiParticipantIds = participants\n\t\t\t.filter((p) => p.type === \"ai\")\n\t\t\t.map((p) => p.id);\n\n\t\t// Get matching agents\n\t\tconst typingHumanAgents = availableHumanAgents.filter((agent) =>\n\t\t\thumanParticipantIds.includes(agent.id)\n\t\t);\n\n\t\tconst typingAIAgents = availableAIAgents.filter((agent) =>\n\t\t\taiParticipantIds.includes(agent.id)\n\t\t);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\"flex items-center gap-6\", className)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{withAvatars && (\n\t\t\t\t\t<AvatarStack\n\t\t\t\t\t\taiAgents={typingAIAgents}\n\t\t\t\t\t\thumanAgents={typingHumanAgents}\n\t\t\t\t\t\tsize={24}\n\t\t\t\t\t\tspacing={16}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<BouncingDots />\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nTypingIndicator.displayName = \"TypingIndicator\";\n"],"mappings":";;;;;;AAmBA,MAAa,gBAAgB,EAC5B,gBAIA,qBAAC;CAAI,WAAU;;EACd,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;EACF,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;EACF,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;;EACG;AAGP,MAAa,kBAAkBA,QAAM,YAKnC,EACC,cACA,oBAAoB,EAAE,EACtB,uBAAuB,EAAE,EACzB,cAAc,MACd,UACA,GAAG,SAEJ,QACI;AACJ,KAAI,CAAC,gBAAgB,aAAa,WAAW,EAC5C,QAAO;CAIR,MAAM,sBAAsB,aAC1B,QAAQ,MAAM,EAAE,SAAS,cAAc,CACvC,KAAK,MAAM,EAAE,GAAG;CAElB,MAAM,mBAAmB,aACvB,QAAQ,MAAM,EAAE,SAAS,KAAK,CAC9B,KAAK,MAAM,EAAE,GAAG;CAGlB,MAAM,oBAAoB,qBAAqB,QAAQ,UACtD,oBAAoB,SAAS,MAAM,GAAG,CACtC;CAED,MAAM,iBAAiB,kBAAkB,QAAQ,UAChD,iBAAiB,SAAS,MAAM,GAAG,CACnC;AAED,QACC,qBAAC;EACA,WAAW,GAAG,2BAA2B,UAAU;EAC9C;EACL,GAAI;aAEH,eACA,oBAAC;GACA,UAAU;GACV,aAAa;GACb,MAAM;GACN,SAAS;IACR,EAEH,oBAAC,iBAAe;GACX;EAGR;AAED,gBAAgB,cAAc"}
1
+ {"version":3,"file":"typing-indicator.js","names":["React"],"sources":["../../../src/support/components/typing-indicator.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport * as React from \"react\";\nimport { cn } from \"../utils\";\nimport { AvatarStack } from \"./avatar-stack\";\n\nexport type TypingParticipantType = \"visitor\" | \"team_member\" | \"ai\";\n\nexport type TypingParticipant = {\n\tid: string;\n\ttype: TypingParticipantType;\n};\n\nexport type TypingIndicatorProps = React.HTMLAttributes<HTMLDivElement> & {\n\tparticipants: TypingParticipant[];\n\tavailableAIAgents?: AvailableAIAgent[];\n\tavailableHumanAgents?: AvailableHumanAgent[];\n\twithAvatars?: boolean;\n};\n\nexport const BouncingDots = ({\n\tclassName,\n}: {\n\tclassName?: string;\n}): React.ReactElement => (\n\t<div className=\"flex gap-1\">\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-1 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-2 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"dot-bounce-3 size-1 rounded-full bg-co-primary\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t/>\n\t</div>\n);\n\nexport const TypingIndicator = React.forwardRef<\n\tHTMLDivElement,\n\tTypingIndicatorProps\n>(\n\t(\n\t\t{\n\t\t\tparticipants,\n\t\t\tavailableAIAgents = [],\n\t\t\tavailableHumanAgents = [],\n\t\t\twithAvatars = true,\n\t\t\tclassName,\n\t\t\t...props\n\t\t},\n\t\tref\n\t) => {\n\t\tif (!participants || participants.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Separate AI and human participants\n\t\tconst humanParticipantIds = participants\n\t\t\t.filter((p) => p.type === \"team_member\")\n\t\t\t.map((p) => p.id);\n\n\t\tconst aiParticipantIds = participants\n\t\t\t.filter((p) => p.type === \"ai\")\n\t\t\t.map((p) => p.id);\n\n\t\t// Get matching agents\n\t\tconst typingHumanAgents = availableHumanAgents.filter((agent) =>\n\t\t\thumanParticipantIds.includes(agent.id)\n\t\t);\n\n\t\tconst typingAIAgents = availableAIAgents.filter((agent) =>\n\t\t\taiParticipantIds.includes(agent.id)\n\t\t);\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\"flex items-center gap-6\", className)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{withAvatars && (\n\t\t\t\t\t<AvatarStack\n\t\t\t\t\t\taiAgents={typingAIAgents}\n\t\t\t\t\t\thideDefaultAIAgent={typingAIAgents.length === 0}\n\t\t\t\t\t\thumanAgents={typingHumanAgents}\n\t\t\t\t\t\tsize={24}\n\t\t\t\t\t\tspacing={16}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<BouncingDots />\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nTypingIndicator.displayName = \"TypingIndicator\";\n"],"mappings":";;;;;;AAmBA,MAAa,gBAAgB,EAC5B,gBAIA,qBAAC;CAAI,WAAU;;EACd,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;EACF,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;EACF,oBAAC,UACA,WAAW,GACV,kDACA,UACA,GACA;;EACG;AAGP,MAAa,kBAAkBA,QAAM,YAKnC,EACC,cACA,oBAAoB,EAAE,EACtB,uBAAuB,EAAE,EACzB,cAAc,MACd,UACA,GAAG,SAEJ,QACI;AACJ,KAAI,CAAC,gBAAgB,aAAa,WAAW,EAC5C,QAAO;CAIR,MAAM,sBAAsB,aAC1B,QAAQ,MAAM,EAAE,SAAS,cAAc,CACvC,KAAK,MAAM,EAAE,GAAG;CAElB,MAAM,mBAAmB,aACvB,QAAQ,MAAM,EAAE,SAAS,KAAK,CAC9B,KAAK,MAAM,EAAE,GAAG;CAGlB,MAAM,oBAAoB,qBAAqB,QAAQ,UACtD,oBAAoB,SAAS,MAAM,GAAG,CACtC;CAED,MAAM,iBAAiB,kBAAkB,QAAQ,UAChD,iBAAiB,SAAS,MAAM,GAAG,CACnC;AAED,QACC,qBAAC;EACA,WAAW,GAAG,2BAA2B,UAAU;EAC9C;EACL,GAAI;aAEH,eACA,oBAAC;GACA,UAAU;GACV,oBAAoB,eAAe,WAAW;GAC9C,aAAa;GACb,MAAM;GACN,SAAS;IACR,EAEH,oBAAC,iBAAe;GACX;EAGR;AAED,gBAAgB,cAAc"}
@@ -0,0 +1,46 @@
1
+ import * as React$1 from "react";
2
+
3
+ //#region src/support/context/controlled-state.d.ts
4
+
5
+ /**
6
+ * Controlled state context for the Support widget.
7
+ * Allows external control of widget open/close state.
8
+ */
9
+ type ControlledStateContextValue = {
10
+ /**
11
+ * Controlled open state (undefined = uncontrolled)
12
+ */
13
+ open: boolean | undefined;
14
+ /**
15
+ * Callback when open state should change
16
+ */
17
+ onOpenChange: ((open: boolean) => void) | undefined;
18
+ /**
19
+ * Whether the component is in controlled mode
20
+ */
21
+ isControlled: boolean;
22
+ };
23
+ type ControlledStateProviderProps = {
24
+ /**
25
+ * Controlled open state
26
+ */
27
+ open?: boolean;
28
+ /**
29
+ * Callback when open state changes
30
+ */
31
+ onOpenChange?: (open: boolean) => void;
32
+ children: React$1.ReactNode;
33
+ };
34
+ /**
35
+ * Provider for controlled widget state.
36
+ * Wraps the Support component to enable controlled mode.
37
+ */
38
+ declare const ControlledStateProvider: React$1.FC<ControlledStateProviderProps>;
39
+ /**
40
+ * Access controlled state context.
41
+ * Returns null if not inside a ControlledStateProvider.
42
+ */
43
+ declare function useControlledState(): ControlledStateContextValue | null;
44
+ //#endregion
45
+ export { ControlledStateContextValue, ControlledStateProvider, ControlledStateProviderProps, useControlledState };
46
+ //# sourceMappingURL=controlled-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controlled-state.d.ts","names":[],"sources":["../../../src/support/context/controlled-state.tsx"],"sourcesContent":[],"mappings":";;;;;;AAQA;AAkBA;AAgBa,KAlCD,2BAAA,GAmDX;EAMe;;;;;;;;;;;;;KAvCJ,4BAAA;;;;;;;;;YASD,OAAA,CAAM;;;;;;cAOJ,yBAAyB,OAAA,CAAM,GAC3C;;;;;iBAsBe,kBAAA,CAAA,GAAsB"}
@@ -0,0 +1,34 @@
1
+ "use client";
2
+
3
+
4
+ import * as React$1 from "react";
5
+ import { jsx } from "react/jsx-runtime";
6
+
7
+ //#region src/support/context/controlled-state.tsx
8
+ const ControlledStateContext = React$1.createContext(null);
9
+ /**
10
+ * Provider for controlled widget state.
11
+ * Wraps the Support component to enable controlled mode.
12
+ */
13
+ const ControlledStateProvider = ({ open, onOpenChange, children }) => {
14
+ const value = React$1.useMemo(() => ({
15
+ open,
16
+ onOpenChange,
17
+ isControlled: open !== void 0
18
+ }), [open, onOpenChange]);
19
+ return /* @__PURE__ */ jsx(ControlledStateContext.Provider, {
20
+ value,
21
+ children
22
+ });
23
+ };
24
+ /**
25
+ * Access controlled state context.
26
+ * Returns null if not inside a ControlledStateProvider.
27
+ */
28
+ function useControlledState() {
29
+ return React$1.useContext(ControlledStateContext);
30
+ }
31
+
32
+ //#endregion
33
+ export { ControlledStateProvider, useControlledState };
34
+ //# sourceMappingURL=controlled-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controlled-state.js","names":["React","ControlledStateProvider: React.FC<\n\tControlledStateProviderProps\n>"],"sources":["../../../src/support/context/controlled-state.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\n/**\n * Controlled state context for the Support widget.\n * Allows external control of widget open/close state.\n */\nexport type ControlledStateContextValue = {\n\t/**\n\t * Controlled open state (undefined = uncontrolled)\n\t */\n\topen: boolean | undefined;\n\t/**\n\t * Callback when open state should change\n\t */\n\tonOpenChange: ((open: boolean) => void) | undefined;\n\t/**\n\t * Whether the component is in controlled mode\n\t */\n\tisControlled: boolean;\n};\n\nconst ControlledStateContext =\n\tReact.createContext<ControlledStateContextValue | null>(null);\n\nexport type ControlledStateProviderProps = {\n\t/**\n\t * Controlled open state\n\t */\n\topen?: boolean;\n\t/**\n\t * Callback when open state changes\n\t */\n\tonOpenChange?: (open: boolean) => void;\n\tchildren: React.ReactNode;\n};\n\n/**\n * Provider for controlled widget state.\n * Wraps the Support component to enable controlled mode.\n */\nexport const ControlledStateProvider: React.FC<\n\tControlledStateProviderProps\n> = ({ open, onOpenChange, children }) => {\n\tconst value = React.useMemo<ControlledStateContextValue>(\n\t\t() => ({\n\t\t\topen,\n\t\t\tonOpenChange,\n\t\t\tisControlled: open !== undefined,\n\t\t}),\n\t\t[open, onOpenChange]\n\t);\n\n\treturn (\n\t\t<ControlledStateContext.Provider value={value}>\n\t\t\t{children}\n\t\t</ControlledStateContext.Provider>\n\t);\n};\n\n/**\n * Access controlled state context.\n * Returns null if not inside a ControlledStateProvider.\n */\nexport function useControlledState(): ControlledStateContextValue | null {\n\treturn React.useContext(ControlledStateContext);\n}\n"],"mappings":";;;;;;;AAuBA,MAAM,yBACLA,QAAM,cAAkD,KAAK;;;;;AAkB9D,MAAaC,2BAER,EAAE,MAAM,cAAc,eAAe;CACzC,MAAM,QAAQD,QAAM,eACZ;EACN;EACA;EACA,cAAc,SAAS;EACvB,GACD,CAAC,MAAM,aAAa,CACpB;AAED,QACC,oBAAC,uBAAuB;EAAgB;EACtC;GACgC;;;;;;AAQpC,SAAgB,qBAAyD;AACxE,QAAOA,QAAM,WAAW,uBAAuB"}
@@ -0,0 +1,103 @@
1
+ import { TimelineItem } from "../../timeline-item.js";
2
+ import * as React$1 from "react";
3
+ import { Conversation } from "@cossistant/types";
4
+
5
+ //#region src/support/context/events.d.ts
6
+ type SupportEventType = "conversationStart" | "conversationEnd" | "messageSent" | "messageReceived" | "error";
7
+ type ConversationStartEvent = {
8
+ type: "conversationStart";
9
+ conversationId: string;
10
+ conversation?: Conversation;
11
+ };
12
+ type ConversationEndEvent = {
13
+ type: "conversationEnd";
14
+ conversationId: string;
15
+ conversation?: Conversation;
16
+ };
17
+ type MessageSentEvent = {
18
+ type: "messageSent";
19
+ conversationId: string;
20
+ message: TimelineItem;
21
+ };
22
+ type MessageReceivedEvent = {
23
+ type: "messageReceived";
24
+ conversationId: string;
25
+ message: TimelineItem;
26
+ };
27
+ type ErrorEvent = {
28
+ type: "error";
29
+ error: Error;
30
+ context?: string;
31
+ };
32
+ type SupportEvent = ConversationStartEvent | ConversationEndEvent | MessageSentEvent | MessageReceivedEvent | ErrorEvent;
33
+ type SupportEventCallbacks = {
34
+ /**
35
+ * Called when a new conversation is started.
36
+ */
37
+ onConversationStart?: (event: ConversationStartEvent) => void;
38
+ /**
39
+ * Called when a conversation ends (resolved, closed, etc.).
40
+ */
41
+ onConversationEnd?: (event: ConversationEndEvent) => void;
42
+ /**
43
+ * Called when the visitor sends a message.
44
+ */
45
+ onMessageSent?: (event: MessageSentEvent) => void;
46
+ /**
47
+ * Called when a message is received from an agent (human or AI).
48
+ */
49
+ onMessageReceived?: (event: MessageReceivedEvent) => void;
50
+ /**
51
+ * Called when an error occurs.
52
+ */
53
+ onError?: (event: ErrorEvent) => void;
54
+ };
55
+ type SupportEventsContextValue = {
56
+ /**
57
+ * Emit an event to all registered callbacks.
58
+ */
59
+ emit: <T extends SupportEvent>(event: T) => void;
60
+ /**
61
+ * Subscribe to a specific event type.
62
+ * Returns an unsubscribe function.
63
+ */
64
+ subscribe: <T extends SupportEventType>(type: T, callback: (event: Extract<SupportEvent, {
65
+ type: T;
66
+ }>) => void) => () => void;
67
+ };
68
+ type SupportEventsProviderProps = SupportEventCallbacks & {
69
+ children: React$1.ReactNode;
70
+ };
71
+ /**
72
+ * Provider for support widget events.
73
+ * Allows listening to lifecycle events like message sent/received,
74
+ * conversation start/end, and errors.
75
+ *
76
+ * @example
77
+ * <Support
78
+ * onMessageSent={({ message }) => console.log("Sent:", message)}
79
+ * onMessageReceived={({ message }) => console.log("Received:", message)}
80
+ * onConversationStart={({ conversationId }) => console.log("Started:", conversationId)}
81
+ * onError={({ error }) => console.error("Error:", error)}
82
+ * />
83
+ */
84
+ declare const SupportEventsProvider: React$1.FC<SupportEventsProviderProps>;
85
+ /**
86
+ * Access the events context.
87
+ * Returns null if not inside a SupportEventsProvider.
88
+ */
89
+ declare function useSupportEvents(): SupportEventsContextValue | null;
90
+ /**
91
+ * Hook to emit events from within the widget.
92
+ * Safe to use outside of provider (will no-op).
93
+ */
94
+ declare function useSupportEventEmitter(): {
95
+ emitConversationStart: (conversationId: string, conversation?: Conversation) => void;
96
+ emitConversationEnd: (conversationId: string, conversation?: Conversation) => void;
97
+ emitMessageSent: (conversationId: string, message: TimelineItem) => void;
98
+ emitMessageReceived: (conversationId: string, message: TimelineItem) => void;
99
+ emitError: (error: Error, context?: string) => void;
100
+ };
101
+ //#endregion
102
+ export { ConversationEndEvent, ConversationStartEvent, ErrorEvent, MessageReceivedEvent, MessageSentEvent, SupportEvent, SupportEventCallbacks, SupportEventType, SupportEventsContextValue, SupportEventsProvider, SupportEventsProviderProps, useSupportEventEmitter, useSupportEvents };
103
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","names":[],"sources":["../../../src/support/context/events.tsx"],"sourcesContent":[],"mappings":";;;;;KAUY,gBAAA;KAOA,sBAAA;EAPA,IAAA,EAAA,mBAAgB;EAOhB,cAAA,EAAA,MAAA;EAMA,YAAA,CAAA,EAHI,YAGgB;AAMhC,CAAA;AAMY,KAZA,oBAAA,GAYoB;EAMpB,IAAA,EAAA,iBAAU;EAMV,cAAA,EAAY,MAAA;EACrB,YAAA,CAAA,EAtBa,YAsBb;CACA;AACA,KArBS,gBAAA,GAqBT;EACA,IAAA,EAAA,aAAA;EACA,cAAA,EAAA,MAAA;EAAU,OAAA,EApBH,YAoBG;AAMb,CAAA;AAI+B,KA3BnB,oBAAA,GA2BmB;EAIF,IAAA,EAAA,iBAAA;EAIJ,cAAA,EAAA,MAAA;EAII,OAAA,EApCnB,YAoCmB;CAIV;AAAU,KArCjB,UAAA,GAqCiB;EAOjB,IAAA,EAAA,OAAA;EAIM,KAAA,EA9CV,KA8CU;EAAqB,OAAA,CAAA,EAAA,MAAA;CAKhB;AACf,KAhDI,YAAA,GACT,sBA+CK,GA9CL,oBA8CK,GA7CL,gBA6CK,GA5CL,oBA4CK,GA3CL,UA2CK;AACoB,KAtChB,qBAAA,GAsCgB;EAAsB;;;EAOtC,mBAAA,CAAA,EAAA,CAAA,KAAA,EAzCmB,sBAyCU,EAAA,GAAA,IAAA;EAiB5B;AA0Gb;AAQA;EAOmB,iBAAA,CAAA,EAAA,CAAA,KAAA,EA/KU,oBA+KV,EAAA,GAAA,IAAA;EAUA;;;EAsBG,aAAA,CAAA,EAAA,CAAA,KAAA,EA3MG,gBA2MH,EAAA,GAAA,IAAA;EAAK;;;8BAvME;;;;oBAIV;;KAOP,yBAAA;;;;mBAIM,qBAAqB;;;;;wBAKhB,wBACf,qBACY,QAAQ;UAAsB;;;KAOtC,0BAAA,GAA6B;YAC9B,OAAA,CAAM;;;;;;;;;;;;;;;cAgBJ,uBAAuB,OAAA,CAAM,GAAG;;;;;iBA0G7B,gBAAA,CAAA,GAAoB;;;;;iBAQpB,sBAAA,CAAA;iEAOG;+DAUA;qDAQmC;yDAOI;qBAOpC"}