@cossistant/react 0.0.3 → 0.0.5

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 (320) hide show
  1. package/README.md +74 -0
  2. package/_virtual/rolldown_runtime.js +19 -0
  3. package/conversation.d.ts +26 -3
  4. package/conversation.d.ts.map +1 -1
  5. package/hooks/index.d.ts +5 -3
  6. package/hooks/index.js +7 -5
  7. package/hooks/private/store/use-conversations-store.d.ts +8 -0
  8. package/hooks/private/store/use-conversations-store.d.ts.map +1 -1
  9. package/hooks/private/store/use-conversations-store.js +8 -0
  10. package/hooks/private/store/use-conversations-store.js.map +1 -1
  11. package/hooks/private/store/use-store-selector.d.ts +4 -0
  12. package/hooks/private/store/use-store-selector.d.ts.map +1 -1
  13. package/hooks/private/store/use-store-selector.js +5 -2
  14. package/hooks/private/store/use-store-selector.js.map +1 -1
  15. package/hooks/private/store/use-website-store.d.ts +4 -0
  16. package/hooks/private/store/use-website-store.d.ts.map +1 -1
  17. package/hooks/private/store/use-website-store.js +6 -3
  18. package/hooks/private/store/use-website-store.js.map +1 -1
  19. package/hooks/private/typing.d.ts +35 -0
  20. package/hooks/private/typing.d.ts.map +1 -0
  21. package/hooks/private/typing.js +49 -0
  22. package/hooks/private/typing.js.map +1 -0
  23. package/hooks/private/use-client-query.d.ts +5 -0
  24. package/hooks/private/use-client-query.d.ts.map +1 -1
  25. package/hooks/private/use-client-query.js +5 -0
  26. package/hooks/private/use-client-query.js.map +1 -1
  27. package/hooks/private/use-grouped-messages.d.ts +10 -4
  28. package/hooks/private/use-grouped-messages.d.ts.map +1 -1
  29. package/hooks/private/use-grouped-messages.js +24 -4
  30. package/hooks/private/use-grouped-messages.js.map +1 -1
  31. package/hooks/private/use-multimodal-input.d.ts.map +1 -1
  32. package/hooks/private/use-rest-client.d.ts.map +1 -1
  33. package/hooks/private/use-visitor-typing-reporter.d.ts +6 -0
  34. package/hooks/private/use-visitor-typing-reporter.d.ts.map +1 -1
  35. package/hooks/private/use-visitor-typing-reporter.js +6 -0
  36. package/hooks/private/use-visitor-typing-reporter.js.map +1 -1
  37. package/hooks/use-composer-refocus.d.ts.map +1 -1
  38. package/hooks/use-conversation-auto-seen.d.ts +9 -0
  39. package/hooks/use-conversation-auto-seen.d.ts.map +1 -1
  40. package/hooks/use-conversation-auto-seen.js +44 -3
  41. package/hooks/use-conversation-auto-seen.js.map +1 -1
  42. package/hooks/use-conversation-history-page.d.ts.map +1 -1
  43. package/hooks/use-conversation-history-page.js +16 -18
  44. package/hooks/use-conversation-history-page.js.map +1 -1
  45. package/hooks/use-conversation-lifecycle.d.ts.map +1 -1
  46. package/hooks/use-conversation-lifecycle.js +2 -4
  47. package/hooks/use-conversation-lifecycle.js.map +1 -1
  48. package/hooks/use-conversation-page.d.ts +6 -0
  49. package/hooks/use-conversation-page.d.ts.map +1 -1
  50. package/hooks/use-conversation-page.js +41 -3
  51. package/hooks/use-conversation-page.js.map +1 -1
  52. package/hooks/use-conversation-preview.d.ts +61 -0
  53. package/hooks/use-conversation-preview.d.ts.map +1 -0
  54. package/hooks/use-conversation-preview.js +173 -0
  55. package/hooks/use-conversation-preview.js.map +1 -0
  56. package/hooks/use-conversation-seen.d.ts +4 -0
  57. package/hooks/use-conversation-seen.d.ts.map +1 -1
  58. package/hooks/use-conversation-seen.js +4 -0
  59. package/hooks/use-conversation-seen.js.map +1 -1
  60. package/hooks/use-conversation-timeline-items.d.ts +4 -0
  61. package/hooks/use-conversation-timeline-items.d.ts.map +1 -1
  62. package/hooks/use-conversation-timeline-items.js +4 -0
  63. package/hooks/use-conversation-timeline-items.js.map +1 -1
  64. package/hooks/use-conversation-timeline.d.ts +32 -0
  65. package/hooks/use-conversation-timeline.d.ts.map +1 -0
  66. package/hooks/use-conversation-timeline.js +41 -0
  67. package/hooks/use-conversation-timeline.js.map +1 -0
  68. package/hooks/use-conversation-typing.d.ts +4 -0
  69. package/hooks/use-conversation-typing.d.ts.map +1 -1
  70. package/hooks/use-conversation-typing.js +4 -0
  71. package/hooks/use-conversation-typing.js.map +1 -1
  72. package/hooks/use-conversation.d.ts +11 -0
  73. package/hooks/use-conversation.d.ts.map +1 -1
  74. package/hooks/use-conversation.js +11 -0
  75. package/hooks/use-conversation.js.map +1 -1
  76. package/hooks/use-conversations.d.ts +12 -0
  77. package/hooks/use-conversations.d.ts.map +1 -1
  78. package/hooks/use-conversations.js +12 -0
  79. package/hooks/use-conversations.js.map +1 -1
  80. package/hooks/use-create-conversation.d.ts +5 -0
  81. package/hooks/use-create-conversation.d.ts.map +1 -1
  82. package/hooks/use-create-conversation.js +12 -9
  83. package/hooks/use-create-conversation.js.map +1 -1
  84. package/hooks/use-home-page.d.ts.map +1 -1
  85. package/hooks/use-home-page.js +6 -4
  86. package/hooks/use-home-page.js.map +1 -1
  87. package/hooks/use-message-composer.d.ts.map +1 -1
  88. package/hooks/use-realtime-support.d.ts.map +1 -1
  89. package/hooks/use-send-message.d.ts +9 -0
  90. package/hooks/use-send-message.d.ts.map +1 -1
  91. package/hooks/use-send-message.js +15 -13
  92. package/hooks/use-send-message.js.map +1 -1
  93. package/hooks/use-visitor.d.ts.map +1 -1
  94. package/hooks/use-visitor.js +28 -30
  95. package/hooks/use-visitor.js.map +1 -1
  96. package/hooks/use-window-visibility-focus.d.ts +4 -0
  97. package/hooks/use-window-visibility-focus.d.ts.map +1 -1
  98. package/hooks/use-window-visibility-focus.js +5 -2
  99. package/hooks/use-window-visibility-focus.js.map +1 -1
  100. package/identify-visitor.d.ts +12 -3
  101. package/identify-visitor.d.ts.map +1 -1
  102. package/identify-visitor.js +58 -9
  103. package/identify-visitor.js.map +1 -1
  104. package/index.d.ts +10 -7
  105. package/index.js +10 -9
  106. package/package.json +14 -17
  107. package/primitives/avatar/avatar.d.ts.map +1 -1
  108. package/primitives/avatar/fallback.d.ts.map +1 -1
  109. package/primitives/avatar/fallback.js +1 -3
  110. package/primitives/avatar/fallback.js.map +1 -1
  111. package/primitives/avatar/image.d.ts.map +1 -1
  112. package/primitives/avatar/index.d.ts +1 -0
  113. package/primitives/bubble.d.ts +2 -0
  114. package/primitives/bubble.d.ts.map +1 -1
  115. package/primitives/bubble.js +8 -2
  116. package/primitives/bubble.js.map +1 -1
  117. package/primitives/button.d.ts.map +1 -1
  118. package/primitives/conversation-timeline.d.ts.map +1 -1
  119. package/primitives/conversation-timeline.js +58 -5
  120. package/primitives/conversation-timeline.js.map +1 -1
  121. package/primitives/index.d.ts +1 -0
  122. package/primitives/index.parts.d.ts +1 -0
  123. package/primitives/multimodal-input.d.ts.map +1 -1
  124. package/primitives/timeline-item-group.d.ts +7 -7
  125. package/primitives/timeline-item-group.d.ts.map +1 -1
  126. package/primitives/timeline-item-group.js.map +1 -1
  127. package/primitives/timeline-item.d.ts +1 -1
  128. package/primitives/timeline-item.d.ts.map +1 -1
  129. package/primitives/timeline-item.js +7 -1
  130. package/primitives/timeline-item.js.map +1 -1
  131. package/primitives/window.d.ts +1 -1
  132. package/primitives/window.d.ts.map +1 -1
  133. package/primitives/window.js +4 -4
  134. package/primitives/window.js.map +1 -1
  135. package/provider.d.ts +23 -43
  136. package/provider.d.ts.map +1 -1
  137. package/provider.js +152 -49
  138. package/provider.js.map +1 -1
  139. package/realtime/event-filter.d.ts +4 -0
  140. package/realtime/event-filter.d.ts.map +1 -1
  141. package/realtime/event-filter.js +4 -0
  142. package/realtime/event-filter.js.map +1 -1
  143. package/realtime/index.js +1 -1
  144. package/realtime/provider.d.ts +7 -2
  145. package/realtime/provider.d.ts.map +1 -1
  146. package/realtime/provider.js +23 -1
  147. package/realtime/provider.js.map +1 -1
  148. package/realtime/seen-store.d.ts +13 -0
  149. package/realtime/seen-store.d.ts.map +1 -1
  150. package/realtime/seen-store.js +14 -2
  151. package/realtime/seen-store.js.map +1 -1
  152. package/realtime/support-provider.d.ts +1 -2
  153. package/realtime/support-provider.d.ts.map +1 -1
  154. package/realtime/support-provider.js +19 -20
  155. package/realtime/support-provider.js.map +1 -1
  156. package/realtime/typing-store.d.ts +18 -0
  157. package/realtime/typing-store.d.ts.map +1 -1
  158. package/realtime/typing-store.js +19 -2
  159. package/realtime/typing-store.js.map +1 -1
  160. package/realtime/use-realtime.d.ts +8 -4
  161. package/realtime/use-realtime.d.ts.map +1 -1
  162. package/realtime/use-realtime.js +4 -0
  163. package/realtime/use-realtime.js.map +1 -1
  164. package/realtime-events.d.ts +17 -3
  165. package/realtime-events.d.ts.map +1 -1
  166. package/schemas.d.ts +7 -1
  167. package/schemas.d.ts.map +1 -1
  168. package/support/components/avatar-stack.d.ts +8 -4
  169. package/support/components/avatar-stack.d.ts.map +1 -1
  170. package/support/components/avatar-stack.js +4 -0
  171. package/support/components/avatar-stack.js.map +1 -1
  172. package/support/components/avatar.d.ts +11 -6
  173. package/support/components/avatar.d.ts.map +1 -1
  174. package/support/components/avatar.js +4 -0
  175. package/support/components/avatar.js.map +1 -1
  176. package/support/components/bubble.d.ts.map +1 -1
  177. package/support/components/bubble.js +29 -6
  178. package/support/components/bubble.js.map +1 -1
  179. package/support/components/button.d.ts +8 -5
  180. package/support/components/button.d.ts.map +1 -1
  181. package/support/components/button.js +5 -1
  182. package/support/components/button.js.map +1 -1
  183. package/support/components/container.d.ts +0 -1
  184. package/support/components/container.d.ts.map +1 -1
  185. package/support/components/container.js +2 -8
  186. package/support/components/container.js.map +1 -1
  187. package/support/components/conversation-button-link.d.ts +8 -21
  188. package/support/components/conversation-button-link.d.ts.map +1 -1
  189. package/support/components/conversation-button-link.js +62 -178
  190. package/support/components/conversation-button-link.js.map +1 -1
  191. package/support/components/conversation-event.d.ts.map +1 -1
  192. package/support/components/conversation-event.js +4 -0
  193. package/support/components/conversation-event.js.map +1 -1
  194. package/support/components/conversation-timeline.d.ts +10 -1
  195. package/support/components/conversation-timeline.d.ts.map +1 -1
  196. package/support/components/conversation-timeline.js +63 -57
  197. package/support/components/conversation-timeline.js.map +1 -1
  198. package/support/components/cossistant-branding.d.ts +5 -2
  199. package/support/components/cossistant-branding.d.ts.map +1 -1
  200. package/support/components/cossistant-branding.js +3 -0
  201. package/support/components/cossistant-branding.js.map +1 -1
  202. package/support/components/header.d.ts.map +1 -1
  203. package/support/components/header.js +2 -2
  204. package/support/components/header.js.map +1 -1
  205. package/support/components/icons.d.ts.map +1 -1
  206. package/support/components/multimodal-input.d.ts.map +1 -1
  207. package/support/components/multimodal-input.js +5 -24
  208. package/support/components/multimodal-input.js.map +1 -1
  209. package/support/components/navigation-tab.d.ts +7 -2
  210. package/support/components/navigation-tab.d.ts.map +1 -1
  211. package/support/components/navigation-tab.js +4 -0
  212. package/support/components/navigation-tab.js.map +1 -1
  213. package/support/components/support-content.d.ts +1 -1
  214. package/support/components/support-content.d.ts.map +1 -1
  215. package/support/components/support-content.js +7 -10
  216. package/support/components/support-content.js.map +1 -1
  217. package/support/components/text-effect.d.ts +5 -2
  218. package/support/components/text-effect.d.ts.map +1 -1
  219. package/support/components/text-effect.js +4 -0
  220. package/support/components/text-effect.js.map +1 -1
  221. package/support/components/timeline-identification-tool.d.ts +7 -0
  222. package/support/components/timeline-identification-tool.d.ts.map +1 -0
  223. package/support/components/timeline-identification-tool.js +139 -0
  224. package/support/components/timeline-identification-tool.js.map +1 -0
  225. package/support/components/timeline-message-group.d.ts +2 -1
  226. package/support/components/timeline-message-group.d.ts.map +1 -1
  227. package/support/components/timeline-message-group.js +4 -19
  228. package/support/components/timeline-message-group.js.map +1 -1
  229. package/support/components/timeline-message-item.d.ts +6 -2
  230. package/support/components/timeline-message-item.d.ts.map +1 -1
  231. package/support/components/timeline-message-item.js +8 -4
  232. package/support/components/timeline-message-item.js.map +1 -1
  233. package/support/components/typing-indicator.d.ts +5 -2
  234. package/support/components/typing-indicator.d.ts.map +1 -1
  235. package/support/components/typing-indicator.js +4 -4
  236. package/support/components/typing-indicator.js.map +1 -1
  237. package/support/components/watermark.d.ts.map +1 -1
  238. package/support/context/websocket.d.ts +8 -0
  239. package/support/context/websocket.d.ts.map +1 -1
  240. package/support/context/websocket.js +12 -6
  241. package/support/context/websocket.js.map +1 -1
  242. package/support/index.d.ts +8 -8
  243. package/support/index.d.ts.map +1 -1
  244. package/support/index.js +18 -18
  245. package/support/index.js.map +1 -1
  246. package/support/pages/conversation-history.js +46 -54
  247. package/support/pages/conversation-history.js.map +1 -1
  248. package/support/pages/conversation.d.ts +3 -6
  249. package/support/pages/conversation.d.ts.map +1 -1
  250. package/support/pages/conversation.js +19 -9
  251. package/support/pages/conversation.js.map +1 -1
  252. package/support/pages/home.d.ts +2 -2
  253. package/support/pages/home.d.ts.map +1 -1
  254. package/support/pages/home.js +64 -77
  255. package/support/pages/home.js.map +1 -1
  256. package/support/store/support-store.d.ts +18 -2
  257. package/support/store/support-store.d.ts.map +1 -1
  258. package/support/store/support-store.js +20 -5
  259. package/support/store/support-store.js.map +1 -1
  260. package/support/{support-CMoDLQoC.css → support-Ck4jy29i.css} +1 -2
  261. package/support/support-Ck4jy29i.css.map +1 -0
  262. package/support/text/index.d.ts +15 -2
  263. package/support/text/index.d.ts.map +1 -1
  264. package/support/text/index.js +15 -2
  265. package/support/text/index.js.map +1 -1
  266. package/support/text/locales/en.js +22 -4
  267. package/support/text/locales/en.js.map +1 -1
  268. package/support/text/locales/es.js +18 -0
  269. package/support/text/locales/es.js.map +1 -1
  270. package/support/text/locales/fr.js +18 -0
  271. package/support/text/locales/fr.js.map +1 -1
  272. package/support/text/locales/keys.d.ts +69 -9
  273. package/support/text/locales/keys.d.ts.map +1 -1
  274. package/support/text/locales/keys.js +18 -0
  275. package/support/text/locales/keys.js.map +1 -1
  276. package/support/text/runtime.d.ts +21 -0
  277. package/support/text/runtime.d.ts.map +1 -1
  278. package/support/text/runtime.js +21 -0
  279. package/support/text/runtime.js.map +1 -1
  280. package/support/utils/index.d.ts +4 -0
  281. package/support/utils/index.d.ts.map +1 -1
  282. package/support/utils/index.js +4 -1
  283. package/support/utils/index.js.map +1 -1
  284. package/support/utils/time.d.ts +3 -0
  285. package/support/utils/time.d.ts.map +1 -1
  286. package/support/utils/time.js +3 -0
  287. package/support/utils/time.js.map +1 -1
  288. package/support-config.d.ts +2 -1
  289. package/support-config.d.ts.map +1 -1
  290. package/support-config.js.map +1 -1
  291. package/support.css +2 -2
  292. package/timeline-item.d.ts +10 -0
  293. package/timeline-item.d.ts.map +1 -1
  294. package/utils/conversation.d.ts +7 -0
  295. package/utils/conversation.d.ts.map +1 -0
  296. package/utils/conversation.js +18 -0
  297. package/utils/conversation.js.map +1 -0
  298. package/utils/id.d.ts +3 -0
  299. package/utils/id.d.ts.map +1 -1
  300. package/utils/id.js +3 -0
  301. package/utils/id.js.map +1 -1
  302. package/utils/index.d.ts +2 -1
  303. package/utils/index.js +2 -1
  304. package/utils/metadata-hash.d.ts +12 -0
  305. package/utils/metadata-hash.d.ts.map +1 -0
  306. package/utils/metadata-hash.js +26 -0
  307. package/utils/metadata-hash.js.map +1 -0
  308. package/utils/text.d.ts +3 -0
  309. package/utils/text.d.ts.map +1 -1
  310. package/utils/text.js +3 -0
  311. package/utils/text.js.map +1 -1
  312. package/utils/use-render-element.d.ts +3 -0
  313. package/utils/use-render-element.d.ts.map +1 -1
  314. package/utils/use-render-element.js +3 -0
  315. package/utils/use-render-element.js.map +1 -1
  316. package/support/context/config.d.ts +0 -32
  317. package/support/context/config.d.ts.map +0 -1
  318. package/support/context/config.js +0 -27
  319. package/support/context/config.js.map +0 -1
  320. package/support/support-CMoDLQoC.css.map +0 -1
@@ -19,38 +19,36 @@ function useVisitor() {
19
19
  const { website, client } = useSupport();
20
20
  const visitor = website?.visitor || null;
21
21
  const visitorId = visitor?.id ?? null;
22
- const setVisitorMetadata = useCallback(async (metadata) => {
23
- if (!visitorId) {
24
- safeWarn("No visitor is associated with this session; metadata update skipped");
25
- return null;
26
- }
27
- try {
28
- return await client.updateVisitorMetadata(metadata);
29
- } catch (error) {
30
- safeError("Failed to update visitor metadata", error);
31
- return null;
32
- }
33
- }, [client, visitorId]);
34
- const identify = useCallback(async (params) => {
35
- if (!visitorId) {
36
- safeWarn("No visitor is associated with this session; identify skipped");
37
- return null;
38
- }
39
- try {
40
- const result = await client.identify(params);
41
- return {
42
- contactId: result.contact.id,
43
- visitorId: result.visitorId
44
- };
45
- } catch (error) {
46
- safeError("Failed to identify visitor", error);
47
- return null;
48
- }
49
- }, [client, visitorId]);
50
22
  return {
51
23
  visitor,
52
- setVisitorMetadata,
53
- identify
24
+ setVisitorMetadata: useCallback(async (metadata) => {
25
+ if (!visitorId) {
26
+ safeWarn("No visitor is associated with this session; metadata update skipped");
27
+ return null;
28
+ }
29
+ try {
30
+ return await client.updateVisitorMetadata(metadata);
31
+ } catch (error) {
32
+ safeError("Failed to update visitor metadata", error);
33
+ return null;
34
+ }
35
+ }, [client, visitorId]),
36
+ identify: useCallback(async (params) => {
37
+ if (!visitorId) {
38
+ safeWarn("No visitor is associated with this session; identify skipped");
39
+ return null;
40
+ }
41
+ try {
42
+ const result = await client.identify(params);
43
+ return {
44
+ contactId: result.contact.id,
45
+ visitorId: result.visitorId
46
+ };
47
+ } catch (error) {
48
+ safeError("Failed to identify visitor", error);
49
+ return null;
50
+ }
51
+ }, [client, visitorId])
54
52
  };
55
53
  }
56
54
 
@@ -1 +1 @@
1
- {"version":3,"file":"use-visitor.js","names":[],"sources":["../../src/hooks/use-visitor.ts"],"sourcesContent":["import type {\n\tPublicVisitor,\n\tVisitorMetadata,\n\tVisitorResponse,\n} from \"@cossistant/types\";\nimport { useCallback } from \"react\";\nimport { useSupport } from \"../provider\";\n\nexport type UseVisitorReturn = {\n\tvisitor: PublicVisitor | null;\n\tsetVisitorMetadata: (\n\t\tmetadata: VisitorMetadata\n\t) => Promise<VisitorResponse | null>;\n\tidentify: (params: {\n\t\texternalId?: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t}) => Promise<{ contactId: string; visitorId: string } | null>;\n};\n\nfunction safeWarn(message: string): void {\n\tif (typeof console !== \"undefined\" && typeof console.warn === \"function\") {\n\t\tconsole.warn(message);\n\t}\n}\n\nfunction safeError(message: string, error: unknown): void {\n\tif (typeof console !== \"undefined\" && typeof console.error === \"function\") {\n\t\tconsole.error(message, error);\n\t}\n}\n\n/**\n * Exposes the current visitor plus helpers to identify and update metadata.\n *\n * Note: Metadata is stored on contacts, not visitors. When you call\n * setVisitorMetadata, it will update the contact metadata if the visitor\n * has been identified. If not, you must call identify() first.\n */\nexport function useVisitor(): UseVisitorReturn {\n\tconst { website, client } = useSupport();\n\tconst visitor = website?.visitor || null;\n\tconst visitorId = visitor?.id ?? null;\n\n\tconst setVisitorMetadata = useCallback<\n\t\t(metadata: VisitorMetadata) => Promise<VisitorResponse | null>\n\t>(\n\t\tasync (metadata) => {\n\t\t\tif (!visitorId) {\n\t\t\t\tsafeWarn(\n\t\t\t\t\t\"No visitor is associated with this session; metadata update skipped\"\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn await client.updateVisitorMetadata(metadata);\n\t\t\t} catch (error) {\n\t\t\t\tsafeError(\"Failed to update visitor metadata\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\t[client, visitorId]\n\t);\n\n\tconst identify = useCallback<\n\t\t(params: {\n\t\t\texternalId?: string;\n\t\t\temail?: string;\n\t\t\tname?: string;\n\t\t\timage?: string;\n\t\t\tmetadata?: Record<string, unknown>;\n\t\t}) => Promise<{ contactId: string; visitorId: string } | null>\n\t>(\n\t\tasync (params) => {\n\t\t\tif (!visitorId) {\n\t\t\t\tsafeWarn(\n\t\t\t\t\t\"No visitor is associated with this session; identify skipped\"\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await client.identify(params);\n\n\t\t\t\treturn {\n\t\t\t\t\tcontactId: result.contact.id,\n\t\t\t\t\tvisitorId: result.visitorId,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tsafeError(\"Failed to identify visitor\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\t[client, visitorId]\n\t);\n\n\treturn {\n\t\tvisitor,\n\t\tsetVisitorMetadata,\n\t\tidentify,\n\t};\n}\n"],"mappings":";;;;AAsBA,SAAS,SAAS,SAAuB;AACxC,KAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,SAAS,WAC7D,SAAQ,KAAK,QAAQ;;AAIvB,SAAS,UAAU,SAAiB,OAAsB;AACzD,KAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,UAAU,WAC9D,SAAQ,MAAM,SAAS,MAAM;;;;;;;;;AAW/B,SAAgB,aAA+B;CAC9C,MAAM,EAAE,SAAS,WAAW,YAAY;CACxC,MAAM,UAAU,SAAS,WAAW;CACpC,MAAM,YAAY,SAAS,MAAM;CAEjC,MAAM,qBAAqB,YAG1B,OAAO,aAAa;AACnB,MAAI,CAAC,WAAW;AACf,YACC,sEACA;AACD,UAAO;;AAGR,MAAI;AACH,UAAO,MAAM,OAAO,sBAAsB,SAAS;WAC3C,OAAO;AACf,aAAU,qCAAqC,MAAM;AACrD,UAAO;;IAGT,CAAC,QAAQ,UAAU,CACnB;CAED,MAAM,WAAW,YAShB,OAAO,WAAW;AACjB,MAAI,CAAC,WAAW;AACf,YACC,+DACA;AACD,UAAO;;AAGR,MAAI;GACH,MAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAE5C,UAAO;IACN,WAAW,OAAO,QAAQ;IAC1B,WAAW,OAAO;IAClB;WACO,OAAO;AACf,aAAU,8BAA8B,MAAM;AAC9C,UAAO;;IAGT,CAAC,QAAQ,UAAU,CACnB;AAED,QAAO;EACN;EACA;EACA;EACA"}
1
+ {"version":3,"file":"use-visitor.js","names":[],"sources":["../../src/hooks/use-visitor.ts"],"sourcesContent":["import type {\n\tPublicVisitor,\n\tVisitorMetadata,\n\tVisitorResponse,\n} from \"@cossistant/types\";\nimport { useCallback } from \"react\";\nimport { useSupport } from \"../provider\";\n\nexport type UseVisitorReturn = {\n\tvisitor: PublicVisitor | null;\n\tsetVisitorMetadata: (\n\t\tmetadata: VisitorMetadata\n\t) => Promise<VisitorResponse | null>;\n\tidentify: (params: {\n\t\texternalId?: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t}) => Promise<{ contactId: string; visitorId: string } | null>;\n};\n\nfunction safeWarn(message: string): void {\n\tif (typeof console !== \"undefined\" && typeof console.warn === \"function\") {\n\t\tconsole.warn(message);\n\t}\n}\n\nfunction safeError(message: string, error: unknown): void {\n\tif (typeof console !== \"undefined\" && typeof console.error === \"function\") {\n\t\tconsole.error(message, error);\n\t}\n}\n\n/**\n * Exposes the current visitor plus helpers to identify and update metadata.\n *\n * Note: Metadata is stored on contacts, not visitors. When you call\n * setVisitorMetadata, it will update the contact metadata if the visitor\n * has been identified. If not, you must call identify() first.\n */\nexport function useVisitor(): UseVisitorReturn {\n\tconst { website, client } = useSupport();\n\tconst visitor = website?.visitor || null;\n\tconst visitorId = visitor?.id ?? null;\n\n\tconst setVisitorMetadata = useCallback<\n\t\t(metadata: VisitorMetadata) => Promise<VisitorResponse | null>\n\t>(\n\t\tasync (metadata) => {\n\t\t\tif (!visitorId) {\n\t\t\t\tsafeWarn(\n\t\t\t\t\t\"No visitor is associated with this session; metadata update skipped\"\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn await client.updateVisitorMetadata(metadata);\n\t\t\t} catch (error) {\n\t\t\t\tsafeError(\"Failed to update visitor metadata\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\t[client, visitorId]\n\t);\n\n\tconst identify = useCallback<\n\t\t(params: {\n\t\t\texternalId?: string;\n\t\t\temail?: string;\n\t\t\tname?: string;\n\t\t\timage?: string;\n\t\t\tmetadata?: Record<string, unknown>;\n\t\t}) => Promise<{ contactId: string; visitorId: string } | null>\n\t>(\n\t\tasync (params) => {\n\t\t\tif (!visitorId) {\n\t\t\t\tsafeWarn(\n\t\t\t\t\t\"No visitor is associated with this session; identify skipped\"\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await client.identify(params);\n\n\t\t\t\treturn {\n\t\t\t\t\tcontactId: result.contact.id,\n\t\t\t\t\tvisitorId: result.visitorId,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tsafeError(\"Failed to identify visitor\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\t[client, visitorId]\n\t);\n\n\treturn {\n\t\tvisitor,\n\t\tsetVisitorMetadata,\n\t\tidentify,\n\t};\n}\n"],"mappings":";;;;AAsBA,SAAS,SAAS,SAAuB;AACxC,KAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,SAAS,WAC7D,SAAQ,KAAK,QAAQ;;AAIvB,SAAS,UAAU,SAAiB,OAAsB;AACzD,KAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,UAAU,WAC9D,SAAQ,MAAM,SAAS,MAAM;;;;;;;;;AAW/B,SAAgB,aAA+B;CAC9C,MAAM,EAAE,SAAS,WAAW,YAAY;CACxC,MAAM,UAAU,SAAS,WAAW;CACpC,MAAM,YAAY,SAAS,MAAM;AAuDjC,QAAO;EACN;EACA,oBAvD0B,YAG1B,OAAO,aAAa;AACnB,OAAI,CAAC,WAAW;AACf,aACC,sEACA;AACD,WAAO;;AAGR,OAAI;AACH,WAAO,MAAM,OAAO,sBAAsB,SAAS;YAC3C,OAAO;AACf,cAAU,qCAAqC,MAAM;AACrD,WAAO;;KAGT,CAAC,QAAQ,UAAU,CACnB;EAqCA,UAnCgB,YAShB,OAAO,WAAW;AACjB,OAAI,CAAC,WAAW;AACf,aACC,+DACA;AACD,WAAO;;AAGR,OAAI;IACH,MAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAE5C,WAAO;KACN,WAAW,OAAO,QAAQ;KAC1B,WAAW,OAAO;KAClB;YACO,OAAO;AACf,cAAU,8BAA8B,MAAM;AAC9C,WAAO;;KAGT,CAAC,QAAQ,UAAU,CACnB;EAMA"}
@@ -3,6 +3,10 @@ type WindowVisibilityFocusState = {
3
3
  isPageVisible: boolean;
4
4
  hasWindowFocus: boolean;
5
5
  };
6
+ /**
7
+ * Tracks document visibility and window focus so hooks can defer updates while
8
+ * the user is away from the page.
9
+ */
6
10
  declare function useWindowVisibilityFocus(): WindowVisibilityFocusState;
7
11
  //#endregion
8
12
  export { WindowVisibilityFocusState, useWindowVisibilityFocus };
@@ -1 +1 @@
1
- {"version":3,"file":"use-window-visibility-focus.d.ts","names":[],"sources":["../../src/hooks/use-window-visibility-focus.ts"],"sourcesContent":[],"mappings":";KAEY,0BAAA;EAAA,aAAA,EAAA,OAAA;EAkBI,cAAA,EAAA,OAAA;;iBAAA,wBAAA,CAAA,GAA4B"}
1
+ {"version":3,"file":"use-window-visibility-focus.d.ts","names":[],"sources":["../../src/hooks/use-window-visibility-focus.ts"],"sourcesContent":[],"mappings":";KAEY,0BAAA;EAAA,aAAA,EAAA,OAAA;EAsBI,cAAA,EAAA,OAAA;;;;;;iBAAA,wBAAA,CAAA,GAA4B"}
@@ -7,12 +7,15 @@ const getVisibilityFocusState = () => {
7
7
  hasWindowFocus: true
8
8
  };
9
9
  const isPageVisible = !document.hidden;
10
- const hasWindowFocus = isPageVisible && (typeof document.hasFocus === "function" ? document.hasFocus() : true);
11
10
  return {
12
11
  isPageVisible,
13
- hasWindowFocus
12
+ hasWindowFocus: isPageVisible && (typeof document.hasFocus === "function" ? document.hasFocus() : true)
14
13
  };
15
14
  };
15
+ /**
16
+ * Tracks document visibility and window focus so hooks can defer updates while
17
+ * the user is away from the page.
18
+ */
16
19
  function useWindowVisibilityFocus() {
17
20
  const [state, setState] = useState(() => getVisibilityFocusState());
18
21
  useEffect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"use-window-visibility-focus.js","names":[],"sources":["../../src/hooks/use-window-visibility-focus.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type WindowVisibilityFocusState = {\n isPageVisible: boolean;\n hasWindowFocus: boolean;\n};\n\nconst getVisibilityFocusState = (): WindowVisibilityFocusState => {\n if (typeof document === \"undefined\") {\n return { isPageVisible: true, hasWindowFocus: true };\n }\n\n const isPageVisible = !document.hidden;\n const hasWindowFocus =\n isPageVisible &&\n (typeof document.hasFocus === \"function\" ? document.hasFocus() : true);\n\n return { isPageVisible, hasWindowFocus };\n};\n\nexport function useWindowVisibilityFocus(): WindowVisibilityFocusState {\n const [state, setState] = useState<WindowVisibilityFocusState>(\n () => getVisibilityFocusState()\n );\n\n useEffect(() => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const handleVisibilityChange = () => {\n setState(getVisibilityFocusState());\n };\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n handleVisibilityChange();\n return () => {\n document.removeEventListener(\n \"visibilitychange\",\n handleVisibilityChange\n );\n };\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") {\n return;\n }\n\n const syncVisibilityFocus = () => {\n setState(getVisibilityFocusState());\n };\n\n const handleFocus = () => {\n syncVisibilityFocus();\n };\n const handleBlur = () => {\n syncVisibilityFocus();\n };\n\n window.addEventListener(\"focus\", handleFocus);\n window.addEventListener(\"blur\", handleBlur);\n\n syncVisibilityFocus();\n\n return () => {\n window.removeEventListener(\"focus\", handleFocus);\n window.removeEventListener(\"blur\", handleBlur);\n };\n }, []);\n\n return state;\n}\n"],"mappings":";;;AAOA,MAAM,gCAA4D;AAC1D,KAAI,OAAO,aAAa,YAChB,QAAO;EAAE,eAAe;EAAM,gBAAgB;EAAM;CAG5D,MAAM,gBAAgB,CAAC,SAAS;CAChC,MAAM,iBACE,kBACC,OAAO,SAAS,aAAa,aAAa,SAAS,UAAU,GAAG;AAEzE,QAAO;EAAE;EAAe;EAAgB;;AAGhD,SAAgB,2BAAuD;CAC/D,MAAM,CAAC,OAAO,YAAY,eACZ,yBAAyB,CACtC;AAED,iBAAgB;AACR,MAAI,OAAO,aAAa,YAChB;EAGR,MAAM,+BAA+B;AAC7B,YAAS,yBAAyB,CAAC;;AAG3C,WAAS,iBAAiB,oBAAoB,uBAAuB;AACrE,0BAAwB;AACxB,eAAa;AACL,YAAS,oBACD,oBACA,uBACP;;IAEd,EAAE,CAAC;AAEN,iBAAgB;AACR,MAAI,OAAO,WAAW,YACd;EAGR,MAAM,4BAA4B;AAC1B,YAAS,yBAAyB,CAAC;;EAG3C,MAAM,oBAAoB;AAClB,wBAAqB;;EAE7B,MAAM,mBAAmB;AACjB,wBAAqB;;AAG7B,SAAO,iBAAiB,SAAS,YAAY;AAC7C,SAAO,iBAAiB,QAAQ,WAAW;AAE3C,uBAAqB;AAErB,eAAa;AACL,UAAO,oBAAoB,SAAS,YAAY;AAChD,UAAO,oBAAoB,QAAQ,WAAW;;IAE3D,EAAE,CAAC;AAEN,QAAO"}
1
+ {"version":3,"file":"use-window-visibility-focus.js","names":[],"sources":["../../src/hooks/use-window-visibility-focus.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type WindowVisibilityFocusState = {\n\tisPageVisible: boolean;\n\thasWindowFocus: boolean;\n};\n\nconst getVisibilityFocusState = (): WindowVisibilityFocusState => {\n\tif (typeof document === \"undefined\") {\n\t\treturn { isPageVisible: true, hasWindowFocus: true };\n\t}\n\n\tconst isPageVisible = !document.hidden;\n\tconst hasWindowFocus =\n\t\tisPageVisible &&\n\t\t(typeof document.hasFocus === \"function\" ? document.hasFocus() : true);\n\n\treturn { isPageVisible, hasWindowFocus };\n};\n\n/**\n * Tracks document visibility and window focus so hooks can defer updates while\n * the user is away from the page.\n */\nexport function useWindowVisibilityFocus(): WindowVisibilityFocusState {\n\tconst [state, setState] = useState<WindowVisibilityFocusState>(() =>\n\t\tgetVisibilityFocusState()\n\t);\n\n\tuseEffect(() => {\n\t\tif (typeof document === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\n\t\tconst handleVisibilityChange = () => {\n\t\t\tsetState(getVisibilityFocusState());\n\t\t};\n\n\t\tdocument.addEventListener(\"visibilitychange\", handleVisibilityChange);\n\t\thandleVisibilityChange();\n\t\treturn () => {\n\t\t\tdocument.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n\t\t};\n\t}, []);\n\n\tuseEffect(() => {\n\t\tif (typeof window === \"undefined\") {\n\t\t\treturn;\n\t\t}\n\n\t\tconst syncVisibilityFocus = () => {\n\t\t\tsetState(getVisibilityFocusState());\n\t\t};\n\n\t\tconst handleFocus = () => {\n\t\t\tsyncVisibilityFocus();\n\t\t};\n\t\tconst handleBlur = () => {\n\t\t\tsyncVisibilityFocus();\n\t\t};\n\n\t\twindow.addEventListener(\"focus\", handleFocus);\n\t\twindow.addEventListener(\"blur\", handleBlur);\n\n\t\tsyncVisibilityFocus();\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"focus\", handleFocus);\n\t\t\twindow.removeEventListener(\"blur\", handleBlur);\n\t\t};\n\t}, []);\n\n\treturn state;\n}\n"],"mappings":";;;AAOA,MAAM,gCAA4D;AACjE,KAAI,OAAO,aAAa,YACvB,QAAO;EAAE,eAAe;EAAM,gBAAgB;EAAM;CAGrD,MAAM,gBAAgB,CAAC,SAAS;AAKhC,QAAO;EAAE;EAAe,gBAHvB,kBACC,OAAO,SAAS,aAAa,aAAa,SAAS,UAAU,GAAG;EAE1B;;;;;;AAOzC,SAAgB,2BAAuD;CACtE,MAAM,CAAC,OAAO,YAAY,eACzB,yBAAyB,CACzB;AAED,iBAAgB;AACf,MAAI,OAAO,aAAa,YACvB;EAGD,MAAM,+BAA+B;AACpC,YAAS,yBAAyB,CAAC;;AAGpC,WAAS,iBAAiB,oBAAoB,uBAAuB;AACrE,0BAAwB;AACxB,eAAa;AACZ,YAAS,oBAAoB,oBAAoB,uBAAuB;;IAEvE,EAAE,CAAC;AAEN,iBAAgB;AACf,MAAI,OAAO,WAAW,YACrB;EAGD,MAAM,4BAA4B;AACjC,YAAS,yBAAyB,CAAC;;EAGpC,MAAM,oBAAoB;AACzB,wBAAqB;;EAEtB,MAAM,mBAAmB;AACxB,wBAAqB;;AAGtB,SAAO,iBAAiB,SAAS,YAAY;AAC7C,SAAO,iBAAiB,QAAQ,WAAW;AAE3C,uBAAqB;AAErB,eAAa;AACZ,UAAO,oBAAoB,SAAS,YAAY;AAChD,UAAO,oBAAoB,QAAQ,WAAW;;IAE7C,EAAE,CAAC;AAEN,QAAO"}
@@ -1,16 +1,25 @@
1
+ import { ReactElement } from "react";
2
+ import { VisitorMetadata } from "@cossistant/types";
3
+
1
4
  //#region src/identify-visitor.d.ts
2
5
  type IdentifySupportVisitorProps = {
3
6
  externalId?: string;
4
7
  email?: string;
8
+ name?: string | null;
9
+ image?: string | null;
10
+ metadata?: VisitorMetadata | null;
5
11
  };
6
12
  /**
7
- * Component exposed by Cossistant allowing you to identify a visitor whenever rendered with either an `externalId` or `email`.
13
+ * Component exposed by Cossistant allowing you to identify a visitor whenever rendered with either an `externalId` or `email`. Once identified, the visitor will be associated with a contact and any subsequent metadata updates will be attached to this contact.
8
14
  */
9
15
  declare const IdentifySupportVisitor: {
10
16
  ({
11
17
  externalId,
12
- email
13
- }: IdentifySupportVisitorProps): null;
18
+ email,
19
+ name,
20
+ image,
21
+ metadata: _newMetadata
22
+ }: IdentifySupportVisitorProps): ReactElement | null;
14
23
  displayName: string;
15
24
  };
16
25
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"identify-visitor.d.ts","names":[],"sources":["../src/identify-visitor.tsx"],"sourcesContent":[],"mappings":";KAIY,2BAAA;EAAA,UAAA,CAAA,EAAA,MAAA;EAQC,KAAA,CAAA,EAAA,MAAA;CAcZ;;;;AAX6B,cAHjB,sBAGiB,EAAA;;;;KAA3B"}
1
+ {"version":3,"file":"identify-visitor.d.ts","names":[],"sources":["../src/identify-visitor.tsx"],"sourcesContent":[],"mappings":";;;;KAOY,2BAAA;EAAA,UAAA,CAAA,EAAA,MAAA;EAWC,KAAA,CAAA,EAAA,MAAA;;;aAND;;;;;AAYiC,cANhC,sBAMgC,EAAA;;;;;;;KAA1C,8BAA8B"}
@@ -1,21 +1,70 @@
1
1
  import { useVisitor } from "./hooks/use-visitor.js";
2
- import { useEffect } from "react";
2
+ import { computeMetadataHash } from "./utils/metadata-hash.js";
3
+ import { useEffect, useState } from "react";
3
4
 
4
5
  //#region src/identify-visitor.tsx
5
6
  /**
6
- * Component exposed by Cossistant allowing you to identify a visitor whenever rendered with either an `externalId` or `email`.
7
+ * Component exposed by Cossistant allowing you to identify a visitor whenever rendered with either an `externalId` or `email`. Once identified, the visitor will be associated with a contact and any subsequent metadata updates will be attached to this contact.
7
8
  */
8
- const IdentifySupportVisitor = ({ externalId, email }) => {
9
- const { visitor, identify } = useVisitor();
9
+ const IdentifySupportVisitor = ({ externalId, email, name, image, metadata: _newMetadata }) => {
10
+ const { visitor, identify, setVisitorMetadata } = useVisitor();
11
+ const [hasIdentified, setHasIdentified] = useState(false);
12
+ const [lastMetadataHash, setLastMetadataHash] = useState(null);
10
13
  useEffect(() => {
11
- if (!visitor?.contact && (externalId || email)) identify({
12
- externalId,
13
- email
14
- });
14
+ const shouldIdentify = async () => {
15
+ if (!Boolean(externalId || email)) return;
16
+ if (!visitor?.contact) {
17
+ if (!hasIdentified) {
18
+ await identify({
19
+ externalId,
20
+ email,
21
+ name: name ?? void 0,
22
+ image: image ?? void 0
23
+ });
24
+ setHasIdentified(true);
25
+ }
26
+ return;
27
+ }
28
+ const contact = visitor.contact;
29
+ const nameChanged = name !== void 0 && name !== contact.name;
30
+ const emailChanged = email !== void 0 && email !== contact.email;
31
+ const imageChanged = image !== void 0 && image !== contact.image;
32
+ if (nameChanged || emailChanged || imageChanged) await identify({
33
+ externalId,
34
+ email,
35
+ name: name ?? void 0,
36
+ image: image ?? void 0
37
+ });
38
+ };
39
+ shouldIdentify();
15
40
  }, [
16
41
  visitor?.contact,
17
42
  externalId,
18
- email
43
+ email,
44
+ name,
45
+ image,
46
+ identify,
47
+ hasIdentified
48
+ ]);
49
+ useEffect(() => {
50
+ const updateMetadata = async () => {
51
+ if (!_newMetadata) return;
52
+ if (!visitor?.contact) return;
53
+ const newMetadataHash = await computeMetadataHash(_newMetadata);
54
+ const hashChanged = newMetadataHash !== (visitor.contact.metadataHash || "");
55
+ const notAlreadyUpdated = newMetadataHash !== lastMetadataHash;
56
+ if (Boolean(newMetadataHash && hashChanged && notAlreadyUpdated)) {
57
+ await setVisitorMetadata(_newMetadata);
58
+ setLastMetadataHash(newMetadataHash);
59
+ }
60
+ };
61
+ updateMetadata();
62
+ }, [
63
+ _newMetadata,
64
+ visitor?.contact?.metadataHash,
65
+ visitor?.contact,
66
+ setVisitorMetadata,
67
+ lastMetadataHash
19
68
  ]);
20
69
  return null;
21
70
  };
@@ -1 +1 @@
1
- {"version":3,"file":"identify-visitor.js","names":[],"sources":["../src/identify-visitor.tsx"],"sourcesContent":["/** biome-ignore-all lint/correctness/useExhaustiveDependencies: wanted here */\nimport { useEffect } from \"react\";\nimport { useVisitor } from \"./hooks\";\n\nexport type IdentifySupportVisitorProps = {\n\texternalId?: string;\n\temail?: string;\n};\n\n/**\n * Component exposed by Cossistant allowing you to identify a visitor whenever rendered with either an `externalId` or `email`.\n */\nexport const IdentifySupportVisitor = ({\n\texternalId,\n\temail,\n}: IdentifySupportVisitorProps) => {\n\tconst { visitor, identify } = useVisitor();\n\n\t// Only update when the arrays actually change content\n\tuseEffect(() => {\n\t\tif (!visitor?.contact && (externalId || email)) {\n\t\t\tidentify({ externalId, email });\n\t\t}\n\t}, [visitor?.contact, externalId, email]);\n\n\treturn null;\n};\n\nIdentifySupportVisitor.displayName = \"IdentifySupportVisitor\";\n"],"mappings":";;;;;;;AAYA,MAAa,0BAA0B,EACtC,YACA,YACkC;CAClC,MAAM,EAAE,SAAS,aAAa,YAAY;AAG1C,iBAAgB;AACf,MAAI,CAAC,SAAS,YAAY,cAAc,OACvC,UAAS;GAAE;GAAY;GAAO,CAAC;IAE9B;EAAC,SAAS;EAAS;EAAY;EAAM,CAAC;AAEzC,QAAO;;AAGR,uBAAuB,cAAc"}
1
+ {"version":3,"file":"identify-visitor.js","names":[],"sources":["../src/identify-visitor.tsx"],"sourcesContent":["/** biome-ignore-all lint/correctness/useExhaustiveDependencies: wanted here */\n\nimport type { VisitorMetadata } from \"@cossistant/types\";\nimport { type ReactElement, useEffect, useState } from \"react\";\nimport { useVisitor } from \"./hooks\";\nimport { computeMetadataHash } from \"./utils/metadata-hash\";\n\nexport type IdentifySupportVisitorProps = {\n\texternalId?: string;\n\temail?: string;\n\tname?: string | null;\n\timage?: string | null;\n\tmetadata?: VisitorMetadata | null;\n};\n\n/**\n * Component exposed by Cossistant allowing you to identify a visitor whenever rendered with either an `externalId` or `email`. Once identified, the visitor will be associated with a contact and any subsequent metadata updates will be attached to this contact.\n */\nexport const IdentifySupportVisitor = ({\n\texternalId,\n\temail,\n\tname,\n\timage,\n\tmetadata: _newMetadata,\n}: IdentifySupportVisitorProps): ReactElement | null => {\n\tconst { visitor, identify, setVisitorMetadata } = useVisitor();\n\tconst [hasIdentified, setHasIdentified] = useState(false);\n\tconst [lastMetadataHash, setLastMetadataHash] = useState<string | null>(null);\n\n\t// Only call identify if:\n\t// 1. Visitor hasn't been identified yet (no contact)\n\t// 2. Name, email, or image changed compared to current contact\n\tuseEffect(() => {\n\t\tconst shouldIdentify = async () => {\n\t\t\tconst hasIdentificationData = Boolean(externalId || email);\n\n\t\t\t// Need at least externalId or email to identify\n\t\t\tif (!hasIdentificationData) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Case 1: No contact exists yet\n\t\t\tif (!visitor?.contact) {\n\t\t\t\tif (!hasIdentified) {\n\t\t\t\t\tawait identify({\n\t\t\t\t\t\texternalId,\n\t\t\t\t\t\temail,\n\t\t\t\t\t\tname: name ?? undefined,\n\t\t\t\t\t\timage: image ?? undefined,\n\t\t\t\t\t});\n\t\t\t\t\tsetHasIdentified(true);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Case 2: Contact exists but name/email/image changed\n\t\t\tconst contact = visitor.contact;\n\t\t\tconst nameChanged = name !== undefined && name !== contact.name;\n\t\t\tconst emailChanged = email !== undefined && email !== contact.email;\n\t\t\tconst imageChanged = image !== undefined && image !== contact.image;\n\t\t\tconst hasChanges = nameChanged || emailChanged || imageChanged;\n\n\t\t\tif (hasChanges) {\n\t\t\t\tawait identify({\n\t\t\t\t\texternalId,\n\t\t\t\t\temail,\n\t\t\t\t\tname: name ?? undefined,\n\t\t\t\t\timage: image ?? undefined,\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\tshouldIdentify();\n\t}, [\n\t\tvisitor?.contact,\n\t\texternalId,\n\t\temail,\n\t\tname,\n\t\timage,\n\t\tidentify,\n\t\thasIdentified,\n\t]);\n\n\t// Compute metadata hash, compare to previous hash and only update if it has changed\n\tuseEffect(() => {\n\t\tconst updateMetadata = async () => {\n\t\t\t// Skip if no metadata provided or visitor doesn't have a contact\n\t\t\tif (!_newMetadata) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!visitor?.contact) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Compute new metadata hash\n\t\t\tconst newMetadataHash = await computeMetadataHash(_newMetadata);\n\n\t\t\t// Get the existing hash from the contact\n\t\t\tconst existingHash = visitor.contact.metadataHash || \"\";\n\n\t\t\t// Only update if hashes don't match and we haven't already updated with this hash\n\t\t\tconst hashChanged = newMetadataHash !== existingHash;\n\t\t\tconst notAlreadyUpdated = newMetadataHash !== lastMetadataHash;\n\t\t\tconst shouldUpdate = Boolean(\n\t\t\t\tnewMetadataHash && hashChanged && notAlreadyUpdated\n\t\t\t);\n\n\t\t\tif (shouldUpdate) {\n\t\t\t\tawait setVisitorMetadata(_newMetadata);\n\t\t\t\tsetLastMetadataHash(newMetadataHash);\n\t\t\t}\n\t\t};\n\n\t\tupdateMetadata();\n\t}, [\n\t\t_newMetadata,\n\t\tvisitor?.contact?.metadataHash,\n\t\tvisitor?.contact,\n\t\tsetVisitorMetadata,\n\t\tlastMetadataHash,\n\t]);\n\n\treturn null;\n};\n\nIdentifySupportVisitor.displayName = \"IdentifySupportVisitor\";\n"],"mappings":";;;;;;;;AAkBA,MAAa,0BAA0B,EACtC,YACA,OACA,MACA,OACA,UAAU,mBAC6C;CACvD,MAAM,EAAE,SAAS,UAAU,uBAAuB,YAAY;CAC9D,MAAM,CAAC,eAAe,oBAAoB,SAAS,MAAM;CACzD,MAAM,CAAC,kBAAkB,uBAAuB,SAAwB,KAAK;AAK7E,iBAAgB;EACf,MAAM,iBAAiB,YAAY;AAIlC,OAAI,CAH0B,QAAQ,cAAc,MAAM,CAIzD;AAID,OAAI,CAAC,SAAS,SAAS;AACtB,QAAI,CAAC,eAAe;AACnB,WAAM,SAAS;MACd;MACA;MACA,MAAM,QAAQ;MACd,OAAO,SAAS;MAChB,CAAC;AACF,sBAAiB,KAAK;;AAEvB;;GAID,MAAM,UAAU,QAAQ;GACxB,MAAM,cAAc,SAAS,UAAa,SAAS,QAAQ;GAC3D,MAAM,eAAe,UAAU,UAAa,UAAU,QAAQ;GAC9D,MAAM,eAAe,UAAU,UAAa,UAAU,QAAQ;AAG9D,OAFmB,eAAe,gBAAgB,aAGjD,OAAM,SAAS;IACd;IACA;IACA,MAAM,QAAQ;IACd,OAAO,SAAS;IAChB,CAAC;;AAIJ,kBAAgB;IACd;EACF,SAAS;EACT;EACA;EACA;EACA;EACA;EACA;EACA,CAAC;AAGF,iBAAgB;EACf,MAAM,iBAAiB,YAAY;AAElC,OAAI,CAAC,aACJ;AAGD,OAAI,CAAC,SAAS,QACb;GAID,MAAM,kBAAkB,MAAM,oBAAoB,aAAa;GAM/D,MAAM,cAAc,qBAHC,QAAQ,QAAQ,gBAAgB;GAIrD,MAAM,oBAAoB,oBAAoB;AAK9C,OAJqB,QACpB,mBAAmB,eAAe,kBAClC,EAEiB;AACjB,UAAM,mBAAmB,aAAa;AACtC,wBAAoB,gBAAgB;;;AAItC,kBAAgB;IACd;EACF;EACA,SAAS,SAAS;EAClB,SAAS;EACT;EACA;EACA,CAAC;AAEF,QAAO;;AAGR,uBAAuB,cAAc"}
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { useClientQuery } from "./hooks/private/use-client-query.js";
2
2
  import { useDefaultMessages } from "./hooks/private/use-default-messages.js";
3
- import { ConversationItem, GroupedMessage, TimelineEventItem, UseGroupedMessagesOptions, UseGroupedMessagesProps, useGroupedMessages } from "./hooks/private/use-grouped-messages.js";
3
+ import { ConversationItem, GroupedMessage, TimelineEventItem, TimelineToolItem, UseGroupedMessagesOptions, UseGroupedMessagesProps, useGroupedMessages } from "./hooks/private/use-grouped-messages.js";
4
4
  import { UseMultimodalInputOptions, UseMultimodalInputReturn, useMultimodalInput } from "./hooks/private/use-multimodal-input.js";
5
5
  import { UseClientResult, useClient } from "./hooks/private/use-rest-client.js";
6
6
  import { UseComposerRefocusOptions, UseComposerRefocusReturn, useComposerRefocus } from "./hooks/use-composer-refocus.js";
@@ -9,9 +9,12 @@ import { CONVERSATION_AUTO_SEEN_DELAY_MS, UseConversationAutoSeenOptions, useCon
9
9
  import { UseConversationHistoryPageOptions, UseConversationHistoryPageReturn, useConversationHistoryPage } from "./hooks/use-conversation-history-page.js";
10
10
  import { ConversationLifecycleState, UseConversationLifecycleOptions, UseConversationLifecycleReturn, useConversationLifecycle } from "./hooks/use-conversation-lifecycle.js";
11
11
  import { UseConversationPageOptions, UseConversationPageReturn, useConversationPage } from "./hooks/use-conversation-page.js";
12
- import { useConversationSeen, useDebouncedConversationSeen } from "./hooks/use-conversation-seen.js";
12
+ import { SupportLocale, SupportTextContentOverrides } from "./support/text/locales/keys.js";
13
13
  import { UseConversationTimelineItemsOptions, UseConversationTimelineItemsResult, useConversationTimelineItems } from "./hooks/use-conversation-timeline-items.js";
14
+ import { ConversationPreviewAssignedAgent, ConversationPreviewLastMessage, ConversationPreviewTypingParticipant, ConversationPreviewTypingState, UseConversationPreviewOptions, UseConversationPreviewReturn, useConversationPreview } from "./hooks/use-conversation-preview.js";
15
+ import { useConversationSeen, useDebouncedConversationSeen } from "./hooks/use-conversation-seen.js";
14
16
  import { ConversationTypingParticipant, useConversationTyping } from "./hooks/use-conversation-typing.js";
17
+ import { ConversationTimelineTypingParticipant, UseConversationTimelineOptions, UseConversationTimelineReturn, useConversationTimeline } from "./hooks/use-conversation-timeline.js";
15
18
  import { UseConversationsOptions, UseConversationsResult, useConversations } from "./hooks/use-conversations.js";
16
19
  import { CreateConversationVariables, UseCreateConversationOptions, UseCreateConversationResult, useCreateConversation } from "./hooks/use-create-conversation.js";
17
20
  import { UseHomePageOptions, UseHomePageReturn, useHomePage } from "./hooks/use-home-page.js";
@@ -20,19 +23,19 @@ import { UseRealtimeSupportOptions, UseRealtimeSupportResult, useRealtimeSupport
20
23
  import { SendMessageOptions, SendMessageResult, UseSendMessageOptions, UseSendMessageResult, useSendMessage } from "./hooks/use-send-message.js";
21
24
  import { UseVisitorReturn, useVisitor } from "./hooks/use-visitor.js";
22
25
  import { WindowVisibilityFocusState, useWindowVisibilityFocus } from "./hooks/use-window-visibility-focus.js";
26
+ import "./hooks/index.js";
23
27
  import { IdentifySupportVisitor, IdentifySupportVisitorProps } from "./identify-visitor.js";
24
28
  import { SupportConfig, SupportConfigProps } from "./support-config.js";
25
29
  import { index_d_exports } from "./primitives/index.js";
26
- import { CossistantContextValue, CossistantProviderProps, SupportProvider, SupportProviderProps, useSupport } from "./provider.js";
30
+ import { CossistantContextValue, CossistantProviderProps, SupportContext, SupportProvider, SupportProviderProps, UseSupportValue, useSupport } from "./provider.js";
27
31
  import { RealtimeAuthConfig, RealtimeContextValue, RealtimeProvider, RealtimeProviderProps, useRealtimeConnection } from "./realtime/provider.js";
28
32
  import { applyConversationSeenEvent, hydrateConversationSeen, upsertConversationSeen } from "./realtime/seen-store.js";
29
33
  import { SupportRealtimeProvider } from "./realtime/support-provider.js";
30
34
  import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./realtime/typing-store.js";
31
35
  import { RealtimeEventHandler, RealtimeEventHandlerEntry, RealtimeEventHandlersMap, RealtimeEventMeta, useRealtime } from "./realtime/use-realtime.js";
32
- import { SupportLocale, SupportTextContentOverrides } from "./support/text/locales/keys.js";
36
+ import "./realtime/index.js";
33
37
  import { Text, useSupportText } from "./support/text/index.js";
34
- import { useSupportConfig } from "./support/context/config.js";
35
38
  import { WebSocketContextValue, WebSocketProvider, useWebSocket } from "./support/context/websocket.js";
36
- import { useSupportStore } from "./support/store/support-store.js";
39
+ import { useSupportConfig, useSupportNavigation, useSupportStore } from "./support/store/support-store.js";
37
40
  import { Support, SupportProps } from "./support/index.js";
38
- export { CONVERSATION_AUTO_SEEN_DELAY_MS, ConversationItem, ConversationLifecycleState, ConversationTypingParticipant, CossistantContextValue, CossistantProviderProps, CreateConversationVariables, GroupedMessage, IdentifySupportVisitor, IdentifySupportVisitorProps, index_d_exports as Primitives, RealtimeAuthConfig, RealtimeContextValue, RealtimeEventHandler, RealtimeEventHandlerEntry, RealtimeEventHandlersMap, RealtimeEventMeta, RealtimeProvider, RealtimeProviderProps, SendMessageOptions, SendMessageResult, Support, SupportConfig, SupportConfigProps, SupportLocale, SupportProps, SupportProvider, SupportProviderProps, SupportRealtimeProvider, SupportTextContentOverrides, Text, TimelineEventItem, UseClientResult, UseComposerRefocusOptions, UseComposerRefocusReturn, UseConversationAutoSeenOptions, UseConversationHistoryPageOptions, UseConversationHistoryPageReturn, UseConversationLifecycleOptions, UseConversationLifecycleReturn, UseConversationOptions, UseConversationPageOptions, UseConversationPageReturn, UseConversationResult, UseConversationTimelineItemsOptions, UseConversationTimelineItemsResult, UseConversationsOptions, UseConversationsResult, UseCreateConversationOptions, UseCreateConversationResult, UseGroupedMessagesOptions, UseGroupedMessagesProps, UseHomePageOptions, UseHomePageReturn, UseMessageComposerOptions, UseMessageComposerReturn, UseMultimodalInputOptions, UseMultimodalInputReturn, UseRealtimeSupportOptions, UseRealtimeSupportResult, UseSendMessageOptions, UseSendMessageResult, UseVisitorReturn, WebSocketContextValue, WebSocketProvider, WindowVisibilityFocusState, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationSeen, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useRealtime, useRealtimeConnection, useRealtimeSupport, useSendMessage, useSupport, useSupportConfig, useSupportStore, useSupportText, useVisitor, useWebSocket, useWindowVisibilityFocus };
41
+ export { CONVERSATION_AUTO_SEEN_DELAY_MS, ConversationItem, ConversationLifecycleState, ConversationPreviewAssignedAgent, ConversationPreviewLastMessage, ConversationPreviewTypingParticipant, ConversationPreviewTypingState, ConversationTimelineTypingParticipant, ConversationTypingParticipant, CossistantContextValue, CossistantProviderProps, CreateConversationVariables, GroupedMessage, IdentifySupportVisitor, IdentifySupportVisitorProps, index_d_exports as Primitives, RealtimeAuthConfig, RealtimeContextValue, RealtimeEventHandler, RealtimeEventHandlerEntry, RealtimeEventHandlersMap, RealtimeEventMeta, RealtimeProvider, RealtimeProviderProps, SendMessageOptions, SendMessageResult, Support, SupportConfig, SupportConfigProps, SupportContext, SupportLocale, SupportProps, SupportProvider, SupportProviderProps, SupportRealtimeProvider, SupportTextContentOverrides, Text, TimelineEventItem, TimelineToolItem, UseClientResult, UseComposerRefocusOptions, UseComposerRefocusReturn, UseConversationAutoSeenOptions, UseConversationHistoryPageOptions, UseConversationHistoryPageReturn, UseConversationLifecycleOptions, UseConversationLifecycleReturn, UseConversationOptions, UseConversationPageOptions, UseConversationPageReturn, UseConversationPreviewOptions, UseConversationPreviewReturn, UseConversationResult, UseConversationTimelineItemsOptions, UseConversationTimelineItemsResult, UseConversationTimelineOptions, UseConversationTimelineReturn, UseConversationsOptions, UseConversationsResult, UseCreateConversationOptions, UseCreateConversationResult, UseGroupedMessagesOptions, UseGroupedMessagesProps, UseHomePageOptions, UseHomePageReturn, UseMessageComposerOptions, UseMessageComposerReturn, UseMultimodalInputOptions, UseMultimodalInputReturn, UseRealtimeSupportOptions, UseRealtimeSupportResult, UseSendMessageOptions, UseSendMessageResult, UseSupportValue, UseVisitorReturn, WebSocketContextValue, WebSocketProvider, WindowVisibilityFocusState, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useRealtime, useRealtimeConnection, useRealtimeSupport, useSendMessage, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useVisitor, useWebSocket, useWindowVisibilityFocus };
package/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import { useClientQuery } from "./hooks/private/use-client-query.js";
2
2
  import { useClient } from "./hooks/private/use-rest-client.js";
3
- import { RealtimeProvider, useRealtimeConnection } from "./realtime/provider.js";
4
3
  import { applyConversationSeenEvent, hydrateConversationSeen, upsertConversationSeen } from "./realtime/seen-store.js";
4
+ import { RealtimeProvider, useRealtimeConnection } from "./realtime/provider.js";
5
5
  import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./realtime/typing-store.js";
6
6
  import { useRealtime } from "./realtime/use-realtime.js";
7
7
  import { SupportRealtimeProvider } from "./realtime/support-provider.js";
8
8
  import { SupportConfig } from "./support-config.js";
9
- import { useSupportStore } from "./support/store/support-store.js";
10
- import { useSupportConfig } from "./support/context/config.js";
9
+ import { useSupportConfig, useSupportNavigation, useSupportStore } from "./support/store/support-store.js";
11
10
  import { primitives_exports } from "./primitives/index.js";
12
11
  import { Text, useSupportText } from "./support/text/index.js";
12
+ import { useConversation } from "./hooks/use-conversation.js";
13
13
  import { useWindowVisibilityFocus } from "./hooks/use-window-visibility-focus.js";
14
14
  import { CONVERSATION_AUTO_SEEN_DELAY_MS, useConversationAutoSeen } from "./hooks/use-conversation-auto-seen.js";
15
15
  import { useConversationLifecycle } from "./hooks/use-conversation-lifecycle.js";
@@ -19,20 +19,21 @@ import { useSendMessage } from "./hooks/use-send-message.js";
19
19
  import { useMessageComposer } from "./hooks/use-message-composer.js";
20
20
  import { useConversationPage } from "./hooks/use-conversation-page.js";
21
21
  import { useGroupedMessages } from "./hooks/private/use-grouped-messages.js";
22
+ import { useConversationSeen, useDebouncedConversationSeen } from "./hooks/use-conversation-seen.js";
23
+ import { useConversationTyping } from "./hooks/use-conversation-typing.js";
24
+ import { useConversationTimeline } from "./hooks/use-conversation-timeline.js";
22
25
  import { useComposerRefocus } from "./hooks/use-composer-refocus.js";
26
+ import { useVisitor } from "./hooks/use-visitor.js";
23
27
  import { useConversations } from "./hooks/use-conversations.js";
24
28
  import { useConversationHistoryPage } from "./hooks/use-conversation-history-page.js";
29
+ import { useConversationPreview } from "./hooks/use-conversation-preview.js";
25
30
  import { useHomePage } from "./hooks/use-home-page.js";
26
31
  import { WebSocketProvider, useWebSocket } from "./support/context/websocket.js";
27
32
  import { Support } from "./support/index.js";
28
- import { SupportProvider, useSupport } from "./provider.js";
33
+ import { SupportContext, SupportProvider, useSupport } from "./provider.js";
29
34
  import { useDefaultMessages } from "./hooks/private/use-default-messages.js";
30
- import { useConversation } from "./hooks/use-conversation.js";
31
- import { useConversationSeen, useDebouncedConversationSeen } from "./hooks/use-conversation-seen.js";
32
- import { useConversationTyping } from "./hooks/use-conversation-typing.js";
33
35
  import { useCreateConversation } from "./hooks/use-create-conversation.js";
34
36
  import { useRealtimeSupport } from "./hooks/use-realtime-support.js";
35
- import { useVisitor } from "./hooks/use-visitor.js";
36
37
  import { IdentifySupportVisitor } from "./identify-visitor.js";
37
38
 
38
- export { CONVERSATION_AUTO_SEEN_DELAY_MS, IdentifySupportVisitor, primitives_exports as Primitives, RealtimeProvider, Support, SupportConfig, SupportProvider, SupportRealtimeProvider, Text, WebSocketProvider, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationSeen, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useRealtime, useRealtimeConnection, useRealtimeSupport, useSendMessage, useSupport, useSupportConfig, useSupportStore, useSupportText, useVisitor, useWebSocket, useWindowVisibilityFocus };
39
+ export { CONVERSATION_AUTO_SEEN_DELAY_MS, IdentifySupportVisitor, primitives_exports as Primitives, RealtimeProvider, Support, SupportConfig, SupportContext, SupportProvider, SupportRealtimeProvider, Text, WebSocketProvider, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useRealtime, useRealtimeConnection, useRealtimeSupport, useSendMessage, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useVisitor, useWebSocket, useWindowVisibilityFocus };
package/package.json CHANGED
@@ -1,27 +1,22 @@
1
1
  {
2
2
  "name": "@cossistant/react",
3
- "version": "0.0.3",
3
+ "type": "module",
4
+ "version": "0.0.5",
4
5
  "private": false,
5
6
  "author": "Cossistant team",
6
7
  "description": "Headless React SDK for building AI-powered support/chat widgets. Hooks + primitives, WS-driven, TypeScript-first. Next.js-ready, Tailwind optional.",
7
8
  "keywords": [
8
9
  "react",
9
- "headless",
10
10
  "headless-ui",
11
- "support",
12
- "customer support",
11
+ "support-widget",
12
+ "chat-widget",
13
+ "customer-support",
13
14
  "helpdesk",
14
- "support widget",
15
- "chat widget",
16
- "live chat",
17
- "ai",
18
- "ai support",
19
- "ai-agent",
20
- "support agent",
15
+ "live-chat",
16
+ "ai-support",
17
+ "websocket",
21
18
  "typescript",
22
- "nextjs",
23
19
  "tailwind",
24
- "shadcn",
25
20
  "accessibility"
26
21
  ],
27
22
  "bugs": {
@@ -56,10 +51,10 @@
56
51
  "import": "./hooks/index.js"
57
52
  },
58
53
  "./hooks/*": {
59
- "types": "./hooks/*d.ts",
60
- "import": "./hooks/*js"
54
+ "types": "./hooks/*.d.ts",
55
+ "import": "./hooks/*.js"
61
56
  },
62
- "./support.css": "./support/support.css",
57
+ "./support.css": "./support.css",
63
58
  "./realtime": {
64
59
  "types": "./realtime/index.d.ts",
65
60
  "import": "./realtime/index.js"
@@ -82,6 +77,8 @@
82
77
  "dependencies": {
83
78
  "@cossistant/core": "workspace:*",
84
79
  "@cossistant/types": "workspace:*",
80
+ "class-variance-authority": "^0.7.1",
81
+ "clsx": "^2.1.1",
85
82
  "nanoid": "^5.1.5",
86
83
  "react-markdown": "^10.1.0",
87
84
  "react-use-websocket": "^4.13.0",
@@ -91,7 +88,7 @@
91
88
  "peerDependencies": {
92
89
  "react": ">=18 <20",
93
90
  "react-dom": ">=18 <20",
94
- "@types/react": "^18 || ^19",
91
+ "@types/react": "",
95
92
  "motion": "^12.18.1",
96
93
  "tailwindcss": "*"
97
94
  },
@@ -1 +1 @@
1
- {"version":3,"file":"avatar.d.ts","names":[],"sources":["../../../src/primitives/avatar/avatar.tsx"],"sourcesContent":[],"mappings":";;;KAGK,WAAA;;AAH0B,CAAA;AAOnB,KAAA,WAAA,GAAc,IAAH,CACtB,OAAA,CAAM,cADgB,CACD,eADC,CAAA,EAAA,UAAA,CAAA,GAAA;EAAA,QAAA,CAAA,EAIX,OAAA,CAAM,SAJK;SACD,CAAA,EAAA,OAAA;WAArB,CAAA,EAAM,MAAA;;AAGK,UAKK,kBAAA,SAA2B,WAL1B,CAAA;EAAS,0BAAA,EAAA,CAAA,MAAA,EAOjB,WAPiB,CAAA,oBAAA,CAAA,EAAA,GAAA,IAAA;AAK3B;;;;;AAYa,cAAA,gBAAgB,EAAA,GAAA,GAAA,kBAQ5B;AAMD;;;;AAAmB,cAAN,MAAM,EAAA,OAAA,CAAA,yBAAA,CAAA,IAAA,CAAA,OAAA,CAAA,cAAA,CAAA,eAAA,CAAA,EAAA,UAAA,CAAA,GAAA;UA/BP,CAAA,EAAA,OAAA,CAAM,SAAA;;;yBA+BC,gBAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"avatar.d.ts","names":[],"sources":["../../../src/primitives/avatar/avatar.tsx"],"sourcesContent":[],"mappings":";;;KAGK,WAAA;;AAH0B,CAAA;AAOnB,KAAA,WAAA,GAAc,IAAH,CACtB,OAAA,CAAM,cADgB,CACD,eADC,CAAA,EAAA,UAAA,CAAA,GAAA;EACD,QAAA,CAAA,EAGV,OAAA,CAAM,SAHI;EAArB,OAAM,CAAA,EAAA,OAAA;EADmB,SAAA,CAAA,EAAA,MAAA;CAId;AAAe,UAKV,kBAAA,SAA2B,WALjB,CAAA;EAKV,0BAAmB,EAAA,CAAA,MAE1B,EAAA,WAFkC,CAAA,oBAAW,CAAA,EAAA,GAAA,IAAA;AAYvD;AAcA;;;;AA/BY,cAiBC,gBAjBK,EAAA,GAAA,GAiBW,kBAjBX;;;;;cA+BL,QAAM,OAAA,CAAA,0BAAA,KAAA,OAAA,CAAA,eAAA;aA/BP,OAAA,CAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"fallback.d.ts","names":[],"sources":["../../../src/primitives/avatar/fallback.tsx"],"sourcesContent":[],"mappings":";;;KASY,mBAAA,GAAsB,KACjC,OAAA,CAAM,eAAe;aAGV,OAAA,CAAM;EAJN,IAAA,CAAA,EAAA,MAAA;EAAmB,OAAA,CAAA,EAAA,MAAA;SACT,CAAA,EAAA,OAAA;WAArB,CAAA,EAAM,MAAA;;;;AA+BP;;AAA2B,cAAd,cAAc,EAAA,OAAA,CAAA,yBAAA,CAAA,IAAA,CAAA,OAAA,CAAA,cAAA,CAAA,eAAA,CAAA,EAAA,UAAA,CAAA,GAAA;UAAA,CAAA,EA5Bf,OAAA,CAAM,SA4BS;MAAA,CAAA,EAAA,MAAA;SA5Bf,CAAA,EAAA,MAAM;;;yBA4BS,gBAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"fallback.d.ts","names":[],"sources":["../../../src/primitives/avatar/fallback.tsx"],"sourcesContent":[],"mappings":";;;KASY,mBAAA,GAAsB,KACjC,OAAA,CAAM,eAAe;aAGV,OAAA,CAAM;EAJN,IAAA,CAAA,EAAA,MAAA;EACU,OAAA,CAAA,EAAA,MAAA;EAArB,OAAM,CAAA,EAAA,OAAA;EAD2B,SAAA,CAAA,EAAA,MAAA;CAItB;;AA4BZ;;;AAA2B,cAAd,cAAc,EAAA,OAAA,CAAA,yBAAA,CAAA,IAAA,CAAA,OAAA,CAAA,cAAA,CAAA,eAAA,CAAA,EAAA,UAAA,CAAA,GAAA;EA5Bf,QAAM,CAAA,EAAN,OAAA,CAAM,SAAA;;;EA4BS,OAAA,CAAA,EAAA,OAAA;EAAA,SAAA,CAAA,EAAA,MAAA"}
@@ -7,9 +7,7 @@ const getInitials = (name) => {
7
7
  const names = name.trim().split(" ");
8
8
  if (names.length === 0) return "";
9
9
  if (names.length === 1) return names[0]?.charAt(0).toUpperCase() || "";
10
- const firstInitial = names[0]?.charAt(0) || "";
11
- const lastInitial = names[names.length - 1]?.charAt(0) || "";
12
- return (firstInitial + lastInitial).toUpperCase();
10
+ return ((names[0]?.charAt(0) || "") + (names[names.length - 1]?.charAt(0) || "")).toUpperCase();
13
11
  };
14
12
  /**
15
13
  * Displays initials or custom content while the avatar image loads or fails.
@@ -1 +1 @@
1
- {"version":3,"file":"fallback.js","names":["React","state: FallbackState"],"sources":["../../../src/primitives/avatar/fallback.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useRenderElement } from \"../../utils/use-render-element\";\nimport { useAvatarContext } from \"./avatar\";\n\ntype FallbackState = {\n\timageLoadingStatus: \"idle\" | \"loading\" | \"loaded\" | \"error\";\n\tinitials?: string;\n};\n\nexport type AvatarFallbackProps = Omit<\n\tReact.HTMLAttributes<HTMLSpanElement>,\n\t\"children\"\n> & {\n\tchildren?: React.ReactNode;\n\tname?: string;\n\tdelayMs?: number;\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\nconst getInitials = (name: string): string => {\n\tconst names = name.trim().split(\" \");\n\tif (names.length === 0) {\n\t\treturn \"\";\n\t}\n\n\tif (names.length === 1) {\n\t\treturn names[0]?.charAt(0).toUpperCase() || \"\";\n\t}\n\n\tconst firstInitial = names[0]?.charAt(0) || \"\";\n\t// biome-ignore lint/style/useAtIndex: ok here\n\tconst lastInitial = names[names.length - 1]?.charAt(0) || \"\";\n\n\treturn (firstInitial + lastInitial).toUpperCase();\n};\n\n/**\n * Displays initials or custom content while the avatar image loads or fails.\n * Optional delay avoids flashes when images load instantly.\n */\nexport const AvatarFallback = (() => {\n\tconst Component = React.forwardRef<HTMLSpanElement, AvatarFallbackProps>(\n\t\t(\n\t\t\t{\n\t\t\t\tchildren,\n\t\t\t\tname = \"\",\n\t\t\t\tdelayMs = 0,\n\t\t\t\tclassName,\n\t\t\t\tasChild = false,\n\t\t\t\t...props\n\t\t\t},\n\t\t\tref\n\t\t) => {\n\t\t\tconst { imageLoadingStatus } = useAvatarContext();\n\t\t\tconst [canRender, setCanRender] = React.useState(delayMs === 0);\n\n\t\t\tReact.useEffect(() => {\n\t\t\t\tif (delayMs > 0) {\n\t\t\t\t\tconst timerId = window.setTimeout(() => setCanRender(true), delayMs);\n\t\t\t\t\treturn () => window.clearTimeout(timerId);\n\t\t\t\t}\n\t\t\t}, [delayMs]);\n\n\t\t\tconst initials = React.useMemo(() => {\n\t\t\t\tif (name) {\n\t\t\t\t\treturn getInitials(name);\n\t\t\t\t}\n\t\t\t\treturn \"\";\n\t\t\t}, [name]);\n\n\t\t\tconst state: FallbackState = {\n\t\t\t\timageLoadingStatus,\n\t\t\t\tinitials,\n\t\t\t};\n\n\t\t\tconst shouldRender =\n\t\t\t\tcanRender &&\n\t\t\t\timageLoadingStatus !== \"loaded\" &&\n\t\t\t\timageLoadingStatus !== \"loading\";\n\n\t\t\tconst content = children || initials;\n\n\t\t\treturn useRenderElement(\n\t\t\t\t\"span\",\n\t\t\t\t{\n\t\t\t\t\tasChild,\n\t\t\t\t\tclassName,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tref,\n\t\t\t\t\tstate,\n\t\t\t\t\tenabled: shouldRender,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tchildren: content,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t);\n\n\tComponent.displayName = \"AvatarFallback\";\n\treturn Component;\n})();\n"],"mappings":";;;;;AAoBA,MAAM,eAAe,SAAyB;CAC7C,MAAM,QAAQ,KAAK,MAAM,CAAC,MAAM,IAAI;AACpC,KAAI,MAAM,WAAW,EACpB,QAAO;AAGR,KAAI,MAAM,WAAW,EACpB,QAAO,MAAM,IAAI,OAAO,EAAE,CAAC,aAAa,IAAI;CAG7C,MAAM,eAAe,MAAM,IAAI,OAAO,EAAE,IAAI;CAE5C,MAAM,cAAc,MAAM,MAAM,SAAS,IAAI,OAAO,EAAE,IAAI;AAE1D,SAAQ,eAAe,aAAa,aAAa;;;;;;AAOlD,MAAa,wBAAwB;CACpC,MAAM,YAAYA,QAAM,YAEtB,EACC,UACA,OAAO,IACP,UAAU,GACV,WACA,UAAU,MACV,GAAG,SAEJ,QACI;EACJ,MAAM,EAAE,uBAAuB,kBAAkB;EACjD,MAAM,CAAC,WAAW,gBAAgBA,QAAM,SAAS,YAAY,EAAE;AAE/D,UAAM,gBAAgB;AACrB,OAAI,UAAU,GAAG;IAChB,MAAM,UAAU,OAAO,iBAAiB,aAAa,KAAK,EAAE,QAAQ;AACpE,iBAAa,OAAO,aAAa,QAAQ;;KAExC,CAAC,QAAQ,CAAC;EAEb,MAAM,WAAWA,QAAM,cAAc;AACpC,OAAI,KACH,QAAO,YAAY,KAAK;AAEzB,UAAO;KACL,CAAC,KAAK,CAAC;EAEV,MAAMC,QAAuB;GAC5B;GACA;GACA;EAED,MAAM,eACL,aACA,uBAAuB,YACvB,uBAAuB;EAExB,MAAM,UAAU,YAAY;AAE5B,SAAO,iBACN,QACA;GACC;GACA;GACA,EACD;GACC;GACA;GACA,SAAS;GACT,OAAO;IACN,GAAG;IACH,UAAU;IACV;GACD,CACD;GAEF;AAED,WAAU,cAAc;AACxB,QAAO;IACJ"}
1
+ {"version":3,"file":"fallback.js","names":["React","state: FallbackState"],"sources":["../../../src/primitives/avatar/fallback.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useRenderElement } from \"../../utils/use-render-element\";\nimport { useAvatarContext } from \"./avatar\";\n\ntype FallbackState = {\n\timageLoadingStatus: \"idle\" | \"loading\" | \"loaded\" | \"error\";\n\tinitials?: string;\n};\n\nexport type AvatarFallbackProps = Omit<\n\tReact.HTMLAttributes<HTMLSpanElement>,\n\t\"children\"\n> & {\n\tchildren?: React.ReactNode;\n\tname?: string;\n\tdelayMs?: number;\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\nconst getInitials = (name: string): string => {\n\tconst names = name.trim().split(\" \");\n\tif (names.length === 0) {\n\t\treturn \"\";\n\t}\n\n\tif (names.length === 1) {\n\t\treturn names[0]?.charAt(0).toUpperCase() || \"\";\n\t}\n\n\tconst firstInitial = names[0]?.charAt(0) || \"\";\n\t// biome-ignore lint/style/useAtIndex: ok here\n\tconst lastInitial = names[names.length - 1]?.charAt(0) || \"\";\n\n\treturn (firstInitial + lastInitial).toUpperCase();\n};\n\n/**\n * Displays initials or custom content while the avatar image loads or fails.\n * Optional delay avoids flashes when images load instantly.\n */\nexport const AvatarFallback = (() => {\n\tconst Component = React.forwardRef<HTMLSpanElement, AvatarFallbackProps>(\n\t\t(\n\t\t\t{\n\t\t\t\tchildren,\n\t\t\t\tname = \"\",\n\t\t\t\tdelayMs = 0,\n\t\t\t\tclassName,\n\t\t\t\tasChild = false,\n\t\t\t\t...props\n\t\t\t},\n\t\t\tref\n\t\t) => {\n\t\t\tconst { imageLoadingStatus } = useAvatarContext();\n\t\t\tconst [canRender, setCanRender] = React.useState(delayMs === 0);\n\n\t\t\tReact.useEffect(() => {\n\t\t\t\tif (delayMs > 0) {\n\t\t\t\t\tconst timerId = window.setTimeout(() => setCanRender(true), delayMs);\n\t\t\t\t\treturn () => window.clearTimeout(timerId);\n\t\t\t\t}\n\t\t\t}, [delayMs]);\n\n\t\t\tconst initials = React.useMemo(() => {\n\t\t\t\tif (name) {\n\t\t\t\t\treturn getInitials(name);\n\t\t\t\t}\n\t\t\t\treturn \"\";\n\t\t\t}, [name]);\n\n\t\t\tconst state: FallbackState = {\n\t\t\t\timageLoadingStatus,\n\t\t\t\tinitials,\n\t\t\t};\n\n\t\t\tconst shouldRender =\n\t\t\t\tcanRender &&\n\t\t\t\timageLoadingStatus !== \"loaded\" &&\n\t\t\t\timageLoadingStatus !== \"loading\";\n\n\t\t\tconst content = children || initials;\n\n\t\t\treturn useRenderElement(\n\t\t\t\t\"span\",\n\t\t\t\t{\n\t\t\t\t\tasChild,\n\t\t\t\t\tclassName,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tref,\n\t\t\t\t\tstate,\n\t\t\t\t\tenabled: shouldRender,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tchildren: content,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t);\n\n\tComponent.displayName = \"AvatarFallback\";\n\treturn Component;\n})();\n"],"mappings":";;;;;AAoBA,MAAM,eAAe,SAAyB;CAC7C,MAAM,QAAQ,KAAK,MAAM,CAAC,MAAM,IAAI;AACpC,KAAI,MAAM,WAAW,EACpB,QAAO;AAGR,KAAI,MAAM,WAAW,EACpB,QAAO,MAAM,IAAI,OAAO,EAAE,CAAC,aAAa,IAAI;AAO7C,UAJqB,MAAM,IAAI,OAAO,EAAE,IAAI,OAExB,MAAM,MAAM,SAAS,IAAI,OAAO,EAAE,IAAI,KAEtB,aAAa;;;;;;AAOlD,MAAa,wBAAwB;CACpC,MAAM,YAAYA,QAAM,YAEtB,EACC,UACA,OAAO,IACP,UAAU,GACV,WACA,UAAU,MACV,GAAG,SAEJ,QACI;EACJ,MAAM,EAAE,uBAAuB,kBAAkB;EACjD,MAAM,CAAC,WAAW,gBAAgBA,QAAM,SAAS,YAAY,EAAE;AAE/D,UAAM,gBAAgB;AACrB,OAAI,UAAU,GAAG;IAChB,MAAM,UAAU,OAAO,iBAAiB,aAAa,KAAK,EAAE,QAAQ;AACpE,iBAAa,OAAO,aAAa,QAAQ;;KAExC,CAAC,QAAQ,CAAC;EAEb,MAAM,WAAWA,QAAM,cAAc;AACpC,OAAI,KACH,QAAO,YAAY,KAAK;AAEzB,UAAO;KACL,CAAC,KAAK,CAAC;EAEV,MAAMC,QAAuB;GAC5B;GACA;GACA;EAED,MAAM,eACL,aACA,uBAAuB,YACvB,uBAAuB;EAExB,MAAM,UAAU,YAAY;AAE5B,SAAO,iBACN,QACA;GACC;GACA;GACA,EACD;GACC;GACA;GACA,SAAS;GACT,OAAO;IACN,GAAG;IACH,UAAU;IACV;GACD,CACD;GAEF;AAED,WAAU,cAAc;AACxB,QAAO;IACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","names":[],"sources":["../../../src/primitives/avatar/image.tsx"],"sourcesContent":[],"mappings":";;;KAIK,UAAA;;AAJ0B,CAAA;AAQnB,KAAA,gBAAA,GAAmB,IAAH,CAC3B,OAAA,CAAM,iBADqB,CACH,gBADG,CAAA,EAAA,KAAA,GAAA,KAAA,CAAA,GAAA;EAAA,GAAA,EAAA,MAAA;KACH,CAAA,EAAA,MAAA;SAAxB,CAAA,EAAA,OAAM;WADwB,CAAA,EAAA,MAAA;uBAQG,CAAA,EAAA,CAAA,MAAA,EAAA,UAAA,CAAA,oBAAA,CAAA,EAAA,GAAA,IAAA;CAAU;AAO5C;;;;AAAwB,cAAX,WAAW,EAAA,OAAA,CAAA,yBAAA,CAAA,IAAA,CAAA,OAAA,CAAA,iBAAA,CAAA,gBAAA,CAAA,EAAA,KAAA,GAAA,KAAA,CAAA,GAAA;KAPU,EAAA,MAAA;;;WAOV,CAAA,EAAA,MAAA;EAAA,qBAAA,CAAA,EAAA,CAAA,MAAA,EAPU,UAOV,CAAA,oBAAA,CAAA,EAAA,GAAA,IAAA"}
1
+ {"version":3,"file":"image.d.ts","names":[],"sources":["../../../src/primitives/avatar/image.tsx"],"sourcesContent":[],"mappings":";;;KAIK,UAAA;;AAJ0B,CAAA;AAQnB,KAAA,gBAAA,GAAmB,IAAH,CAC3B,OAAA,CAAM,iBADqB,CACH,gBADG,CAAA,EAAA,KAAA,GAAA,KAAA,CAAA,GAAA;EACH,GAAA,EAAA,MAAA;EAAxB,GAAA,CAAA,EAAM,MAAA;EADwB,OAAA,CAAA,EAAA,OAAA;EAQG,SAAA,CAAA,EAAA,MAAA;EAAU,qBAAA,CAAA,EAAA,CAAA,MAAA,EAAV,UAAU,CAAA,oBAAA,CAAA,EAAA,GAAA,IAAA;AAO5C,CAAA;;;;;cAAa,aAAW,OAAA,CAAA,0BAAA,KAAA,OAAA,CAAA,kBAAA;;EAAA,GAAA,CAAA,EAAA,MAAA;EAAA,OAAA,CAAA,EAAA,OAAA;;mCAPU"}
@@ -1,4 +1,5 @@
1
1
  import { Avatar, AvatarProps } from "./avatar.js";
2
2
  import { AvatarFallback, AvatarFallbackProps } from "./fallback.js";
3
3
  import { AvatarImage, AvatarImageProps } from "./image.js";
4
+ import "./index.parts.js";
4
5
  export { Avatar, AvatarFallback, AvatarFallbackProps, AvatarImage, AvatarImageProps, AvatarProps };
@@ -5,6 +5,7 @@ type SupportBubbleProps = Omit<React$1.ButtonHTMLAttributes<HTMLButtonElement>,
5
5
  children?: React$1.ReactNode | ((props: {
6
6
  isOpen: boolean;
7
7
  unreadCount: number;
8
+ isTyping: boolean;
8
9
  toggle: () => void;
9
10
  }) => React$1.ReactNode);
10
11
  asChild?: boolean;
@@ -18,6 +19,7 @@ declare const SupportBubble: React$1.ForwardRefExoticComponent<Omit<React$1.Butt
18
19
  children?: React$1.ReactNode | ((props: {
19
20
  isOpen: boolean;
20
21
  unreadCount: number;
22
+ isTyping: boolean;
21
23
  toggle: () => void;
22
24
  }) => React$1.ReactNode);
23
25
  asChild?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"bubble.d.ts","names":[],"sources":["../../src/primitives/bubble.tsx"],"sourcesContent":[],"mappings":";;;KAKY,kBAAA,GAAqB,KAChC,OAAA,CAAM,qBAAqB;aAIxB,OAAA,CAAM;IALE,MAAA,EAAA,OAAA;IAAkB,WAAA,EAAA,MAAA;IACF,MAAA,EAAA,GAAA,GAAA,IAAA;KAA3B,GASS,OAAA,CAAM,SATT,CAAA;SAD0B,CAAA,EAAA,OAAA;WAK7B,CAAA,EAAM,MAAA;;;AAcV;;;AAA0B,cAAb,aAAa,EAAA,OAAA,CAAA,yBAAA,CAAA,IAAA,CAAA,OAAA,CAAA,oBAAA,CAAA,iBAAA,CAAA,EAAA,UAAA,CAAA,GAAA;UAAA,CAAA,EAdtB,OAAA,CAAM,SAcgB,GAAA,CAAA,CAAA,KAAA,EAAA;IAdtB,MAAA,EAAM,OAAA;IAKA,WAAM,EAAA,MAAA;;QAAN,OAAA,CAAM;SASU,CAAA,EAAA,OAAA;EAAA,SAAA,CAAA,EAAA,MAAA"}
1
+ {"version":3,"file":"bubble.d.ts","names":[],"sources":["../../src/primitives/bubble.tsx"],"sourcesContent":[],"mappings":";;;KAMY,kBAAA,GAAqB,KAChC,OAAA,CAAM,qBAAqB;aAIxB,OAAA,CAAM;IALE,MAAA,EAAA,OAAA;IACgB,WAAA,EAAA,MAAA;IAA3B,QAAM,EAAA,OAAA;IAD0B,MAAA,EAAA,GAAA,GAAA,IAAA;EAK7B,CAAA,EAAA,GAMM,OAAA,CAAM,SANN,CAAA;EAMA,OAAM,CAAA,EAAA,OAAA;EAAS,SAAA,CAAA,EAAA,MAAA;AASzB,CAAA;;;;;AATU,cASG,aATG,EASU,OAAA,CAAA,yBATV,CASU,IATV,CASU,OAAA,CAAA,oBATV,CASU,iBATV,CAAA,EAAA,UAAA,CAAA,GAAA;aANZ,OAAA,CAAM;;IAegB,WAAA,EAAA,MAAA;IAAA,QAAA,EAAA,OAAA;;QAThB,OAAA,CAAM"}
@@ -1,5 +1,6 @@
1
+ import { useTypingStore } from "../realtime/typing-store.js";
1
2
  import { useRenderElement } from "../utils/use-render-element.js";
2
- import { useSupportConfig } from "../support/context/config.js";
3
+ import { useSupportConfig } from "../support/store/support-store.js";
3
4
  import { useSupport } from "../provider.js";
4
5
  import * as React$1 from "react";
5
6
 
@@ -11,10 +12,15 @@ import * as React$1 from "react";
11
12
  const SupportBubble = (() => {
12
13
  const Component = React$1.forwardRef(({ children, className, asChild = false,...props }, ref) => {
13
14
  const { isOpen, toggle } = useSupportConfig();
14
- const { unreadCount } = useSupport();
15
+ const { unreadCount, visitor } = useSupport();
16
+ const visitorId = visitor?.id ?? null;
15
17
  const renderProps = {
16
18
  isOpen,
17
19
  unreadCount,
20
+ isTyping: useTypingStore(React$1.useCallback((state) => Object.values(state.conversations).some((entries) => Object.values(entries).some((entry) => {
21
+ if (visitorId && entry.actorType === "visitor" && entry.actorId === visitorId) return false;
22
+ return true;
23
+ })), [visitorId])),
18
24
  toggle
19
25
  };
20
26
  const content = typeof children === "function" ? children(renderProps) : children;
@@ -1 +1 @@
1
- {"version":3,"file":"bubble.js","names":["React"],"sources":["../../src/primitives/bubble.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useSupport } from \"../provider\";\nimport { useSupportConfig } from \"../support\";\nimport { useRenderElement } from \"../utils/use-render-element\";\n\nexport type SupportBubbleProps = Omit<\n\tReact.ButtonHTMLAttributes<HTMLButtonElement>,\n\t\"children\"\n> & {\n\tchildren?:\n\t\t| React.ReactNode\n\t\t| ((props: {\n\t\t\t\tisOpen: boolean;\n\t\t\t\tunreadCount: number;\n\t\t\t\ttoggle: () => void;\n\t\t }) => React.ReactNode);\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Floating action button that toggles the support window. Exposes widget state\n * and unread counts to render-prop children for fully custom UI shells.\n */\nexport const SupportBubble = (() => {\n\tconst Component = React.forwardRef<HTMLButtonElement, SupportBubbleProps>(\n\t\t({ children, className, asChild = false, ...props }, ref) => {\n\t\t\tconst { isOpen, toggle } = useSupportConfig();\n\t\t\tconst { unreadCount } = useSupport();\n\n\t\t\tconst renderProps = { isOpen, unreadCount, toggle };\n\n\t\t\tconst content =\n\t\t\t\ttypeof children === \"function\" ? children(renderProps) : children;\n\n\t\t\treturn useRenderElement(\n\t\t\t\t\"button\",\n\t\t\t\t{\n\t\t\t\t\tasChild,\n\t\t\t\t\tclassName,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tref,\n\t\t\t\t\tstate: renderProps,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\ttype: \"button\",\n\t\t\t\t\t\t\"aria-haspopup\": \"dialog\",\n\t\t\t\t\t\t\"aria-expanded\": isOpen,\n\t\t\t\t\t\tonClick: toggle,\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tchildren: content,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t);\n\n\tComponent.displayName = \"SupportBubble\";\n\treturn Component;\n})();\n"],"mappings":";;;;;;;;;;AAwBA,MAAa,uBAAuB;CACnC,MAAM,YAAYA,QAAM,YACtB,EAAE,UAAU,WAAW,UAAU,MAAO,GAAG,SAAS,QAAQ;EAC5D,MAAM,EAAE,QAAQ,WAAW,kBAAkB;EAC7C,MAAM,EAAE,gBAAgB,YAAY;EAEpC,MAAM,cAAc;GAAE;GAAQ;GAAa;GAAQ;EAEnD,MAAM,UACL,OAAO,aAAa,aAAa,SAAS,YAAY,GAAG;AAE1D,SAAO,iBACN,UACA;GACC;GACA;GACA,EACD;GACC;GACA,OAAO;GACP,OAAO;IACN,MAAM;IACN,iBAAiB;IACjB,iBAAiB;IACjB,SAAS;IACT,GAAG;IACH,UAAU;IACV;GACD,CACD;GAEF;AAED,WAAU,cAAc;AACxB,QAAO;IACJ"}
1
+ {"version":3,"file":"bubble.js","names":["React"],"sources":["../../src/primitives/bubble.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useSupport } from \"../provider\";\nimport { useTypingStore } from \"../realtime/typing-store\";\nimport { useSupportConfig } from \"../support\";\nimport { useRenderElement } from \"../utils/use-render-element\";\n\nexport type SupportBubbleProps = Omit<\n\tReact.ButtonHTMLAttributes<HTMLButtonElement>,\n\t\"children\"\n> & {\n\tchildren?:\n\t\t| React.ReactNode\n\t\t| ((props: {\n\t\t\t\tisOpen: boolean;\n\t\t\t\tunreadCount: number;\n\t\t\t\tisTyping: boolean;\n\t\t\t\ttoggle: () => void;\n\t\t }) => React.ReactNode);\n\tasChild?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Floating action button that toggles the support window. Exposes widget state\n * and unread counts to render-prop children for fully custom UI shells.\n */\nexport const SupportBubble = (() => {\n\tconst Component = React.forwardRef<HTMLButtonElement, SupportBubbleProps>(\n\t\t({ children, className, asChild = false, ...props }, ref) => {\n\t\t\tconst { isOpen, toggle } = useSupportConfig();\n\t\t\tconst { unreadCount, visitor } = useSupport();\n\t\t\tconst visitorId = visitor?.id ?? null;\n\n\t\t\tconst hasTyping = useTypingStore(\n\t\t\t\tReact.useCallback(\n\t\t\t\t\t(state) =>\n\t\t\t\t\t\tObject.values(state.conversations).some((entries) =>\n\t\t\t\t\t\t\tObject.values(entries).some((entry) => {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tvisitorId &&\n\t\t\t\t\t\t\t\t\tentry.actorType === \"visitor\" &&\n\t\t\t\t\t\t\t\t\tentry.actorId === visitorId\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t),\n\t\t\t\t\t[visitorId]\n\t\t\t\t)\n\t\t\t);\n\n\t\t\tconst renderProps = {\n\t\t\t\tisOpen,\n\t\t\t\tunreadCount,\n\t\t\t\tisTyping: hasTyping,\n\t\t\t\ttoggle,\n\t\t\t};\n\n\t\t\tconst content =\n\t\t\t\ttypeof children === \"function\" ? children(renderProps) : children;\n\n\t\t\treturn useRenderElement(\n\t\t\t\t\"button\",\n\t\t\t\t{\n\t\t\t\t\tasChild,\n\t\t\t\t\tclassName,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tref,\n\t\t\t\t\tstate: renderProps,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\ttype: \"button\",\n\t\t\t\t\t\t\"aria-haspopup\": \"dialog\",\n\t\t\t\t\t\t\"aria-expanded\": isOpen,\n\t\t\t\t\t\tonClick: toggle,\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\tchildren: content,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t);\n\n\tComponent.displayName = \"SupportBubble\";\n\treturn Component;\n})();\n"],"mappings":";;;;;;;;;;;AA0BA,MAAa,uBAAuB;CACnC,MAAM,YAAYA,QAAM,YACtB,EAAE,UAAU,WAAW,UAAU,MAAO,GAAG,SAAS,QAAQ;EAC5D,MAAM,EAAE,QAAQ,WAAW,kBAAkB;EAC7C,MAAM,EAAE,aAAa,YAAY,YAAY;EAC7C,MAAM,YAAY,SAAS,MAAM;EAsBjC,MAAM,cAAc;GACnB;GACA;GACA,UAvBiB,eACjBA,QAAM,aACJ,UACA,OAAO,OAAO,MAAM,cAAc,CAAC,MAAM,YACxC,OAAO,OAAO,QAAQ,CAAC,MAAM,UAAU;AACtC,QACC,aACA,MAAM,cAAc,aACpB,MAAM,YAAY,UAElB,QAAO;AAGR,WAAO;KACN,CACF,EACF,CAAC,UAAU,CACX,CACD;GAMA;GACA;EAED,MAAM,UACL,OAAO,aAAa,aAAa,SAAS,YAAY,GAAG;AAE1D,SAAO,iBACN,UACA;GACC;GACA;GACA,EACD;GACC;GACA,OAAO;GACP,OAAO;IACN,MAAM;IACN,iBAAiB;IACjB,iBAAiB;IACjB,SAAS;IACT,GAAG;IACH,UAAU;IACV;GACD,CACD;GAEF;AAED,WAAU,cAAc;AACxB,QAAO;IACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"button.d.ts","names":[],"sources":["../../src/primitives/button.tsx"],"sourcesContent":[],"mappings":";;;KAGY,WAAA,GAAc,OAAA,CAAM,qBAAqB;;EAAzC,SAAA,CAAA,EAAA,MAAW;CAAA;;;;AAUvB;;AAAmB,cAAN,MAAM,EAAA,OAAA,CAAA,yBAAA,CAAA,OAAA,CAAA,oBAAA,CAAA,iBAAA,CAAA,GAAA;SAAA,CAAA,EAAA,OAAA"}
1
+ {"version":3,"file":"button.d.ts","names":[],"sources":["../../src/primitives/button.tsx"],"sourcesContent":[],"mappings":";;;KAGY,WAAA,GAAc,OAAA,CAAM,qBAAqB;;EAAzC,SAAA,CAAA,EAAA,MAAW;AAUvB,CAAA;;;;;;AAAmB,cAAN,MAAM,EAAA,OAAA,CAAA,yBAAA,CAAA,OAAA,CAAA,oBAAA,CAAA,iBAAA,CAAA,GAAA"}