@cossistant/react 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/hooks/index.d.ts +2 -1
  2. package/hooks/index.js +2 -1
  3. package/hooks/use-home-page.js +1 -1
  4. package/hooks/use-home-page.js.map +1 -1
  5. package/hooks/use-scroll-mask.d.ts +24 -0
  6. package/hooks/use-scroll-mask.d.ts.map +1 -0
  7. package/hooks/use-scroll-mask.js +90 -0
  8. package/hooks/use-scroll-mask.js.map +1 -0
  9. package/hooks/use-send-message.js +1 -1
  10. package/hooks/use-send-message.js.map +1 -1
  11. package/index.d.ts +7 -2
  12. package/index.js +9 -5
  13. package/package.json +3 -3
  14. package/parse.d.ts.map +1 -1
  15. package/primitives/avatar/image.d.ts +1 -1
  16. package/primitives/bubble.d.ts +10 -2
  17. package/primitives/bubble.d.ts.map +1 -1
  18. package/primitives/bubble.js +11 -3
  19. package/primitives/bubble.js.map +1 -1
  20. package/primitives/conversation-timeline.d.ts.map +1 -1
  21. package/primitives/conversation-timeline.js +10 -20
  22. package/primitives/conversation-timeline.js.map +1 -1
  23. package/primitives/index.d.ts +5 -2
  24. package/primitives/index.js +11 -3
  25. package/primitives/index.parts.d.ts +4 -1
  26. package/primitives/index.parts.js +5 -2
  27. package/primitives/page-registry.d.ts +30 -0
  28. package/primitives/page-registry.d.ts.map +1 -0
  29. package/primitives/page-registry.js +45 -0
  30. package/primitives/page-registry.js.map +1 -0
  31. package/primitives/page.d.ts +21 -0
  32. package/primitives/page.d.ts.map +1 -0
  33. package/primitives/page.js +18 -0
  34. package/primitives/page.js.map +1 -0
  35. package/primitives/router.d.ts +35 -0
  36. package/primitives/router.d.ts.map +1 -0
  37. package/primitives/router.js +22 -0
  38. package/primitives/router.js.map +1 -0
  39. package/primitives/window.d.ts +8 -3
  40. package/primitives/window.d.ts.map +1 -1
  41. package/primitives/window.js +8 -3
  42. package/primitives/window.js.map +1 -1
  43. package/realtime/index.js +1 -1
  44. package/realtime/provider.js +1 -1
  45. package/realtime/support-provider.js +0 -4
  46. package/realtime/support-provider.js.map +1 -1
  47. package/realtime-events.d.ts +1 -1
  48. package/schemas2.d.ts.map +1 -1
  49. package/support/components/avatar-stack.js +1 -1
  50. package/support/components/avatar-stack.js.map +1 -1
  51. package/support/components/bubble.js +1 -1
  52. package/support/components/bubble.js.map +1 -1
  53. package/support/components/button.d.ts +1 -1
  54. package/support/components/button.js +3 -3
  55. package/support/components/button.js.map +1 -1
  56. package/support/components/container.js +1 -1
  57. package/support/components/container.js.map +1 -1
  58. package/support/components/conversation-timeline.js +1 -1
  59. package/support/components/conversation-timeline.js.map +1 -1
  60. package/support/components/multimodal-input.js +2 -2
  61. package/support/components/multimodal-input.js.map +1 -1
  62. package/support/components/support-content.d.ts +5 -7
  63. package/support/components/support-content.d.ts.map +1 -1
  64. package/support/components/support-content.js +9 -11
  65. package/support/components/support-content.js.map +1 -1
  66. package/support/components/theme-wrapper.d.ts +15 -0
  67. package/support/components/theme-wrapper.d.ts.map +1 -0
  68. package/support/components/theme-wrapper.js +18 -0
  69. package/support/components/theme-wrapper.js.map +1 -0
  70. package/support/components/timeline-identification-tool.js +2 -2
  71. package/support/components/timeline-identification-tool.js.map +1 -1
  72. package/support/components/watermark.js +2 -2
  73. package/support/components/watermark.js.map +1 -1
  74. package/support/index.d.ts +36 -6
  75. package/support/index.d.ts.map +1 -1
  76. package/support/index.js +43 -20
  77. package/support/index.js.map +1 -1
  78. package/support/pages/articles.d.ts +4 -1
  79. package/support/pages/articles.d.ts.map +1 -1
  80. package/support/pages/articles.js +1 -1
  81. package/support/pages/articles.js.map +1 -1
  82. package/support/pages/conversation-history.d.ts +5 -10
  83. package/support/pages/conversation-history.d.ts.map +1 -1
  84. package/support/pages/conversation-history.js +2 -9
  85. package/support/pages/conversation-history.js.map +1 -1
  86. package/support/pages/conversation.d.ts +17 -12
  87. package/support/pages/conversation.d.ts.map +1 -1
  88. package/support/pages/conversation.js +5 -2
  89. package/support/pages/conversation.js.map +1 -1
  90. package/support/pages/home.d.ts +5 -12
  91. package/support/pages/home.d.ts.map +1 -1
  92. package/support/pages/home.js +3 -12
  93. package/support/pages/home.js.map +1 -1
  94. package/support/router.d.ts +9 -4
  95. package/support/router.d.ts.map +1 -1
  96. package/support/router.js +34 -15
  97. package/support/router.js.map +1 -1
  98. package/support/store/support-store.d.ts +17 -14
  99. package/support/store/support-store.d.ts.map +1 -1
  100. package/support/store/support-store.js +13 -10
  101. package/support/store/support-store.js.map +1 -1
  102. package/support/{support-D0JydWRx.css → support-BQhCt9Za.css} +10 -9
  103. package/support/support-BQhCt9Za.css.map +1 -0
  104. package/support/types.d.ts +28 -0
  105. package/support/types.d.ts.map +1 -0
  106. package/support/types.js +1 -0
  107. package/support.css +1 -1
  108. package/tailwind.css +9 -8
  109. package/utils/conversation.d.ts.map +1 -1
  110. package/utils/conversation.js +3 -1
  111. package/utils/conversation.js.map +1 -1
  112. package/utils/use-render-element.d.ts.map +1 -1
  113. package/zod-extensions.d.ts.map +1 -1
  114. package/index4.d.ts +0 -18
  115. package/index4.d.ts.map +0 -1
  116. package/index5.d.ts +0 -999
  117. package/index5.d.ts.map +0 -1
  118. package/index6.d.ts +0 -6
  119. package/react.d.ts +0 -4
  120. package/support/components/text-effect.d.ts +0 -53
  121. package/support/components/text-effect.d.ts.map +0 -1
  122. package/support/components/text-effect.js +0 -225
  123. package/support/components/text-effect.js.map +0 -1
  124. package/support/support-D0JydWRx.css.map +0 -1
  125. package/types.d-BJcRxCew.d.ts +0 -39
  126. package/types.d-BJcRxCew.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-timeline.js","names":["EMPTY_SEEN_BY_IDS: readonly string[]","EMPTY_SEEN_BY_NAMES: readonly string[]","ConversationTimelineList: React.FC<ConversationTimelineProps>","names: string[]","PrimitiveConversationTimeline"],"sources":["../../../src/support/components/conversation-timeline.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport type {\n\tTimelineItem,\n\tTimelinePartEvent,\n} from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport { useCallback, useMemo } from \"react\";\nimport { useConversationTimeline } from \"../../hooks/use-conversation-timeline\";\nimport {\n\tConversationTimelineContainer,\n\tConversationTimeline as PrimitiveConversationTimeline,\n} from \"../../primitives/conversation-timeline\";\nimport { cn } from \"../utils\";\nimport { ConversationEvent } from \"./conversation-event\";\nimport { TimelineMessageGroup } from \"./timeline-message-group\";\nimport { TypingIndicator, type TypingParticipant } from \"./typing-indicator\";\n\n// Helper to extract event part from timeline item\nfunction extractEventPart(item: TimelineItem): TimelinePartEvent | null {\n\tif (item.type !== \"event\") {\n\t\treturn null;\n\t}\n\n\tconst eventPart = item.parts.find(\n\t\t(part): part is TimelinePartEvent => part.type === \"event\"\n\t);\n\n\treturn eventPart || null;\n}\n\nconst EMPTY_SEEN_BY_IDS: readonly string[] = Object.freeze([]);\nconst EMPTY_SEEN_BY_NAMES: readonly string[] = Object.freeze([]);\n\nexport type ConversationTimelineToolProps = {\n\titem: TimelineItem;\n\tconversationId: string;\n};\n\nexport type ConversationTimelineToolDefinition = {\n\tcomponent: React.ComponentType<ConversationTimelineToolProps>;\n};\n\nexport type ConversationTimelineTools = Record<\n\tstring,\n\tConversationTimelineToolDefinition\n>;\n\nexport type ConversationTimelineProps = {\n\tconversationId: string;\n\titems: TimelineItem[];\n\tclassName?: string;\n\tavailableAIAgents: AvailableAIAgent[];\n\tavailableHumanAgents: AvailableHumanAgent[];\n\tcurrentVisitorId?: string;\n\ttools?: ConversationTimelineTools;\n};\n\nexport const ConversationTimelineList: React.FC<ConversationTimelineProps> = ({\n\tconversationId,\n\titems: timelineItems,\n\tclassName,\n\tavailableAIAgents = [],\n\tavailableHumanAgents = [],\n\tcurrentVisitorId,\n\ttools,\n}) => {\n\tconst timeline = useConversationTimeline({\n\t\tconversationId,\n\t\titems: timelineItems,\n\t\tcurrentVisitorId,\n\t});\n\n\tconst typingIndicatorParticipants = useMemo(\n\t\t() =>\n\t\t\ttimeline.typingParticipants.map<TypingParticipant>((participant) => ({\n\t\t\t\tid: participant.id,\n\t\t\t\ttype: participant.type,\n\t\t\t})),\n\t\t[timeline.typingParticipants]\n\t);\n\n\tconst seenNameLookup = useMemo(() => {\n\t\tconst map = new Map<string, string>();\n\n\t\tfor (const agent of availableHumanAgents) {\n\t\t\tif (agent.name) {\n\t\t\t\tmap.set(agent.id, agent.name);\n\t\t\t}\n\t\t}\n\n\t\tfor (const agent of availableAIAgents) {\n\t\t\tif (agent.name) {\n\t\t\t\tmap.set(agent.id, agent.name);\n\t\t\t}\n\t\t}\n\n\t\treturn map;\n\t}, [availableHumanAgents, availableAIAgents]);\n\n\tconst getSeenByNames = useCallback(\n\t\t(ids: readonly string[] = EMPTY_SEEN_BY_IDS): readonly string[] => {\n\t\t\tif (ids.length === 0 || seenNameLookup.size === 0) {\n\t\t\t\treturn EMPTY_SEEN_BY_NAMES;\n\t\t\t}\n\n\t\t\tconst uniqueNames = new Set<string>();\n\t\t\tconst names: string[] = [];\n\n\t\t\tfor (const id of ids) {\n\t\t\t\tconst name = seenNameLookup.get(id);\n\t\t\t\tif (!name || uniqueNames.has(name)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tuniqueNames.add(name);\n\t\t\t\tnames.push(name);\n\t\t\t}\n\n\t\t\tif (names.length === 0) {\n\t\t\t\treturn EMPTY_SEEN_BY_NAMES;\n\t\t\t}\n\n\t\t\treturn Object.freeze(names);\n\t\t},\n\t\t[seenNameLookup]\n\t);\n\n\treturn (\n\t\t<PrimitiveConversationTimeline\n\t\t\tautoScroll={true}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-y-auto scroll-smooth px-3 py-6\",\n\t\t\t\t\"scrollbar-thin scrollbar-thumb-co-background-300 scrollbar-track-transparent\",\n\t\t\t\t\"h-full w-full\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\tid=\"conversation-timeline\"\n\t\t\titems={timelineItems}\n\t\t>\n\t\t\t<ConversationTimelineContainer className=\"flex min-h-full w-full flex-col gap-3\">\n\t\t\t\t{timeline.groupedMessages.items.map((item, index) => {\n\t\t\t\t\tif (item.type === \"timeline_event\") {\n\t\t\t\t\t\t// Extract event data from parts\n\t\t\t\t\t\tconst eventPart = extractEventPart(item.item);\n\n\t\t\t\t\t\t// Only render if we have valid event data\n\t\t\t\t\t\tif (!eventPart) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<ConversationEvent\n\t\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\t\tcreatedAt={item.item.createdAt}\n\t\t\t\t\t\t\t\tevent={eventPart}\n\t\t\t\t\t\t\t\tkey={item.item.id ?? `timeline-event-${item.item.createdAt}`}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (item.type === \"timeline_tool\") {\n\t\t\t\t\t\tconst toolName = item.tool ?? item.item.tool ?? item.item.type;\n\t\t\t\t\t\tconst toolDefinition = toolName ? tools?.[toolName] : undefined;\n\n\t\t\t\t\t\tif (!toolDefinition) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst ToolComponent = toolDefinition.component;\n\n\t\t\t\t\t\tconst toolKey =\n\t\t\t\t\t\t\titem.item.id ?? `${toolName}-${item.item.createdAt}-${index}`;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<ToolComponent\n\t\t\t\t\t\t\t\tconversationId={conversationId}\n\t\t\t\t\t\t\t\titem={item.item}\n\t\t\t\t\t\t\t\tkey={toolKey}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only show seen indicator on the LAST message group sent by the visitor\n\t\t\t\t\tconst isLastVisitorGroup =\n\t\t\t\t\t\tindex === timeline.lastVisitorMessageGroupIndex;\n\t\t\t\t\tconst seenByIds =\n\t\t\t\t\t\tisLastVisitorGroup && item.lastMessageId\n\t\t\t\t\t\t\t? timeline.groupedMessages.getMessageSeenBy(item.lastMessageId)\n\t\t\t\t\t\t\t: EMPTY_SEEN_BY_IDS;\n\t\t\t\t\tconst seenByNames =\n\t\t\t\t\t\tseenByIds.length > 0\n\t\t\t\t\t\t\t? getSeenByNames(seenByIds)\n\t\t\t\t\t\t\t: EMPTY_SEEN_BY_NAMES;\n\n\t\t\t\t\t// Use first timeline item ID as stable key\n\t\t\t\t\tconst groupKey =\n\t\t\t\t\t\titem.lastMessageId ??\n\t\t\t\t\t\titem.items?.[0]?.id ??\n\t\t\t\t\t\t`group-${item.items?.[0]?.createdAt ?? index}`;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<TimelineMessageGroup\n\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\tcurrentVisitorId={currentVisitorId}\n\t\t\t\t\t\t\titems={item.items || []}\n\t\t\t\t\t\t\tkey={groupKey}\n\t\t\t\t\t\t\tseenByIds={seenByIds}\n\t\t\t\t\t\t\tseenByNames={seenByNames}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t\t<div className=\"h-6 w-full\">\n\t\t\t\t\t{typingIndicatorParticipants.length > 0 ? (\n\t\t\t\t\t\t<TypingIndicator\n\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\tclassName=\"mt-2\"\n\t\t\t\t\t\t\tparticipants={typingIndicatorParticipants}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</ConversationTimelineContainer>\n\t\t</PrimitiveConversationTimeline>\n\t);\n};\n"],"mappings":";;;;;;;;;;AAkBA,SAAS,iBAAiB,MAA8C;AACvE,KAAI,KAAK,SAAS,QACjB,QAAO;AAOR,QAJkB,KAAK,MAAM,MAC3B,SAAoC,KAAK,SAAS,QACnD,IAEmB;;AAGrB,MAAMA,oBAAuC,OAAO,OAAO,EAAE,CAAC;AAC9D,MAAMC,sBAAyC,OAAO,OAAO,EAAE,CAAC;AA0BhE,MAAaC,4BAAiE,EAC7E,gBACA,OAAO,eACP,WACA,oBAAoB,EAAE,EACtB,uBAAuB,EAAE,EACzB,kBACA,YACK;CACL,MAAM,WAAW,wBAAwB;EACxC;EACA,OAAO;EACP;EACA,CAAC;CAEF,MAAM,8BAA8B,cAElC,SAAS,mBAAmB,KAAwB,iBAAiB;EACpE,IAAI,YAAY;EAChB,MAAM,YAAY;EAClB,EAAE,EACJ,CAAC,SAAS,mBAAmB,CAC7B;CAED,MAAM,iBAAiB,cAAc;EACpC,MAAM,sBAAM,IAAI,KAAqB;AAErC,OAAK,MAAM,SAAS,qBACnB,KAAI,MAAM,KACT,KAAI,IAAI,MAAM,IAAI,MAAM,KAAK;AAI/B,OAAK,MAAM,SAAS,kBACnB,KAAI,MAAM,KACT,KAAI,IAAI,MAAM,IAAI,MAAM,KAAK;AAI/B,SAAO;IACL,CAAC,sBAAsB,kBAAkB,CAAC;CAE7C,MAAM,iBAAiB,aACrB,MAAyB,sBAAyC;AAClE,MAAI,IAAI,WAAW,KAAK,eAAe,SAAS,EAC/C,QAAO;EAGR,MAAM,8BAAc,IAAI,KAAa;EACrC,MAAMC,QAAkB,EAAE;AAE1B,OAAK,MAAM,MAAM,KAAK;GACrB,MAAM,OAAO,eAAe,IAAI,GAAG;AACnC,OAAI,CAAC,QAAQ,YAAY,IAAI,KAAK,CACjC;AAGD,eAAY,IAAI,KAAK;AACrB,SAAM,KAAK,KAAK;;AAGjB,MAAI,MAAM,WAAW,EACpB,QAAO;AAGR,SAAO,OAAO,OAAO,MAAM;IAE5B,CAAC,eAAe,CAChB;AAED,QACC,oBAACC;EACA,YAAY;EACZ,WAAW,GACV,2CACA,gFACA,iBACA,UACA;EACD,IAAG;EACH,OAAO;YAEP,qBAAC;GAA8B,WAAU;cACvC,SAAS,gBAAgB,MAAM,KAAK,MAAM,UAAU;AACpD,QAAI,KAAK,SAAS,kBAAkB;KAEnC,MAAM,YAAY,iBAAiB,KAAK,KAAK;AAG7C,SAAI,CAAC,UACJ,QAAO;AAGR,YACC,oBAAC;MACmB;MACG;MACtB,WAAW,KAAK,KAAK;MACrB,OAAO;QACF,KAAK,KAAK,MAAM,kBAAkB,KAAK,KAAK,YAChD;;AAIJ,QAAI,KAAK,SAAS,iBAAiB;KAClC,MAAM,WAAW,KAAK,QAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK;KAC1D,MAAM,iBAAiB,WAAW,QAAQ,YAAY;AAEtD,SAAI,CAAC,eACJ,QAAO;KAGR,MAAM,gBAAgB,eAAe;KAErC,MAAM,UACL,KAAK,KAAK,MAAM,GAAG,SAAS,GAAG,KAAK,KAAK,UAAU,GAAG;AAEvD,YACC,oBAAC;MACgB;MAChB,MAAM,KAAK;QACN,QACJ;;IAOJ,MAAM,YADL,UAAU,SAAS,gCAEG,KAAK,gBACxB,SAAS,gBAAgB,iBAAiB,KAAK,cAAc,GAC7D;IACJ,MAAM,cACL,UAAU,SAAS,IAChB,eAAe,UAAU,GACzB;IAGJ,MAAM,WACL,KAAK,iBACL,KAAK,QAAQ,IAAI,MACjB,SAAS,KAAK,QAAQ,IAAI,aAAa;AAExC,WACC,oBAAC;KACmB;KACG;KACJ;KAClB,OAAO,KAAK,SAAS,EAAE;KAEZ;KACE;OAFR,SAGJ;KAEF,EACF,oBAAC;IAAI,WAAU;cACb,4BAA4B,SAAS,IACrC,oBAAC;KACmB;KACG;KACtB,WAAU;KACV,cAAc;MACb,GACC;KACC;IACyB;GACD"}
1
+ {"version":3,"file":"conversation-timeline.js","names":["EMPTY_SEEN_BY_IDS: readonly string[]","EMPTY_SEEN_BY_NAMES: readonly string[]","ConversationTimelineList: React.FC<ConversationTimelineProps>","names: string[]","PrimitiveConversationTimeline"],"sources":["../../../src/support/components/conversation-timeline.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport type {\n\tTimelineItem,\n\tTimelinePartEvent,\n} from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport { useCallback, useMemo } from \"react\";\nimport { useConversationTimeline } from \"../../hooks/use-conversation-timeline\";\nimport {\n\tConversationTimelineContainer,\n\tConversationTimeline as PrimitiveConversationTimeline,\n} from \"../../primitives/conversation-timeline\";\nimport { cn } from \"../utils\";\nimport { ConversationEvent } from \"./conversation-event\";\nimport { TimelineMessageGroup } from \"./timeline-message-group\";\nimport { TypingIndicator, type TypingParticipant } from \"./typing-indicator\";\n\n// Helper to extract event part from timeline item\nfunction extractEventPart(item: TimelineItem): TimelinePartEvent | null {\n\tif (item.type !== \"event\") {\n\t\treturn null;\n\t}\n\n\tconst eventPart = item.parts.find(\n\t\t(part): part is TimelinePartEvent => part.type === \"event\"\n\t);\n\n\treturn eventPart || null;\n}\n\nconst EMPTY_SEEN_BY_IDS: readonly string[] = Object.freeze([]);\nconst EMPTY_SEEN_BY_NAMES: readonly string[] = Object.freeze([]);\n\nexport type ConversationTimelineToolProps = {\n\titem: TimelineItem;\n\tconversationId: string;\n};\n\nexport type ConversationTimelineToolDefinition = {\n\tcomponent: React.ComponentType<ConversationTimelineToolProps>;\n};\n\nexport type ConversationTimelineTools = Record<\n\tstring,\n\tConversationTimelineToolDefinition\n>;\n\nexport type ConversationTimelineProps = {\n\tconversationId: string;\n\titems: TimelineItem[];\n\tclassName?: string;\n\tavailableAIAgents: AvailableAIAgent[];\n\tavailableHumanAgents: AvailableHumanAgent[];\n\tcurrentVisitorId?: string;\n\ttools?: ConversationTimelineTools;\n};\n\nexport const ConversationTimelineList: React.FC<ConversationTimelineProps> = ({\n\tconversationId,\n\titems: timelineItems,\n\tclassName,\n\tavailableAIAgents = [],\n\tavailableHumanAgents = [],\n\tcurrentVisitorId,\n\ttools,\n}) => {\n\tconst timeline = useConversationTimeline({\n\t\tconversationId,\n\t\titems: timelineItems,\n\t\tcurrentVisitorId,\n\t});\n\n\tconst typingIndicatorParticipants = useMemo(\n\t\t() =>\n\t\t\ttimeline.typingParticipants.map<TypingParticipant>((participant) => ({\n\t\t\t\tid: participant.id,\n\t\t\t\ttype: participant.type,\n\t\t\t})),\n\t\t[timeline.typingParticipants]\n\t);\n\n\tconst seenNameLookup = useMemo(() => {\n\t\tconst map = new Map<string, string>();\n\n\t\tfor (const agent of availableHumanAgents) {\n\t\t\tif (agent.name) {\n\t\t\t\tmap.set(agent.id, agent.name);\n\t\t\t}\n\t\t}\n\n\t\tfor (const agent of availableAIAgents) {\n\t\t\tif (agent.name) {\n\t\t\t\tmap.set(agent.id, agent.name);\n\t\t\t}\n\t\t}\n\n\t\treturn map;\n\t}, [availableHumanAgents, availableAIAgents]);\n\n\tconst getSeenByNames = useCallback(\n\t\t(ids: readonly string[] = EMPTY_SEEN_BY_IDS): readonly string[] => {\n\t\t\tif (ids.length === 0 || seenNameLookup.size === 0) {\n\t\t\t\treturn EMPTY_SEEN_BY_NAMES;\n\t\t\t}\n\n\t\t\tconst uniqueNames = new Set<string>();\n\t\t\tconst names: string[] = [];\n\n\t\t\tfor (const id of ids) {\n\t\t\t\tconst name = seenNameLookup.get(id);\n\t\t\t\tif (!name || uniqueNames.has(name)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tuniqueNames.add(name);\n\t\t\t\tnames.push(name);\n\t\t\t}\n\n\t\t\tif (names.length === 0) {\n\t\t\t\treturn EMPTY_SEEN_BY_NAMES;\n\t\t\t}\n\n\t\t\treturn Object.freeze(names);\n\t\t},\n\t\t[seenNameLookup]\n\t);\n\n\treturn (\n\t\t<PrimitiveConversationTimeline\n\t\t\tautoScroll={true}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-y-scroll scroll-smooth px-3 py-6\",\n\t\t\t\t\"scrollbar-thin scrollbar-thumb-co-primary/30 scrollbar-track-transparent\",\n\t\t\t\t\"h-full w-full\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\tid=\"conversation-timeline\"\n\t\t\titems={timelineItems}\n\t\t>\n\t\t\t<ConversationTimelineContainer className=\"flex min-h-full w-full flex-col gap-3\">\n\t\t\t\t{timeline.groupedMessages.items.map((item, index) => {\n\t\t\t\t\tif (item.type === \"timeline_event\") {\n\t\t\t\t\t\t// Extract event data from parts\n\t\t\t\t\t\tconst eventPart = extractEventPart(item.item);\n\n\t\t\t\t\t\t// Only render if we have valid event data\n\t\t\t\t\t\tif (!eventPart) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<ConversationEvent\n\t\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\t\tcreatedAt={item.item.createdAt}\n\t\t\t\t\t\t\t\tevent={eventPart}\n\t\t\t\t\t\t\t\tkey={item.item.id ?? `timeline-event-${item.item.createdAt}`}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (item.type === \"timeline_tool\") {\n\t\t\t\t\t\tconst toolName = item.tool ?? item.item.tool ?? item.item.type;\n\t\t\t\t\t\tconst toolDefinition = toolName ? tools?.[toolName] : undefined;\n\n\t\t\t\t\t\tif (!toolDefinition) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst ToolComponent = toolDefinition.component;\n\n\t\t\t\t\t\tconst toolKey =\n\t\t\t\t\t\t\titem.item.id ?? `${toolName}-${item.item.createdAt}-${index}`;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<ToolComponent\n\t\t\t\t\t\t\t\tconversationId={conversationId}\n\t\t\t\t\t\t\t\titem={item.item}\n\t\t\t\t\t\t\t\tkey={toolKey}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only show seen indicator on the LAST message group sent by the visitor\n\t\t\t\t\tconst isLastVisitorGroup =\n\t\t\t\t\t\tindex === timeline.lastVisitorMessageGroupIndex;\n\t\t\t\t\tconst seenByIds =\n\t\t\t\t\t\tisLastVisitorGroup && item.lastMessageId\n\t\t\t\t\t\t\t? timeline.groupedMessages.getMessageSeenBy(item.lastMessageId)\n\t\t\t\t\t\t\t: EMPTY_SEEN_BY_IDS;\n\t\t\t\t\tconst seenByNames =\n\t\t\t\t\t\tseenByIds.length > 0\n\t\t\t\t\t\t\t? getSeenByNames(seenByIds)\n\t\t\t\t\t\t\t: EMPTY_SEEN_BY_NAMES;\n\n\t\t\t\t\t// Use first timeline item ID as stable key\n\t\t\t\t\tconst groupKey =\n\t\t\t\t\t\titem.lastMessageId ??\n\t\t\t\t\t\titem.items?.[0]?.id ??\n\t\t\t\t\t\t`group-${item.items?.[0]?.createdAt ?? index}`;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<TimelineMessageGroup\n\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\tcurrentVisitorId={currentVisitorId}\n\t\t\t\t\t\t\titems={item.items || []}\n\t\t\t\t\t\t\tkey={groupKey}\n\t\t\t\t\t\t\tseenByIds={seenByIds}\n\t\t\t\t\t\t\tseenByNames={seenByNames}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t\t<div className=\"h-6 w-full\">\n\t\t\t\t\t{typingIndicatorParticipants.length > 0 ? (\n\t\t\t\t\t\t<TypingIndicator\n\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\tclassName=\"mt-2\"\n\t\t\t\t\t\t\tparticipants={typingIndicatorParticipants}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</ConversationTimelineContainer>\n\t\t</PrimitiveConversationTimeline>\n\t);\n};\n"],"mappings":";;;;;;;;;;AAkBA,SAAS,iBAAiB,MAA8C;AACvE,KAAI,KAAK,SAAS,QACjB,QAAO;AAOR,QAJkB,KAAK,MAAM,MAC3B,SAAoC,KAAK,SAAS,QACnD,IAEmB;;AAGrB,MAAMA,oBAAuC,OAAO,OAAO,EAAE,CAAC;AAC9D,MAAMC,sBAAyC,OAAO,OAAO,EAAE,CAAC;AA0BhE,MAAaC,4BAAiE,EAC7E,gBACA,OAAO,eACP,WACA,oBAAoB,EAAE,EACtB,uBAAuB,EAAE,EACzB,kBACA,YACK;CACL,MAAM,WAAW,wBAAwB;EACxC;EACA,OAAO;EACP;EACA,CAAC;CAEF,MAAM,8BAA8B,cAElC,SAAS,mBAAmB,KAAwB,iBAAiB;EACpE,IAAI,YAAY;EAChB,MAAM,YAAY;EAClB,EAAE,EACJ,CAAC,SAAS,mBAAmB,CAC7B;CAED,MAAM,iBAAiB,cAAc;EACpC,MAAM,sBAAM,IAAI,KAAqB;AAErC,OAAK,MAAM,SAAS,qBACnB,KAAI,MAAM,KACT,KAAI,IAAI,MAAM,IAAI,MAAM,KAAK;AAI/B,OAAK,MAAM,SAAS,kBACnB,KAAI,MAAM,KACT,KAAI,IAAI,MAAM,IAAI,MAAM,KAAK;AAI/B,SAAO;IACL,CAAC,sBAAsB,kBAAkB,CAAC;CAE7C,MAAM,iBAAiB,aACrB,MAAyB,sBAAyC;AAClE,MAAI,IAAI,WAAW,KAAK,eAAe,SAAS,EAC/C,QAAO;EAGR,MAAM,8BAAc,IAAI,KAAa;EACrC,MAAMC,QAAkB,EAAE;AAE1B,OAAK,MAAM,MAAM,KAAK;GACrB,MAAM,OAAO,eAAe,IAAI,GAAG;AACnC,OAAI,CAAC,QAAQ,YAAY,IAAI,KAAK,CACjC;AAGD,eAAY,IAAI,KAAK;AACrB,SAAM,KAAK,KAAK;;AAGjB,MAAI,MAAM,WAAW,EACpB,QAAO;AAGR,SAAO,OAAO,OAAO,MAAM;IAE5B,CAAC,eAAe,CAChB;AAED,QACC,oBAACC;EACA,YAAY;EACZ,WAAW,GACV,6CACA,4EACA,iBACA,UACA;EACD,IAAG;EACH,OAAO;YAEP,qBAAC;GAA8B,WAAU;cACvC,SAAS,gBAAgB,MAAM,KAAK,MAAM,UAAU;AACpD,QAAI,KAAK,SAAS,kBAAkB;KAEnC,MAAM,YAAY,iBAAiB,KAAK,KAAK;AAG7C,SAAI,CAAC,UACJ,QAAO;AAGR,YACC,oBAAC;MACmB;MACG;MACtB,WAAW,KAAK,KAAK;MACrB,OAAO;QACF,KAAK,KAAK,MAAM,kBAAkB,KAAK,KAAK,YAChD;;AAIJ,QAAI,KAAK,SAAS,iBAAiB;KAClC,MAAM,WAAW,KAAK,QAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK;KAC1D,MAAM,iBAAiB,WAAW,QAAQ,YAAY;AAEtD,SAAI,CAAC,eACJ,QAAO;KAGR,MAAM,gBAAgB,eAAe;KAErC,MAAM,UACL,KAAK,KAAK,MAAM,GAAG,SAAS,GAAG,KAAK,KAAK,UAAU,GAAG;AAEvD,YACC,oBAAC;MACgB;MAChB,MAAM,KAAK;QACN,QACJ;;IAOJ,MAAM,YADL,UAAU,SAAS,gCAEG,KAAK,gBACxB,SAAS,gBAAgB,iBAAiB,KAAK,cAAc,GAC7D;IACJ,MAAM,cACL,UAAU,SAAS,IAChB,eAAe,UAAU,GACzB;IAGJ,MAAM,WACL,KAAK,iBACL,KAAK,QAAQ,IAAI,MACjB,SAAS,KAAK,QAAQ,IAAI,aAAa;AAExC,WACC,oBAAC;KACmB;KACG;KACJ;KAClB,OAAO,KAAK,SAAS,EAAE;KAEZ;KACE;OAFR,SAGJ;KAEF,EACF,oBAAC;IAAI,WAAU;cACb,4BAA4B,SAAS,IACrC,oBAAC;KACmB;KACG;KACtB,WAAU;KACV,cAAc;MACb,GACC;KACC;IACyB;GACD"}
@@ -81,9 +81,9 @@ const MultimodalInput = ({ className, value, onChange, onSubmit, onFileSelect, p
81
81
  }, `${file.name}-${index}`))
82
82
  }),
83
83
  /* @__PURE__ */ jsxs("div", {
84
- className: "flex flex-col rounded border border-co-border/50 bg-co-background-100 dark:bg-co-background-200",
84
+ className: "group/multimodal-input flex flex-col rounded border border-co-border bg-co-background ring-offset-2 focus-within:ring-1 focus-within:ring-co-primary/10 dark:bg-co-background-200",
85
85
  children: [/* @__PURE__ */ jsx(MultimodalInput$1, {
86
- className: cn("flex-1 resize-none overflow-hidden p-3 text-co-foreground text-sm placeholder:text-co-primary/40 focus-visible:outline-none", className),
86
+ className: cn("flex-1 resize-none overflow-hidden p-3 text-co-foreground text-sm placeholder:text-co-primary/50 focus-visible:outline-none", className),
87
87
  disabled: disabled || isSubmitting,
88
88
  error,
89
89
  onChange,
@@ -1 +1 @@
1
- {"version":3,"file":"multimodal-input.js","names":["MultimodalInput: React.FC<MultimodalInputProps>","Icon","Primitive.MultimodalInput","SendButton: React.FC<SendButtonProps>","Primitive.Button"],"sources":["../../../src/support/components/multimodal-input.tsx"],"sourcesContent":["\"use client\";\n\nimport type React from \"react\";\nimport { useRef } from \"react\";\nimport { useComposerRefocus } from \"../../hooks/use-composer-refocus\";\nimport * as Primitive from \"../../primitives\";\nimport { useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\nimport { Watermark } from \"./watermark\";\n\nexport type MultimodalInputProps = {\n\tclassName?: string;\n\tvalue: string;\n\tonChange: (value: string) => void;\n\tonSubmit: () => void;\n\tonFileSelect?: (files: File[]) => void;\n\tplaceholder?: string;\n\tdisabled?: boolean;\n\tisSubmitting?: boolean;\n\terror?: Error | null;\n\tfiles?: File[];\n\tonRemoveFile?: (index: number) => void;\n\tmaxFiles?: number;\n\tmaxFileSize?: number;\n\tallowedFileTypes?: string[];\n};\n\nexport const MultimodalInput: React.FC<MultimodalInputProps> = ({\n\tclassName,\n\tvalue,\n\tonChange,\n\tonSubmit,\n\tonFileSelect,\n\tplaceholder,\n\tdisabled = false,\n\tisSubmitting = false,\n\terror,\n\tfiles = [],\n\tonRemoveFile,\n\tmaxFiles = 5,\n\tmaxFileSize = 10 * 1024 * 1024, // 10MB\n\tallowedFileTypes = [\"image/*\", \"application/pdf\", \"text/*\"],\n}) => {\n\tconst fileInputRef = useRef<HTMLInputElement>(null);\n\tconst hasContent = value.trim().length > 0 || files.length > 0;\n\tconst { focusComposer, inputRef } = useComposerRefocus({\n\t\tdisabled,\n\t\thasContent,\n\t\tisSubmitting,\n\t});\n\tconst canSubmit = !(disabled || isSubmitting) && hasContent;\n\tconst text = useSupportText();\n\tconst resolvedPlaceholder =\n\t\tplaceholder ?? text(\"component.multimodalInput.placeholder\");\n\n\tconst handleSubmit = () => {\n\t\tif (!canSubmit) {\n\t\t\treturn;\n\t\t}\n\n\t\tonSubmit();\n\t\tfocusComposer();\n\t};\n\n\tconst handleFormSubmit = (e: React.FormEvent) => {\n\t\te.preventDefault();\n\t\thandleSubmit();\n\t};\n\n\tconst handleAttachClick = () => {\n\t\tif (files.length < maxFiles) {\n\t\t\tfileInputRef.current?.click();\n\t\t}\n\t};\n\n\tconst formatFileSize = (bytes: number) => {\n\t\tif (bytes < 1024) {\n\t\t\treturn `${bytes} B`;\n\t\t}\n\t\tif (bytes < 1024 * 1024) {\n\t\t\treturn `${(bytes / 1024).toFixed(1)} KB`;\n\t\t}\n\t\treturn `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n\t};\n\n\treturn (\n\t\t<form className=\"flex flex-col gap-2\" onSubmit={handleFormSubmit}>\n\t\t\t{/* Error message */}\n\t\t\t{error && (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"rounded-md bg-co-destructive-muted p-2 text-co-destructive text-xs\"\n\t\t\t\t\tid=\"multimodal-input-error\"\n\t\t\t\t>\n\t\t\t\t\t{error.message}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* File attachments */}\n\t\t\t{files.length > 0 && (\n\t\t\t\t<div className=\"flex flex-wrap gap-2 p-2\">\n\t\t\t\t\t{files.map((file, index) => (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"flex items-center gap-2 rounded-md bg-co-muted px-2 py-1 text-xs\"\n\t\t\t\t\t\t\tkey={`${file.name}-${index}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Icon className=\"h-3 w-3\" name=\"attachment\" />\n\t\t\t\t\t\t\t<span className=\"max-w-[150px] truncate\">{file.name}</span>\n\t\t\t\t\t\t\t<span className=\"text-co-muted-foreground\">\n\t\t\t\t\t\t\t\t{formatFileSize(file.size)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{onRemoveFile && (\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\taria-label={text(\"common.actions.removeFile\", {\n\t\t\t\t\t\t\t\t\t\tfileName: file.name,\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\tclassName=\"ml-1 hover:text-co-destructive\"\n\t\t\t\t\t\t\t\t\tonClick={() => onRemoveFile(index)}\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon className=\"h-3 w-3\" name=\"close\" />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Input area */}\n\t\t\t<div className=\"flex flex-col rounded border border-co-border/50 bg-co-background-100 dark:bg-co-background-200\">\n\t\t\t\t<Primitive.MultimodalInput\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"flex-1 resize-none overflow-hidden p-3 text-co-foreground text-sm placeholder:text-co-primary/40 focus-visible:outline-none\",\n\t\t\t\t\t\tclassName\n\t\t\t\t\t)}\n\t\t\t\t\tdisabled={disabled || isSubmitting}\n\t\t\t\t\terror={error}\n\t\t\t\t\tonChange={onChange}\n\t\t\t\t\tonFileSelect={onFileSelect}\n\t\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\t\tplaceholder={resolvedPlaceholder}\n\t\t\t\t\tref={inputRef}\n\t\t\t\t\tvalue={value}\n\t\t\t\t/>\n\n\t\t\t\t<div className=\"flex items-center justify-between py-1 pr-1 pl-3\">\n\t\t\t\t\t<Watermark />\n\n\t\t\t\t\t<div className=\"flex items-center gap-0.5\">\n\t\t\t\t\t\t{/* File attachment button */}\n\t\t\t\t\t\t{/* {onFileSelect && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\taria-label={text(\"common.actions.attachFiles\")}\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"group flex h-8 w-8 items-center justify-center rounded-md text-co-muted-foreground hover:bg-co-muted hover:text-co-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\t\t\t\t\t\tfiles.length >= maxFiles && \"opacity-50\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\t\t\t\tdisabled || isSubmitting || files.length >= maxFiles\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tonClick={handleAttachClick}\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon className=\"h-4 w-4\" name=\"attachment\" />\n\t\t\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t\t\t<Primitive.FileInput\n\t\t\t\t\t\t\t\t\taccept={allowedFileTypes.join(\",\")}\n\t\t\t\t\t\t\t\t\tclassName=\"hidden\"\n\t\t\t\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\t\t\t\tdisabled || isSubmitting || files.length >= maxFiles\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tonFileSelect={onFileSelect}\n\t\t\t\t\t\t\t\t\tref={fileInputRef}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)} */}\n\n\t\t\t\t\t\t{/* Send button */}\n\t\t\t\t\t\t<SendButton disabled={!canSubmit} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</form>\n\t);\n};\n\nexport type SendButtonProps = {\n\tclassName?: string;\n\tdisabled?: boolean;\n};\n\nexport const SendButton: React.FC<SendButtonProps> = ({\n\tclassName,\n\tdisabled = false,\n}) => (\n\t<Primitive.Button\n\t\tclassName={cn(\n\t\t\t\"group flex h-8 w-8 items-center justify-center rounded-md text-co-primary hover:bg-co-muted disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\tclassName\n\t\t)}\n\t\tdisabled={disabled}\n\t\ttype=\"submit\"\n\t>\n\t\t<Icon className=\"h-4 w-4\" filledOnHover name=\"send\" />\n\t</Primitive.Button>\n);\n"],"mappings":";;;;;;;;;;;;;;AA4BA,MAAaA,mBAAmD,EAC/D,WACA,OACA,UACA,UACA,cACA,aACA,WAAW,OACX,eAAe,OACf,OACA,QAAQ,EAAE,EACV,cACA,WAAW,GACX,cAAc,KAAK,OAAO,MAC1B,mBAAmB;CAAC;CAAW;CAAmB;CAAS,OACtD;AACgB,QAAyB,KAAK;CACnD,MAAM,aAAa,MAAM,MAAM,CAAC,SAAS,KAAK,MAAM,SAAS;CAC7D,MAAM,EAAE,eAAe,aAAa,mBAAmB;EACtD;EACA;EACA;EACA,CAAC;CACF,MAAM,YAAY,EAAE,YAAY,iBAAiB;CACjD,MAAM,OAAO,gBAAgB;CAC7B,MAAM,sBACL,eAAe,KAAK,wCAAwC;CAE7D,MAAM,qBAAqB;AAC1B,MAAI,CAAC,UACJ;AAGD,YAAU;AACV,iBAAe;;CAGhB,MAAM,oBAAoB,MAAuB;AAChD,IAAE,gBAAgB;AAClB,gBAAc;;CASf,MAAM,kBAAkB,UAAkB;AACzC,MAAI,QAAQ,KACX,QAAO,GAAG,MAAM;AAEjB,MAAI,QAAQ,OAAO,KAClB,QAAO,IAAI,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAErC,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,EAAE,CAAC;;AAG9C,QACC,qBAAC;EAAK,WAAU;EAAsB,UAAU;;GAE9C,SACA,oBAAC;IACA,WAAU;IACV,IAAG;cAEF,MAAM;KACF;GAIN,MAAM,SAAS,KACf,oBAAC;IAAI,WAAU;cACb,MAAM,KAAK,MAAM,UACjB,qBAAC;KACA,WAAU;;MAGV,oBAACC;OAAK,WAAU;OAAU,MAAK;QAAe;MAC9C,oBAAC;OAAK,WAAU;iBAA0B,KAAK;QAAY;MAC3D,oBAAC;OAAK,WAAU;iBACd,eAAe,KAAK,KAAK;QACpB;MACN,gBACA,oBAAC;OACA,cAAY,KAAK,6BAA6B,EAC7C,UAAU,KAAK,MACf,CAAC;OACF,WAAU;OACV,eAAe,aAAa,MAAM;OAClC,MAAK;iBAEL,oBAACA;QAAK,WAAU;QAAU,MAAK;SAAU;QACjC;;OAjBL,GAAG,KAAK,KAAK,GAAG,QAmBhB,CACL;KACG;GAIP,qBAAC;IAAI,WAAU;eACd,oBAACC;KACA,WAAW,GACV,+HACA,UACA;KACD,UAAU,YAAY;KACf;KACG;KACI;KACd,UAAU;KACV,aAAa;KACb,KAAK;KACE;MACN,EAEF,qBAAC;KAAI,WAAU;gBACd,oBAAC,cAAY,EAEb,oBAAC;MAAI,WAAU;gBAgCd,oBAAC,cAAW,UAAU,CAAC,YAAa;OAC/B;MACD;KACD;;GACA;;AAST,MAAaC,cAAyC,EACrD,WACA,WAAW,YAEX,oBAACC;CACA,WAAW,GACV,+IACA,UACA;CACS;CACV,MAAK;WAEL,oBAACH;EAAK,WAAU;EAAU;EAAc,MAAK;GAAS;EACpC"}
1
+ {"version":3,"file":"multimodal-input.js","names":["MultimodalInput: React.FC<MultimodalInputProps>","Icon","Primitive.MultimodalInput","SendButton: React.FC<SendButtonProps>","Primitive.Button"],"sources":["../../../src/support/components/multimodal-input.tsx"],"sourcesContent":["\"use client\";\n\nimport type React from \"react\";\nimport { useRef } from \"react\";\nimport { useComposerRefocus } from \"../../hooks/use-composer-refocus\";\nimport * as Primitive from \"../../primitives\";\nimport { useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\nimport { Watermark } from \"./watermark\";\n\nexport type MultimodalInputProps = {\n\tclassName?: string;\n\tvalue: string;\n\tonChange: (value: string) => void;\n\tonSubmit: () => void;\n\tonFileSelect?: (files: File[]) => void;\n\tplaceholder?: string;\n\tdisabled?: boolean;\n\tisSubmitting?: boolean;\n\terror?: Error | null;\n\tfiles?: File[];\n\tonRemoveFile?: (index: number) => void;\n\tmaxFiles?: number;\n\tmaxFileSize?: number;\n\tallowedFileTypes?: string[];\n};\n\nexport const MultimodalInput: React.FC<MultimodalInputProps> = ({\n\tclassName,\n\tvalue,\n\tonChange,\n\tonSubmit,\n\tonFileSelect,\n\tplaceholder,\n\tdisabled = false,\n\tisSubmitting = false,\n\terror,\n\tfiles = [],\n\tonRemoveFile,\n\tmaxFiles = 5,\n\tmaxFileSize = 10 * 1024 * 1024, // 10MB\n\tallowedFileTypes = [\"image/*\", \"application/pdf\", \"text/*\"],\n}) => {\n\tconst fileInputRef = useRef<HTMLInputElement>(null);\n\tconst hasContent = value.trim().length > 0 || files.length > 0;\n\tconst { focusComposer, inputRef } = useComposerRefocus({\n\t\tdisabled,\n\t\thasContent,\n\t\tisSubmitting,\n\t});\n\tconst canSubmit = !(disabled || isSubmitting) && hasContent;\n\tconst text = useSupportText();\n\tconst resolvedPlaceholder =\n\t\tplaceholder ?? text(\"component.multimodalInput.placeholder\");\n\n\tconst handleSubmit = () => {\n\t\tif (!canSubmit) {\n\t\t\treturn;\n\t\t}\n\n\t\tonSubmit();\n\t\tfocusComposer();\n\t};\n\n\tconst handleFormSubmit = (e: React.FormEvent) => {\n\t\te.preventDefault();\n\t\thandleSubmit();\n\t};\n\n\tconst handleAttachClick = () => {\n\t\tif (files.length < maxFiles) {\n\t\t\tfileInputRef.current?.click();\n\t\t}\n\t};\n\n\tconst formatFileSize = (bytes: number) => {\n\t\tif (bytes < 1024) {\n\t\t\treturn `${bytes} B`;\n\t\t}\n\t\tif (bytes < 1024 * 1024) {\n\t\t\treturn `${(bytes / 1024).toFixed(1)} KB`;\n\t\t}\n\t\treturn `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n\t};\n\n\treturn (\n\t\t<form className=\"flex flex-col gap-2\" onSubmit={handleFormSubmit}>\n\t\t\t{/* Error message */}\n\t\t\t{error && (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"rounded-md bg-co-destructive-muted p-2 text-co-destructive text-xs\"\n\t\t\t\t\tid=\"multimodal-input-error\"\n\t\t\t\t>\n\t\t\t\t\t{error.message}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* File attachments */}\n\t\t\t{files.length > 0 && (\n\t\t\t\t<div className=\"flex flex-wrap gap-2 p-2\">\n\t\t\t\t\t{files.map((file, index) => (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName=\"flex items-center gap-2 rounded-md bg-co-muted px-2 py-1 text-xs\"\n\t\t\t\t\t\t\tkey={`${file.name}-${index}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Icon className=\"h-3 w-3\" name=\"attachment\" />\n\t\t\t\t\t\t\t<span className=\"max-w-[150px] truncate\">{file.name}</span>\n\t\t\t\t\t\t\t<span className=\"text-co-muted-foreground\">\n\t\t\t\t\t\t\t\t{formatFileSize(file.size)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{onRemoveFile && (\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\taria-label={text(\"common.actions.removeFile\", {\n\t\t\t\t\t\t\t\t\t\tfileName: file.name,\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\tclassName=\"ml-1 hover:text-co-destructive\"\n\t\t\t\t\t\t\t\t\tonClick={() => onRemoveFile(index)}\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon className=\"h-3 w-3\" name=\"close\" />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Input area */}\n\t\t\t<div className=\"group/multimodal-input flex flex-col rounded border border-co-border bg-co-background ring-offset-2 focus-within:ring-1 focus-within:ring-co-primary/10 dark:bg-co-background-200\">\n\t\t\t\t<Primitive.MultimodalInput\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"flex-1 resize-none overflow-hidden p-3 text-co-foreground text-sm placeholder:text-co-primary/50 focus-visible:outline-none\",\n\t\t\t\t\t\tclassName\n\t\t\t\t\t)}\n\t\t\t\t\tdisabled={disabled || isSubmitting}\n\t\t\t\t\terror={error}\n\t\t\t\t\tonChange={onChange}\n\t\t\t\t\tonFileSelect={onFileSelect}\n\t\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\t\tplaceholder={resolvedPlaceholder}\n\t\t\t\t\tref={inputRef}\n\t\t\t\t\tvalue={value}\n\t\t\t\t/>\n\n\t\t\t\t<div className=\"flex items-center justify-between py-1 pr-1 pl-3\">\n\t\t\t\t\t<Watermark />\n\n\t\t\t\t\t<div className=\"flex items-center gap-0.5\">\n\t\t\t\t\t\t{/* File attachment button */}\n\t\t\t\t\t\t{/* {onFileSelect && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\taria-label={text(\"common.actions.attachFiles\")}\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\"group flex h-8 w-8 items-center justify-center rounded-md text-co-muted-foreground hover:bg-co-muted hover:text-co-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\t\t\t\t\t\tfiles.length >= maxFiles && \"opacity-50\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\t\t\t\tdisabled || isSubmitting || files.length >= maxFiles\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tonClick={handleAttachClick}\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon className=\"h-4 w-4\" name=\"attachment\" />\n\t\t\t\t\t\t\t\t</button>\n\n\t\t\t\t\t\t\t\t<Primitive.FileInput\n\t\t\t\t\t\t\t\t\taccept={allowedFileTypes.join(\",\")}\n\t\t\t\t\t\t\t\t\tclassName=\"hidden\"\n\t\t\t\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\t\t\t\tdisabled || isSubmitting || files.length >= maxFiles\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tonFileSelect={onFileSelect}\n\t\t\t\t\t\t\t\t\tref={fileInputRef}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)} */}\n\n\t\t\t\t\t\t{/* Send button */}\n\t\t\t\t\t\t<SendButton disabled={!canSubmit} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</form>\n\t);\n};\n\nexport type SendButtonProps = {\n\tclassName?: string;\n\tdisabled?: boolean;\n};\n\nexport const SendButton: React.FC<SendButtonProps> = ({\n\tclassName,\n\tdisabled = false,\n}) => (\n\t<Primitive.Button\n\t\tclassName={cn(\n\t\t\t\"group flex h-8 w-8 items-center justify-center rounded-md text-co-primary hover:bg-co-muted disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\tclassName\n\t\t)}\n\t\tdisabled={disabled}\n\t\ttype=\"submit\"\n\t>\n\t\t<Icon className=\"h-4 w-4\" filledOnHover name=\"send\" />\n\t</Primitive.Button>\n);\n"],"mappings":";;;;;;;;;;;;;;AA4BA,MAAaA,mBAAmD,EAC/D,WACA,OACA,UACA,UACA,cACA,aACA,WAAW,OACX,eAAe,OACf,OACA,QAAQ,EAAE,EACV,cACA,WAAW,GACX,cAAc,KAAK,OAAO,MAC1B,mBAAmB;CAAC;CAAW;CAAmB;CAAS,OACtD;AACgB,QAAyB,KAAK;CACnD,MAAM,aAAa,MAAM,MAAM,CAAC,SAAS,KAAK,MAAM,SAAS;CAC7D,MAAM,EAAE,eAAe,aAAa,mBAAmB;EACtD;EACA;EACA;EACA,CAAC;CACF,MAAM,YAAY,EAAE,YAAY,iBAAiB;CACjD,MAAM,OAAO,gBAAgB;CAC7B,MAAM,sBACL,eAAe,KAAK,wCAAwC;CAE7D,MAAM,qBAAqB;AAC1B,MAAI,CAAC,UACJ;AAGD,YAAU;AACV,iBAAe;;CAGhB,MAAM,oBAAoB,MAAuB;AAChD,IAAE,gBAAgB;AAClB,gBAAc;;CASf,MAAM,kBAAkB,UAAkB;AACzC,MAAI,QAAQ,KACX,QAAO,GAAG,MAAM;AAEjB,MAAI,QAAQ,OAAO,KAClB,QAAO,IAAI,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAErC,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,EAAE,CAAC;;AAG9C,QACC,qBAAC;EAAK,WAAU;EAAsB,UAAU;;GAE9C,SACA,oBAAC;IACA,WAAU;IACV,IAAG;cAEF,MAAM;KACF;GAIN,MAAM,SAAS,KACf,oBAAC;IAAI,WAAU;cACb,MAAM,KAAK,MAAM,UACjB,qBAAC;KACA,WAAU;;MAGV,oBAACC;OAAK,WAAU;OAAU,MAAK;QAAe;MAC9C,oBAAC;OAAK,WAAU;iBAA0B,KAAK;QAAY;MAC3D,oBAAC;OAAK,WAAU;iBACd,eAAe,KAAK,KAAK;QACpB;MACN,gBACA,oBAAC;OACA,cAAY,KAAK,6BAA6B,EAC7C,UAAU,KAAK,MACf,CAAC;OACF,WAAU;OACV,eAAe,aAAa,MAAM;OAClC,MAAK;iBAEL,oBAACA;QAAK,WAAU;QAAU,MAAK;SAAU;QACjC;;OAjBL,GAAG,KAAK,KAAK,GAAG,QAmBhB,CACL;KACG;GAIP,qBAAC;IAAI,WAAU;eACd,oBAACC;KACA,WAAW,GACV,+HACA,UACA;KACD,UAAU,YAAY;KACf;KACG;KACI;KACd,UAAU;KACV,aAAa;KACb,KAAK;KACE;MACN,EAEF,qBAAC;KAAI,WAAU;gBACd,oBAAC,cAAY,EAEb,oBAAC;MAAI,WAAU;gBAgCd,oBAAC,cAAW,UAAU,CAAC,YAAa;OAC/B;MACD;KACD;;GACA;;AAST,MAAaC,cAAyC,EACrD,WACA,WAAW,YAEX,oBAACC;CACA,WAAW,GACV,+IACA,UACA;CACS;CACV,MAAK;WAEL,oBAACH;EAAK,WAAU;EAAU;EAAc,MAAK;GAAS;EACpC"}
@@ -1,3 +1,4 @@
1
+ import { SupportProps } from "../index.js";
1
2
  import React from "react";
2
3
 
3
4
  //#region src/support/components/support-content.d.ts
@@ -6,15 +7,12 @@ type SupportContentProps = {
6
7
  position?: "top" | "bottom";
7
8
  align?: "right" | "left";
8
9
  positioning?: "fixed" | "absolute";
10
+ slots?: SupportProps["slots"];
11
+ classNames?: SupportProps["classNames"];
12
+ children?: React.ReactNode;
9
13
  };
10
14
  /**
11
- * Main support widget content container.
12
- *
13
- * Handles the layout and positioning of the support widget,
14
- * and renders the appropriate page via SupportRouter.
15
- *
16
- * Each page (e.g., conversation, home) manages its own state internally,
17
- * so this component is purely presentational.
15
+ * Main support widget container handling layout, positioning, and routing.
18
16
  */
19
17
  declare const SupportContent: React.FC<SupportContentProps>;
20
18
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"support-content.d.ts","names":[],"sources":["../../../src/support/components/support-content.tsx"],"sourcesContent":[],"mappings":";;;KAUK,mBAAA;;EAAA,QAAA,CAAA,EAAA,KAAA,GAAA,QAAmB;EAgBX,KAAA,CAAA,EAAA,OAAA,GAmCZ,MAAA;;;;;;;;;;;;cAnCY,gBAAgB,KAAA,CAAM,GAAG"}
1
+ {"version":3,"file":"support-content.d.ts","names":[],"sources":["../../../src/support/components/support-content.tsx"],"sourcesContent":[],"mappings":";;;;KAWK,mBAAA;;EAAA,QAAA,CAAA,EAAA,KAAA,GAAA,QAAmB;EAKf,KAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EACK,WAAA,CAAA,EAAA,OAAA,GAAA,UAAA;EACF,KAAM,CAAA,EAFT,YAES,CAAA,OAAA,CAAA;EAAS,UAAA,CAAA,EADb,YACa,CAAA,YAAA,CAAA;EAMd,QAAA,CAAA,EAND,KAAA,CAAM,SAwDjB;;;;;cAlDY,gBAAgB,KAAA,CAAM,GAAG"}
@@ -10,21 +10,18 @@ import { motion } from "motion/react";
10
10
 
11
11
  //#region src/support/components/support-content.tsx
12
12
  /**
13
- * Main support widget content container.
14
- *
15
- * Handles the layout and positioning of the support widget,
16
- * and renders the appropriate page via SupportRouter.
17
- *
18
- * Each page (e.g., conversation, home) manages its own state internally,
19
- * so this component is purely presentational.
13
+ * Main support widget container handling layout, positioning, and routing.
20
14
  */
21
- const SupportContent = ({ className, position = "bottom", align = "right", positioning = "fixed" }) => {
15
+ const SupportContent = ({ className, position = "bottom", align = "right", positioning = "fixed", slots = {}, classNames = {}, children }) => {
16
+ const BubbleComponent = slots.bubble ?? Bubble;
17
+ const ContainerComponent = slots.container ?? Container;
18
+ const RouterComponent = slots.router ?? SupportRouter;
22
19
  const containerClasses = cn("cossistant z-[9999]", positioning === "fixed" ? "fixed" : "absolute", {
23
20
  "bottom-4": position === "bottom",
24
21
  "top-4": position === "top",
25
22
  "right-4": align === "right",
26
23
  "left-4": align === "left"
27
- }, className);
24
+ }, classNames.root, className);
28
25
  return /* @__PURE__ */ jsxs(motion.div, {
29
26
  animate: { opacity: 1 },
30
27
  className: containerClasses,
@@ -34,10 +31,11 @@ const SupportContent = ({ className, position = "bottom", align = "right", posit
34
31
  default: { ease: "anticipate" },
35
32
  layout: { duration: .3 }
36
33
  },
37
- children: [/* @__PURE__ */ jsx(Bubble, { className: "z-[1000] md:z-[9999]" }), /* @__PURE__ */ jsx(Container, {
34
+ children: [/* @__PURE__ */ jsx(BubbleComponent, { className: cn("z-[1000] md:z-[9999]", classNames.bubble) }), /* @__PURE__ */ jsx(ContainerComponent, {
38
35
  align,
36
+ className: classNames.container,
39
37
  position,
40
- children: /* @__PURE__ */ jsx(SupportRouter, {})
38
+ children: /* @__PURE__ */ jsx(RouterComponent, { children })
41
39
  })]
42
40
  });
43
41
  };
@@ -1 +1 @@
1
- {"version":3,"file":"support-content.js","names":["SupportContent: React.FC<SupportContentProps>"],"sources":["../../../src/support/components/support-content.tsx"],"sourcesContent":["\"use client\";\n\nimport { motion } from \"motion/react\";\nimport type React from \"react\";\n\nimport { SupportRouter } from \"../router\";\nimport { cn } from \"../utils\";\nimport { Bubble } from \"./bubble\";\nimport { Container } from \"./container\";\n\ntype SupportContentProps = {\n\tclassName?: string;\n\tposition?: \"top\" | \"bottom\";\n\talign?: \"right\" | \"left\";\n\tpositioning?: \"fixed\" | \"absolute\";\n};\n\n/**\n * Main support widget content container.\n *\n * Handles the layout and positioning of the support widget,\n * and renders the appropriate page via SupportRouter.\n *\n * Each page (e.g., conversation, home) manages its own state internally,\n * so this component is purely presentational.\n */\nexport const SupportContent: React.FC<SupportContentProps> = ({\n\tclassName,\n\tposition = \"bottom\",\n\talign = \"right\",\n\tpositioning = \"fixed\",\n}) => {\n\tconst containerClasses = cn(\n\t\t\"cossistant z-[9999]\",\n\t\tpositioning === \"fixed\" ? \"fixed\" : \"absolute\",\n\t\t{\n\t\t\t\"bottom-4\": position === \"bottom\",\n\t\t\t\"top-4\": position === \"top\",\n\t\t\t\"right-4\": align === \"right\",\n\t\t\t\"left-4\": align === \"left\",\n\t\t},\n\t\tclassName\n\t);\n\n\treturn (\n\t\t<motion.div\n\t\t\tanimate={{ opacity: 1 }}\n\t\t\tclassName={containerClasses}\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<Bubble className=\"z-[1000] md:z-[9999]\" />\n\t\t\t<Container align={align} position={position}>\n\t\t\t\t<SupportRouter />\n\t\t\t</Container>\n\t\t</motion.div>\n\t);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0BA,MAAaA,kBAAiD,EAC7D,WACA,WAAW,UACX,QAAQ,SACR,cAAc,cACT;CACL,MAAM,mBAAmB,GACxB,uBACA,gBAAgB,UAAU,UAAU,YACpC;EACC,YAAY,aAAa;EACzB,SAAS,aAAa;EACtB,WAAW,UAAU;EACrB,UAAU,UAAU;EACpB,EACD,UACA;AAED,QACC,qBAAC,OAAO;EACP,SAAS,EAAE,SAAS,GAAG;EACvB,WAAW;EACX,SAAS,EAAE,SAAS,GAAG;EACvB,QAAO;EACP,YAAY;GACX,SAAS,EAAE,MAAM,cAAc;GAC/B,QAAQ,EAAE,UAAU,IAAK;GACzB;aAED,oBAAC,UAAO,WAAU,yBAAyB,EAC3C,oBAAC;GAAiB;GAAiB;aAClC,oBAAC,kBAAgB;IACN;GACA"}
1
+ {"version":3,"file":"support-content.js","names":["SupportContent: React.FC<SupportContentProps>"],"sources":["../../../src/support/components/support-content.tsx"],"sourcesContent":["\"use client\";\n\nimport { motion } from \"motion/react\";\nimport type React from \"react\";\n\nimport type { SupportProps } from \"../index\";\nimport { SupportRouter } from \"../router\";\nimport { cn } from \"../utils\";\nimport { Bubble } from \"./bubble\";\nimport { Container } from \"./container\";\n\ntype SupportContentProps = {\n\tclassName?: string;\n\tposition?: \"top\" | \"bottom\";\n\talign?: \"right\" | \"left\";\n\tpositioning?: \"fixed\" | \"absolute\";\n\tslots?: SupportProps[\"slots\"];\n\tclassNames?: SupportProps[\"classNames\"];\n\tchildren?: React.ReactNode;\n};\n\n/**\n * Main support widget container handling layout, positioning, and routing.\n */\nexport const SupportContent: React.FC<SupportContentProps> = ({\n\tclassName,\n\tposition = \"bottom\",\n\talign = \"right\",\n\tpositioning = \"fixed\",\n\tslots = {},\n\tclassNames = {},\n\tchildren,\n}) => {\n\t// Use custom components if provided, otherwise use defaults\n\tconst BubbleComponent = slots.bubble ?? Bubble;\n\tconst ContainerComponent = slots.container ?? Container;\n\tconst RouterComponent = slots.router ?? SupportRouter;\n\n\tconst containerClasses = cn(\n\t\t\"cossistant z-[9999]\",\n\t\tpositioning === \"fixed\" ? \"fixed\" : \"absolute\",\n\t\t{\n\t\t\t\"bottom-4\": position === \"bottom\",\n\t\t\t\"top-4\": position === \"top\",\n\t\t\t\"right-4\": align === \"right\",\n\t\t\t\"left-4\": align === \"left\",\n\t\t},\n\t\tclassNames.root,\n\t\tclassName\n\t);\n\n\treturn (\n\t\t<motion.div\n\t\t\tanimate={{ opacity: 1 }}\n\t\t\tclassName={containerClasses}\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<BubbleComponent\n\t\t\t\tclassName={cn(\"z-[1000] md:z-[9999]\", classNames.bubble)}\n\t\t\t/>\n\t\t\t<ContainerComponent\n\t\t\t\talign={align}\n\t\t\t\tclassName={classNames.container}\n\t\t\t\tposition={position}\n\t\t\t>\n\t\t\t\t<RouterComponent>{children}</RouterComponent>\n\t\t\t</ContainerComponent>\n\t\t</motion.div>\n\t);\n};\n"],"mappings":";;;;;;;;;;;;;;AAwBA,MAAaA,kBAAiD,EAC7D,WACA,WAAW,UACX,QAAQ,SACR,cAAc,SACd,QAAQ,EAAE,EACV,aAAa,EAAE,EACf,eACK;CAEL,MAAM,kBAAkB,MAAM,UAAU;CACxC,MAAM,qBAAqB,MAAM,aAAa;CAC9C,MAAM,kBAAkB,MAAM,UAAU;CAExC,MAAM,mBAAmB,GACxB,uBACA,gBAAgB,UAAU,UAAU,YACpC;EACC,YAAY,aAAa;EACzB,SAAS,aAAa;EACtB,WAAW,UAAU;EACrB,UAAU,UAAU;EACpB,EACD,WAAW,MACX,UACA;AAED,QACC,qBAAC,OAAO;EACP,SAAS,EAAE,SAAS,GAAG;EACvB,WAAW;EACX,SAAS,EAAE,SAAS,GAAG;EACvB,QAAO;EACP,YAAY;GACX,SAAS,EAAE,MAAM,cAAc;GAC/B,QAAQ,EAAE,UAAU,IAAK;GACzB;aAED,oBAAC,mBACA,WAAW,GAAG,wBAAwB,WAAW,OAAO,GACvD,EACF,oBAAC;GACO;GACP,WAAW,WAAW;GACZ;aAEV,oBAAC,mBAAiB,WAA2B;IACzB;GACT"}
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+
3
+ //#region src/support/components/theme-wrapper.d.ts
4
+ type ThemeWrapperProps = {
5
+ theme?: "light" | "dark";
6
+ children: React.ReactNode;
7
+ };
8
+ /**
9
+ * Applies theme data attribute when dark mode is requested.
10
+ * Omit theme for automatic detection from parent elements.
11
+ */
12
+ declare const ThemeWrapper: React.FC<ThemeWrapperProps>;
13
+ //#endregion
14
+ export { ThemeWrapper };
15
+ //# sourceMappingURL=theme-wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-wrapper.d.ts","names":[],"sources":["../../../src/support/components/theme-wrapper.tsx"],"sourcesContent":[],"mappings":";;;KAEK,iBAAA;;EAAA,QAAA,EAEM,KAAA,CAAM,SAFK;AAStB,CAAA;;;;;cAAa,cAAc,KAAA,CAAM,GAAG"}
@@ -0,0 +1,18 @@
1
+ import { Fragment, jsx } from "react/jsx-runtime";
2
+
3
+ //#region src/support/components/theme-wrapper.tsx
4
+ /**
5
+ * Applies theme data attribute when dark mode is requested.
6
+ * Omit theme for automatic detection from parent elements.
7
+ */
8
+ const ThemeWrapper = ({ theme, children }) => {
9
+ if (theme === "dark") return /* @__PURE__ */ jsx("div", {
10
+ "data-color-scheme": "dark",
11
+ children
12
+ });
13
+ return /* @__PURE__ */ jsx(Fragment, { children });
14
+ };
15
+
16
+ //#endregion
17
+ export { ThemeWrapper };
18
+ //# sourceMappingURL=theme-wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-wrapper.js","names":["ThemeWrapper: React.FC<ThemeWrapperProps>"],"sources":["../../../src/support/components/theme-wrapper.tsx"],"sourcesContent":["import type React from \"react\";\n\ntype ThemeWrapperProps = {\n\ttheme?: \"light\" | \"dark\";\n\tchildren: React.ReactNode;\n};\n\n/**\n * Applies theme data attribute when dark mode is requested.\n * Omit theme for automatic detection from parent elements.\n */\nexport const ThemeWrapper: React.FC<ThemeWrapperProps> = ({\n\ttheme,\n\tchildren,\n}) => {\n\tif (theme === \"dark\") {\n\t\treturn <div data-color-scheme=\"dark\">{children}</div>;\n\t}\n\n\t// Light or undefined - render children directly to inherit theme from parent\n\treturn <>{children}</>;\n};\n"],"mappings":";;;;;;;AAWA,MAAaA,gBAA6C,EACzD,OACA,eACK;AACL,KAAI,UAAU,OACb,QAAO,oBAAC;EAAI,qBAAkB;EAAQ;GAAe;AAItD,QAAO,gCAAG,WAAY"}
@@ -90,7 +90,7 @@ const IdentificationTimelineTool = ({ conversationId }) => {
90
90
  successLabel
91
91
  ]);
92
92
  return /* @__PURE__ */ jsx("div", {
93
- className: "rounded border border-co-border/60 bg-co-background-100 p-4 shadow-sm",
93
+ className: "mt-6 rounded border border-co-border bg-co-background p-4",
94
94
  children: /* @__PURE__ */ jsxs("div", {
95
95
  className: "flex flex-col gap-3",
96
96
  children: [/* @__PURE__ */ jsxs("div", {
@@ -112,7 +112,7 @@ const IdentificationTimelineTool = ({ conversationId }) => {
112
112
  /* @__PURE__ */ jsx("input", {
113
113
  "aria-label": text("component.identificationTool.inputLabel"),
114
114
  autoComplete: "email",
115
- className: "h-10 w-full rounded border border-co-border/60 bg-transparent px-3 py-2 text-sm outline-none focus:border-co-primary focus:ring-2 focus:ring-co-primary/20",
115
+ className: "h-10 w-full rounded border border-co-border bg-transparent px-3 py-2 text-sm outline-none focus:border-co-primary focus:ring-2 focus:ring-co-primary/20",
116
116
  disabled: submitDisabled,
117
117
  inputMode: "email",
118
118
  onChange: (event) => setEmail(event.target.value),
@@ -1 +1 @@
1
- {"version":3,"file":"timeline-identification-tool.js","names":["IdentificationTimelineTool: React.FC<\n\tConversationTimelineToolProps\n>","payload: SendTimelineItemRequest"],"sources":["../../../src/support/components/timeline-identification-tool.tsx"],"sourcesContent":["import type { SendTimelineItemRequest } from \"@cossistant/types/api/timeline-item\";\nimport {\n\tConversationEventType,\n\tConversationTimelineType,\n\tTimelineItemVisibility,\n} from \"@cossistant/types/enums\";\nimport { type FormEventHandler, useCallback, useMemo, useState } from \"react\";\n\nimport { useVisitor } from \"../../hooks/use-visitor\";\nimport { useSupport } from \"../../provider\";\nimport { useSupportText } from \"../text\";\nimport { CoButton } from \"./button\";\nimport type { ConversationTimelineToolProps } from \"./conversation-timeline\";\n\nexport const IdentificationTimelineTool: React.FC<\n\tConversationTimelineToolProps\n> = ({ conversationId }) => {\n\tconst text = useSupportText();\n\tconst { identify, visitor } = useVisitor();\n\tconst { client } = useSupport();\n\tconst [email, setEmail] = useState(\"\");\n\tconst [status, setStatus] = useState<\n\t\t\"idle\" | \"submitting\" | \"success\" | \"error\"\n\t>(\"idle\");\n\tconst [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n\tconst isAlreadyIdentified = Boolean(visitor?.contact);\n\tconst hasSucceeded = status === \"success\" || isAlreadyIdentified;\n\n\tconst ctaLabel = text(\"component.identificationTool.cta\");\n\tconst successLabel = text(\"component.identificationTool.success\");\n\tconst description = text(\"component.identificationTool.description\");\n\tconst title = text(\"component.identificationTool.title\");\n\n\tconst submitDisabled = hasSucceeded || status === \"submitting\";\n\n\tconst handleSubmit = useCallback<FormEventHandler<HTMLFormElement>>(\n\t\tasync (event) => {\n\t\t\tevent.preventDefault();\n\n\t\t\tif (submitDisabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst trimmedEmail = email.trim();\n\t\t\tif (!trimmedEmail) {\n\t\t\t\tsetErrorMessage(text(\"component.identificationTool.validation\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetStatus(\"submitting\");\n\t\t\tsetErrorMessage(null);\n\n\t\t\ttry {\n\t\t\t\tconst identifyResult = await identify({ email: trimmedEmail });\n\n\t\t\t\tif (!identifyResult) {\n\t\t\t\t\tsetStatus(\"error\");\n\t\t\t\t\tsetErrorMessage(text(\"component.identificationTool.error\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst payload: SendTimelineItemRequest = {\n\t\t\t\t\tconversationId,\n\t\t\t\t\titem: {\n\t\t\t\t\t\ttype: ConversationTimelineType.EVENT,\n\t\t\t\t\t\ttext: text(\"component.identificationTool.eventLog\"),\n\t\t\t\t\t\ttool: null,\n\t\t\t\t\t\tparts: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"event\" as const,\n\t\t\t\t\t\t\t\teventType: ConversationEventType.VISITOR_IDENTIFIED,\n\t\t\t\t\t\t\t\tactorUserId: null,\n\t\t\t\t\t\t\t\tactorAiAgentId: null,\n\t\t\t\t\t\t\t\ttargetUserId: null,\n\t\t\t\t\t\t\t\ttargetAiAgentId: null,\n\t\t\t\t\t\t\t\tmessage: text(\"component.identificationTool.eventLog\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tvisitorId: identifyResult.visitorId,\n\t\t\t\t\t\tvisibility: TimelineItemVisibility.PUBLIC,\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tawait client.sendMessage(payload);\n\n\t\t\t\tsetStatus(\"success\");\n\t\t\t\tsetEmail(\"\");\n\n\t\t\t\tvoid client.fetchWebsite({ force: true }).catch(() => {});\n\t\t\t} catch {\n\t\t\t\tsetStatus(\"error\");\n\t\t\t\tsetErrorMessage(text(\"component.identificationTool.error\"));\n\t\t\t}\n\t\t},\n\t\t[conversationId, email, identify, client, submitDisabled, text]\n\t);\n\n\tconst helperMessage = useMemo(() => {\n\t\tif (errorMessage) {\n\t\t\treturn (\n\t\t\t\t<p className=\"text-co-destructive text-xs\" role=\"alert\">\n\t\t\t\t\t{errorMessage}\n\t\t\t\t</p>\n\t\t\t);\n\t\t}\n\n\t\tif (hasSucceeded) {\n\t\t\treturn <p className=\"text-co-primary text-xs\">{successLabel}</p>;\n\t\t}\n\n\t\treturn null;\n\t}, [errorMessage, hasSucceeded, successLabel]);\n\n\treturn (\n\t\t<div className=\"rounded border border-co-border/60 bg-co-background-100 p-4 shadow-sm\">\n\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t<h3 className=\"font-semibold text-sm\">{title}</h3>\n\t\t\t\t\t<p className=\"text-co-muted-foreground text-xs\">{description}</p>\n\t\t\t\t</div>\n\t\t\t\t{hasSucceeded ? (\n\t\t\t\t\t<div className=\"rounded-md bg-co-primary/10 px-3 py-2 text-co-primary text-sm\">\n\t\t\t\t\t\t{successLabel}\n\t\t\t\t\t</div>\n\t\t\t\t) : (\n\t\t\t\t\t<form className=\"flex gap-2\" onSubmit={handleSubmit}>\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\taria-label={text(\"component.identificationTool.inputLabel\")}\n\t\t\t\t\t\t\tautoComplete=\"email\"\n\t\t\t\t\t\t\tclassName=\"h-10 w-full rounded border border-co-border/60 bg-transparent px-3 py-2 text-sm outline-none focus:border-co-primary focus:ring-2 focus:ring-co-primary/20\"\n\t\t\t\t\t\t\tdisabled={submitDisabled}\n\t\t\t\t\t\t\tinputMode=\"email\"\n\t\t\t\t\t\t\tonChange={(event) => setEmail(event.target.value)}\n\t\t\t\t\t\t\tplaceholder={text(\n\t\t\t\t\t\t\t\t\"component.identificationTool.inputPlaceholder\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\tvalue={email}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{helperMessage}\n\t\t\t\t\t\t<CoButton className=\"h-10\" disabled={submitDisabled} type=\"submit\">\n\t\t\t\t\t\t\t{status === \"submitting\"\n\t\t\t\t\t\t\t\t? text(\"component.identificationTool.loading\")\n\t\t\t\t\t\t\t\t: ctaLabel}\n\t\t\t\t\t\t</CoButton>\n\t\t\t\t\t</form>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n\nIdentificationTimelineTool.displayName = \"IdentificationTimelineTool\";\n"],"mappings":";;;;;;;;;AAcA,MAAaA,8BAER,EAAE,qBAAqB;CAC3B,MAAM,OAAO,gBAAgB;CAC7B,MAAM,EAAE,UAAU,YAAY,YAAY;CAC1C,MAAM,EAAE,WAAW,YAAY;CAC/B,MAAM,CAAC,OAAO,YAAY,SAAS,GAAG;CACtC,MAAM,CAAC,QAAQ,aAAa,SAE1B,OAAO;CACT,MAAM,CAAC,cAAc,mBAAmB,SAAwB,KAAK;CAErE,MAAM,sBAAsB,QAAQ,SAAS,QAAQ;CACrD,MAAM,eAAe,WAAW,aAAa;CAE7C,MAAM,WAAW,KAAK,mCAAmC;CACzD,MAAM,eAAe,KAAK,uCAAuC;CACjE,MAAM,cAAc,KAAK,2CAA2C;CACpE,MAAM,QAAQ,KAAK,qCAAqC;CAExD,MAAM,iBAAiB,gBAAgB,WAAW;CAElD,MAAM,eAAe,YACpB,OAAO,UAAU;AAChB,QAAM,gBAAgB;AAEtB,MAAI,eACH;EAGD,MAAM,eAAe,MAAM,MAAM;AACjC,MAAI,CAAC,cAAc;AAClB,mBAAgB,KAAK,0CAA0C,CAAC;AAChE;;AAGD,YAAU,aAAa;AACvB,kBAAgB,KAAK;AAErB,MAAI;GACH,MAAM,iBAAiB,MAAM,SAAS,EAAE,OAAO,cAAc,CAAC;AAE9D,OAAI,CAAC,gBAAgB;AACpB,cAAU,QAAQ;AAClB,oBAAgB,KAAK,qCAAqC,CAAC;AAC3D;;GAGD,MAAMC,UAAmC;IACxC;IACA,MAAM;KACL,MAAM,yBAAyB;KAC/B,MAAM,KAAK,wCAAwC;KACnD,MAAM;KACN,OAAO,CACN;MACC,MAAM;MACN,WAAW,sBAAsB;MACjC,aAAa;MACb,gBAAgB;MAChB,cAAc;MACd,iBAAiB;MACjB,SAAS,KAAK,wCAAwC;MACtD,CACD;KACD,WAAW,eAAe;KAC1B,YAAY,uBAAuB;KACnC;IACD;AAED,SAAM,OAAO,YAAY,QAAQ;AAEjC,aAAU,UAAU;AACpB,YAAS,GAAG;AAEZ,GAAK,OAAO,aAAa,EAAE,OAAO,MAAM,CAAC,CAAC,YAAY,GAAG;UAClD;AACP,aAAU,QAAQ;AAClB,mBAAgB,KAAK,qCAAqC,CAAC;;IAG7D;EAAC;EAAgB;EAAO;EAAU;EAAQ;EAAgB;EAAK,CAC/D;CAED,MAAM,gBAAgB,cAAc;AACnC,MAAI,aACH,QACC,oBAAC;GAAE,WAAU;GAA8B,MAAK;aAC9C;IACE;AAIN,MAAI,aACH,QAAO,oBAAC;GAAE,WAAU;aAA2B;IAAiB;AAGjE,SAAO;IACL;EAAC;EAAc;EAAc;EAAa,CAAC;AAE9C,QACC,oBAAC;EAAI,WAAU;YACd,qBAAC;GAAI,WAAU;cACd,qBAAC;IAAI,WAAU;eACd,oBAAC;KAAG,WAAU;eAAyB;MAAW,EAClD,oBAAC;KAAE,WAAU;eAAoC;MAAgB;KAC5D,EACL,eACA,oBAAC;IAAI,WAAU;cACb;KACI,GAEN,qBAAC;IAAK,WAAU;IAAa,UAAU;;KACtC,oBAAC;MACA,cAAY,KAAK,0CAA0C;MAC3D,cAAa;MACb,WAAU;MACV,UAAU;MACV,WAAU;MACV,WAAW,UAAU,SAAS,MAAM,OAAO,MAAM;MACjD,aAAa,KACZ,gDACA;MACD,MAAK;MACL,OAAO;OACN;KACD;KACD,oBAAC;MAAS,WAAU;MAAO,UAAU;MAAgB,MAAK;gBACxD,WAAW,eACT,KAAK,uCAAuC,GAC5C;OACO;;KACL;IAEH;GACD;;AAIR,2BAA2B,cAAc"}
1
+ {"version":3,"file":"timeline-identification-tool.js","names":["IdentificationTimelineTool: React.FC<\n\tConversationTimelineToolProps\n>","payload: SendTimelineItemRequest"],"sources":["../../../src/support/components/timeline-identification-tool.tsx"],"sourcesContent":["import type { SendTimelineItemRequest } from \"@cossistant/types/api/timeline-item\";\nimport {\n\tConversationEventType,\n\tConversationTimelineType,\n\tTimelineItemVisibility,\n} from \"@cossistant/types/enums\";\nimport { type FormEventHandler, useCallback, useMemo, useState } from \"react\";\n\nimport { useVisitor } from \"../../hooks/use-visitor\";\nimport { useSupport } from \"../../provider\";\nimport { useSupportText } from \"../text\";\nimport { CoButton } from \"./button\";\nimport type { ConversationTimelineToolProps } from \"./conversation-timeline\";\n\nexport const IdentificationTimelineTool: React.FC<\n\tConversationTimelineToolProps\n> = ({ conversationId }) => {\n\tconst text = useSupportText();\n\tconst { identify, visitor } = useVisitor();\n\tconst { client } = useSupport();\n\tconst [email, setEmail] = useState(\"\");\n\tconst [status, setStatus] = useState<\n\t\t\"idle\" | \"submitting\" | \"success\" | \"error\"\n\t>(\"idle\");\n\tconst [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n\tconst isAlreadyIdentified = Boolean(visitor?.contact);\n\tconst hasSucceeded = status === \"success\" || isAlreadyIdentified;\n\n\tconst ctaLabel = text(\"component.identificationTool.cta\");\n\tconst successLabel = text(\"component.identificationTool.success\");\n\tconst description = text(\"component.identificationTool.description\");\n\tconst title = text(\"component.identificationTool.title\");\n\n\tconst submitDisabled = hasSucceeded || status === \"submitting\";\n\n\tconst handleSubmit = useCallback<FormEventHandler<HTMLFormElement>>(\n\t\tasync (event) => {\n\t\t\tevent.preventDefault();\n\n\t\t\tif (submitDisabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst trimmedEmail = email.trim();\n\t\t\tif (!trimmedEmail) {\n\t\t\t\tsetErrorMessage(text(\"component.identificationTool.validation\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetStatus(\"submitting\");\n\t\t\tsetErrorMessage(null);\n\n\t\t\ttry {\n\t\t\t\tconst identifyResult = await identify({ email: trimmedEmail });\n\n\t\t\t\tif (!identifyResult) {\n\t\t\t\t\tsetStatus(\"error\");\n\t\t\t\t\tsetErrorMessage(text(\"component.identificationTool.error\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst payload: SendTimelineItemRequest = {\n\t\t\t\t\tconversationId,\n\t\t\t\t\titem: {\n\t\t\t\t\t\ttype: ConversationTimelineType.EVENT,\n\t\t\t\t\t\ttext: text(\"component.identificationTool.eventLog\"),\n\t\t\t\t\t\ttool: null,\n\t\t\t\t\t\tparts: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"event\" as const,\n\t\t\t\t\t\t\t\teventType: ConversationEventType.VISITOR_IDENTIFIED,\n\t\t\t\t\t\t\t\tactorUserId: null,\n\t\t\t\t\t\t\t\tactorAiAgentId: null,\n\t\t\t\t\t\t\t\ttargetUserId: null,\n\t\t\t\t\t\t\t\ttargetAiAgentId: null,\n\t\t\t\t\t\t\t\tmessage: text(\"component.identificationTool.eventLog\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tvisitorId: identifyResult.visitorId,\n\t\t\t\t\t\tvisibility: TimelineItemVisibility.PUBLIC,\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tawait client.sendMessage(payload);\n\n\t\t\t\tsetStatus(\"success\");\n\t\t\t\tsetEmail(\"\");\n\n\t\t\t\tvoid client.fetchWebsite({ force: true }).catch(() => {});\n\t\t\t} catch {\n\t\t\t\tsetStatus(\"error\");\n\t\t\t\tsetErrorMessage(text(\"component.identificationTool.error\"));\n\t\t\t}\n\t\t},\n\t\t[conversationId, email, identify, client, submitDisabled, text]\n\t);\n\n\tconst helperMessage = useMemo(() => {\n\t\tif (errorMessage) {\n\t\t\treturn (\n\t\t\t\t<p className=\"text-co-destructive text-xs\" role=\"alert\">\n\t\t\t\t\t{errorMessage}\n\t\t\t\t</p>\n\t\t\t);\n\t\t}\n\n\t\tif (hasSucceeded) {\n\t\t\treturn <p className=\"text-co-primary text-xs\">{successLabel}</p>;\n\t\t}\n\n\t\treturn null;\n\t}, [errorMessage, hasSucceeded, successLabel]);\n\n\treturn (\n\t\t<div className=\"mt-6 rounded border border-co-border bg-co-background p-4\">\n\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t<h3 className=\"font-semibold text-sm\">{title}</h3>\n\t\t\t\t\t<p className=\"text-co-muted-foreground text-xs\">{description}</p>\n\t\t\t\t</div>\n\t\t\t\t{hasSucceeded ? (\n\t\t\t\t\t<div className=\"rounded-md bg-co-primary/10 px-3 py-2 text-co-primary text-sm\">\n\t\t\t\t\t\t{successLabel}\n\t\t\t\t\t</div>\n\t\t\t\t) : (\n\t\t\t\t\t<form className=\"flex gap-2\" onSubmit={handleSubmit}>\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\taria-label={text(\"component.identificationTool.inputLabel\")}\n\t\t\t\t\t\t\tautoComplete=\"email\"\n\t\t\t\t\t\t\tclassName=\"h-10 w-full rounded border border-co-border bg-transparent px-3 py-2 text-sm outline-none focus:border-co-primary focus:ring-2 focus:ring-co-primary/20\"\n\t\t\t\t\t\t\tdisabled={submitDisabled}\n\t\t\t\t\t\t\tinputMode=\"email\"\n\t\t\t\t\t\t\tonChange={(event) => setEmail(event.target.value)}\n\t\t\t\t\t\t\tplaceholder={text(\n\t\t\t\t\t\t\t\t\"component.identificationTool.inputPlaceholder\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\tvalue={email}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{helperMessage}\n\t\t\t\t\t\t<CoButton className=\"h-10\" disabled={submitDisabled} type=\"submit\">\n\t\t\t\t\t\t\t{status === \"submitting\"\n\t\t\t\t\t\t\t\t? text(\"component.identificationTool.loading\")\n\t\t\t\t\t\t\t\t: ctaLabel}\n\t\t\t\t\t\t</CoButton>\n\t\t\t\t\t</form>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n\nIdentificationTimelineTool.displayName = \"IdentificationTimelineTool\";\n"],"mappings":";;;;;;;;;AAcA,MAAaA,8BAER,EAAE,qBAAqB;CAC3B,MAAM,OAAO,gBAAgB;CAC7B,MAAM,EAAE,UAAU,YAAY,YAAY;CAC1C,MAAM,EAAE,WAAW,YAAY;CAC/B,MAAM,CAAC,OAAO,YAAY,SAAS,GAAG;CACtC,MAAM,CAAC,QAAQ,aAAa,SAE1B,OAAO;CACT,MAAM,CAAC,cAAc,mBAAmB,SAAwB,KAAK;CAErE,MAAM,sBAAsB,QAAQ,SAAS,QAAQ;CACrD,MAAM,eAAe,WAAW,aAAa;CAE7C,MAAM,WAAW,KAAK,mCAAmC;CACzD,MAAM,eAAe,KAAK,uCAAuC;CACjE,MAAM,cAAc,KAAK,2CAA2C;CACpE,MAAM,QAAQ,KAAK,qCAAqC;CAExD,MAAM,iBAAiB,gBAAgB,WAAW;CAElD,MAAM,eAAe,YACpB,OAAO,UAAU;AAChB,QAAM,gBAAgB;AAEtB,MAAI,eACH;EAGD,MAAM,eAAe,MAAM,MAAM;AACjC,MAAI,CAAC,cAAc;AAClB,mBAAgB,KAAK,0CAA0C,CAAC;AAChE;;AAGD,YAAU,aAAa;AACvB,kBAAgB,KAAK;AAErB,MAAI;GACH,MAAM,iBAAiB,MAAM,SAAS,EAAE,OAAO,cAAc,CAAC;AAE9D,OAAI,CAAC,gBAAgB;AACpB,cAAU,QAAQ;AAClB,oBAAgB,KAAK,qCAAqC,CAAC;AAC3D;;GAGD,MAAMC,UAAmC;IACxC;IACA,MAAM;KACL,MAAM,yBAAyB;KAC/B,MAAM,KAAK,wCAAwC;KACnD,MAAM;KACN,OAAO,CACN;MACC,MAAM;MACN,WAAW,sBAAsB;MACjC,aAAa;MACb,gBAAgB;MAChB,cAAc;MACd,iBAAiB;MACjB,SAAS,KAAK,wCAAwC;MACtD,CACD;KACD,WAAW,eAAe;KAC1B,YAAY,uBAAuB;KACnC;IACD;AAED,SAAM,OAAO,YAAY,QAAQ;AAEjC,aAAU,UAAU;AACpB,YAAS,GAAG;AAEZ,GAAK,OAAO,aAAa,EAAE,OAAO,MAAM,CAAC,CAAC,YAAY,GAAG;UAClD;AACP,aAAU,QAAQ;AAClB,mBAAgB,KAAK,qCAAqC,CAAC;;IAG7D;EAAC;EAAgB;EAAO;EAAU;EAAQ;EAAgB;EAAK,CAC/D;CAED,MAAM,gBAAgB,cAAc;AACnC,MAAI,aACH,QACC,oBAAC;GAAE,WAAU;GAA8B,MAAK;aAC9C;IACE;AAIN,MAAI,aACH,QAAO,oBAAC;GAAE,WAAU;aAA2B;IAAiB;AAGjE,SAAO;IACL;EAAC;EAAc;EAAc;EAAa,CAAC;AAE9C,QACC,oBAAC;EAAI,WAAU;YACd,qBAAC;GAAI,WAAU;cACd,qBAAC;IAAI,WAAU;eACd,oBAAC;KAAG,WAAU;eAAyB;MAAW,EAClD,oBAAC;KAAE,WAAU;eAAoC;MAAgB;KAC5D,EACL,eACA,oBAAC;IAAI,WAAU;cACb;KACI,GAEN,qBAAC;IAAK,WAAU;IAAa,UAAU;;KACtC,oBAAC;MACA,cAAY,KAAK,0CAA0C;MAC3D,cAAa;MACb,WAAU;MACV,UAAU;MACV,WAAU;MACV,WAAW,UAAU,SAAS,MAAM,OAAO,MAAM;MACjD,aAAa,KACZ,gDACA;MACD,MAAK;MACL,OAAO;OACN;KACD;KACD,oBAAC;MAAS,WAAU;MAAO,UAAU;MAAgB,MAAK;gBACxD,WAAW,eACT,KAAK,uCAAuC,GAC5C;OACO;;KACL;IAEH;GACD;;AAIR,2BAA2B,cAAc"}
@@ -17,7 +17,7 @@ const Watermark = ({ className }) => {
17
17
  return url.toString();
18
18
  }, [website]);
19
19
  return /* @__PURE__ */ jsxs("a", {
20
- className: cn("flex items-center gap-1.5 font-medium font-mono text-co-primary hover:text-co-blue", className),
20
+ className: cn("group/watermark flex items-center gap-1.5 font-medium text-co-primary/80 hover:text-co-blue", className),
21
21
  href: cossistantUrl,
22
22
  rel: "noopener noreferrer",
23
23
  target: "_blank",
@@ -25,7 +25,7 @@ const Watermark = ({ className }) => {
25
25
  as: "span",
26
26
  className: "text-co-muted-foreground text-xs",
27
27
  textKey: "common.brand.watermark"
28
- }), /* @__PURE__ */ jsx(CossistantLogo, { className: "h-3" })]
28
+ }), /* @__PURE__ */ jsx(CossistantLogo, { className: "h-3 transition-transform duration-200 group-focus-within/watermark:rotate-5 group-hover/watermark:scale-105" })]
29
29
  });
30
30
  };
31
31
 
@@ -1 +1 @@
1
- {"version":3,"file":"watermark.js","names":["Watermark: React.FC<WatermarkProps>"],"sources":["../../../src/support/components/watermark.tsx"],"sourcesContent":["import { useSupport } from \"@cossistant/react\";\nimport { useMemo } from \"react\";\nimport { Text } from \"../text\";\nimport { cn } from \"../utils\";\nimport { CossistantLogo } from \"./cossistant-branding\";\n\nexport type WatermarkProps = {\n\tclassName?: string;\n};\n\nexport const Watermark: React.FC<WatermarkProps> = ({ className }) => {\n\tconst { website } = useSupport();\n\n\tconst cossistantUrl = useMemo(() => {\n\t\tif (!website) {\n\t\t\treturn \"https://cossistant.com\";\n\t\t}\n\n\t\tconst url = new URL(\"https://cossistant.com\");\n\n\t\turl.searchParams.set(\"ref\", \"chatbox\");\n\t\turl.searchParams.set(\"domain\", website.domain);\n\t\turl.searchParams.set(\"name\", website.name);\n\n\t\treturn url.toString();\n\t}, [website]);\n\n\treturn (\n\t\t<a\n\t\t\tclassName={cn(\n\t\t\t\t\"flex items-center gap-1.5 font-medium font-mono text-co-primary hover:text-co-blue\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\thref={cossistantUrl}\n\t\t\trel=\"noopener noreferrer\"\n\t\t\ttarget=\"_blank\"\n\t\t>\n\t\t\t<Text\n\t\t\t\tas=\"span\"\n\t\t\t\tclassName=\"text-co-muted-foreground text-xs\"\n\t\t\t\ttextKey=\"common.brand.watermark\"\n\t\t\t/>\n\t\t\t<CossistantLogo className=\"h-3\" />\n\t\t</a>\n\t);\n};\n"],"mappings":";;;;;;;;AAUA,MAAaA,aAAuC,EAAE,gBAAgB;CACrE,MAAM,EAAE,YAAY,YAAY;CAEhC,MAAM,gBAAgB,cAAc;AACnC,MAAI,CAAC,QACJ,QAAO;EAGR,MAAM,MAAM,IAAI,IAAI,yBAAyB;AAE7C,MAAI,aAAa,IAAI,OAAO,UAAU;AACtC,MAAI,aAAa,IAAI,UAAU,QAAQ,OAAO;AAC9C,MAAI,aAAa,IAAI,QAAQ,QAAQ,KAAK;AAE1C,SAAO,IAAI,UAAU;IACnB,CAAC,QAAQ,CAAC;AAEb,QACC,qBAAC;EACA,WAAW,GACV,sFACA,UACA;EACD,MAAM;EACN,KAAI;EACJ,QAAO;aAEP,oBAAC;GACA,IAAG;GACH,WAAU;GACV,SAAQ;IACP,EACF,oBAAC,kBAAe,WAAU,QAAQ;GAC/B"}
1
+ {"version":3,"file":"watermark.js","names":["Watermark: React.FC<WatermarkProps>"],"sources":["../../../src/support/components/watermark.tsx"],"sourcesContent":["import { useSupport } from \"@cossistant/react\";\nimport { useMemo } from \"react\";\nimport { Text } from \"../text\";\nimport { cn } from \"../utils\";\nimport { CossistantLogo } from \"./cossistant-branding\";\n\nexport type WatermarkProps = {\n\tclassName?: string;\n};\n\nexport const Watermark: React.FC<WatermarkProps> = ({ className }) => {\n\tconst { website } = useSupport();\n\n\tconst cossistantUrl = useMemo(() => {\n\t\tif (!website) {\n\t\t\treturn \"https://cossistant.com\";\n\t\t}\n\n\t\tconst url = new URL(\"https://cossistant.com\");\n\n\t\turl.searchParams.set(\"ref\", \"chatbox\");\n\t\turl.searchParams.set(\"domain\", website.domain);\n\t\turl.searchParams.set(\"name\", website.name);\n\n\t\treturn url.toString();\n\t}, [website]);\n\n\treturn (\n\t\t<a\n\t\t\tclassName={cn(\n\t\t\t\t\"group/watermark flex items-center gap-1.5 font-medium text-co-primary/80 hover:text-co-blue\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\thref={cossistantUrl}\n\t\t\trel=\"noopener noreferrer\"\n\t\t\ttarget=\"_blank\"\n\t\t>\n\t\t\t<Text\n\t\t\t\tas=\"span\"\n\t\t\t\tclassName=\"text-co-muted-foreground text-xs\"\n\t\t\t\ttextKey=\"common.brand.watermark\"\n\t\t\t/>\n\t\t\t<CossistantLogo className=\"h-3 transition-transform duration-200 group-focus-within/watermark:rotate-5 group-hover/watermark:scale-105\" />\n\t\t</a>\n\t);\n};\n"],"mappings":";;;;;;;;AAUA,MAAaA,aAAuC,EAAE,gBAAgB;CACrE,MAAM,EAAE,YAAY,YAAY;CAEhC,MAAM,gBAAgB,cAAc;AACnC,MAAI,CAAC,QACJ,QAAO;EAGR,MAAM,MAAM,IAAI,IAAI,yBAAyB;AAE7C,MAAI,aAAa,IAAI,OAAO,UAAU;AACtC,MAAI,aAAa,IAAI,UAAU,QAAQ,OAAO;AAC9C,MAAI,aAAa,IAAI,QAAQ,QAAQ,KAAK;AAE1C,SAAO,IAAI,UAAU;IACnB,CAAC,QAAQ,CAAC;AAEb,QACC,qBAAC;EACA,WAAW,GACV,+FACA,UACA;EACD,MAAM;EACN,KAAI;EACJ,QAAO;aAEP,oBAAC;GACA,IAAG;GACH,WAAU;GACV,SAAQ;IACP,EACF,oBAAC,kBAAe,WAAU,gHAAgH;GACvI"}
@@ -1,9 +1,15 @@
1
1
  import { SupportLocale, SupportTextContentOverrides } from "./text/locales/keys.js";
2
+ import { Page, PageProps } from "../primitives/page.js";
3
+ import "../primitives/index.js";
2
4
  import { Text, useSupportText } from "./text/index.js";
5
+ import { BubbleSlotProps, ContainerSlotProps, RouterSlotProps } from "./types.js";
6
+ import { CoButton } from "./components/button.js";
7
+ import { Header } from "./components/header.js";
3
8
  import { WebSocketContextValue, WebSocketProvider, useWebSocket } from "./context/websocket.js";
4
9
  import { useSupportConfig, useSupportNavigation, useSupportStore } from "./store/support-store.js";
5
10
  import "./store/index.js";
6
- import { ReactElement } from "react";
11
+ import React, { ReactElement } from "react";
12
+ import { DefaultRoutes, NavigationState, RouteRegistry, SupportPage } from "@cossistant/core";
7
13
  import { DefaultMessage } from "@cossistant/types";
8
14
 
9
15
  //#region src/support/index.d.ts
@@ -17,11 +23,31 @@ type SupportProps<Locale extends string = SupportLocale> = {
17
23
  defaultOpen?: boolean;
18
24
  locale?: Locale;
19
25
  content?: SupportTextContentOverrides<Locale>;
26
+ theme?: "light" | "dark";
27
+ slots?: {
28
+ bubble?: React.ComponentType<BubbleSlotProps>;
29
+ container?: React.ComponentType<ContainerSlotProps>;
30
+ router?: React.ComponentType<RouterSlotProps>;
31
+ };
32
+ classNames?: {
33
+ root?: string;
34
+ bubble?: string;
35
+ container?: string;
36
+ };
37
+ children?: React.ReactNode;
20
38
  };
21
39
  /**
22
- * Orchestrates the end-user support experience by nesting realtime and
23
- * content providers. Renders nothing until website data is available to avoid
24
- * flashing incomplete UI.
40
+ * Complete support widget with chat, routing, and real-time features.
41
+ *
42
+ * @example
43
+ * // Zero config
44
+ * <Support />
45
+ *
46
+ * @example
47
+ * // With customization
48
+ * <Support theme="dark" classNames={{ bubble: "bg-purple-600" }}>
49
+ * <Page name="FAQ" component={FAQPage} />
50
+ * </Support>
25
51
  */
26
52
  declare function Support<Locale extends string = SupportLocale>({
27
53
  className,
@@ -32,8 +58,12 @@ declare function Support<Locale extends string = SupportLocale>({
32
58
  defaultMessages,
33
59
  defaultOpen,
34
60
  locale,
35
- content
61
+ content,
62
+ theme,
63
+ slots,
64
+ classNames,
65
+ children
36
66
  }: SupportProps<Locale>): ReactElement | null;
37
67
  //#endregion
38
- export { Support, Support as default, type SupportLocale, SupportProps, type SupportTextContentOverrides, Text, type WebSocketContextValue, WebSocketProvider, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useWebSocket };
68
+ export { type BubbleSlotProps, CoButton as Button, type ContainerSlotProps, type DefaultRoutes, Header, type NavigationState, Page, type PageProps, type RouteRegistry, type RouterSlotProps, Support, Support as default, type SupportLocale, type SupportPage, SupportProps, type SupportTextContentOverrides, Text, type WebSocketContextValue, WebSocketProvider, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useWebSocket };
39
69
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/support/index.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;KAYY,qCAAqC;;;;;EAArC,YAAA,CAAA,EAAY,MAAA,EAAA;EAAyB,eAAA,CAAA,EAM9B,cAN8B,EAAA;EAM9B,WAAA,CAAA,EAAA,OAAA;EAET,MAAA,CAAA,EAAA,MAAA;EAC6B,OAAA,CAAA,EAA5B,2BAA4B,CAAA,MAAA,CAAA;CAA5B;;AASX;;;;AAGC,iBAHe,OAGf,CAAA,eAAA,MAAA,GAH+C,aAG/C,CAAA,CAAA;EAAA,SAAA;EAAA,QAAA;EAAA,KAAA;EAAA,WAAA;EAAA,YAAA;EAAA,eAAA;EAAA,WAAA;EAAA,MAAA;EAAA;AAAA,CAAA,EAOE,YAPF,CAOe,MAPf,CAAA,CAAA,EAOyB,YAPzB,GAAA,IAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/support/index.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;KAmBY,qCAAqC;;;;;;oBAO9B;;WAET;YACC,4BAA4B;EAV3B,KAAA,CAAA,EAAA,OAAY,GAAA,MAAA;EAAyB,KAAA,CAAA,EAAA;IAO9B,MAAA,CAAA,EAUR,KAAA,CAAM,aAVE,CAUY,eAVZ,CAAA;IAET,SAAA,CAAA,EASI,KAAA,CAAM,aATV,CASwB,kBATxB,CAAA;IAC6B,MAAA,CAAA,EAS5B,KAAA,CAAM,aATsB,CASR,eATQ,CAAA;EAA5B,CAAA;EAOoB,UAAA,CAAA,EAAA;IAAd,IAAA,CAAA,EAAA,MAAA;IACiB,MAAA,CAAA,EAAA,MAAA;IAAd,SAAA,CAAA,EAAA,MAAA;EACW,CAAA;EAApB,QAAM,CAAA,EAWL,KAAA,CAAM,SAXD;CAWL;;AAgBZ;;;;;;;;;;;;AAWC,iBAXe,OAWf,CAAA,eAAA,MAAA,GAX+C,aAW/C,CAAA,CAAA;EAAA,SAAA;EAAA,QAAA;EAAA,KAAA;EAAA,WAAA;EAAA,YAAA;EAAA,eAAA;EAAA,WAAA;EAAA,MAAA;EAAA,OAAA;EAAA,KAAA;EAAA,KAAA;EAAA,UAAA;EAAA;AAAA,CAAA,EAGE,YAHF,CAGe,MAHf,CAAA,CAAA,EAGyB,YAHzB,GAAA,IAAA"}
package/support/index.js CHANGED
@@ -1,43 +1,66 @@
1
1
  import "./support.js";
2
- import { SupportRealtimeProvider } from "../realtime/support-provider.js";
3
2
  import { SupportConfig } from "../support-config.js";
3
+ import { PageRegistryProvider } from "../primitives/page-registry.js";
4
+ import { Page } from "../primitives/page.js";
4
5
  import { initializeSupportStore, useSupportConfig, useSupportNavigation, useSupportStore } from "./store/support-store.js";
6
+ import { SupportRealtimeProvider } from "../realtime/support-provider.js";
7
+ import { CoButton } from "./components/button.js";
8
+ import { Header } from "./components/header.js";
5
9
  import { SupportTextProvider, Text, useSupportText } from "./text/index.js";
6
10
  import { SupportContent } from "./components/support-content.js";
11
+ import { ThemeWrapper } from "./components/theme-wrapper.js";
7
12
  import { WebSocketProvider, useWebSocket } from "./context/websocket.js";
8
13
  import { useSupport } from "../provider.js";
9
14
  import React from "react";
10
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
11
16
 
12
17
  //#region src/support/index.tsx
13
18
  /**
14
- * Orchestrates the end-user support experience by nesting realtime and
15
- * content providers. Renders nothing until website data is available to avoid
16
- * flashing incomplete UI.
19
+ * Complete support widget with chat, routing, and real-time features.
20
+ *
21
+ * @example
22
+ * // Zero config
23
+ * <Support />
24
+ *
25
+ * @example
26
+ * // With customization
27
+ * <Support theme="dark" classNames={{ bubble: "bg-purple-600" }}>
28
+ * <Page name="FAQ" component={FAQPage} />
29
+ * </Support>
17
30
  */
18
- function Support({ className, position = "bottom", align = "right", positioning = "fixed", quickOptions, defaultMessages, defaultOpen, locale, content }) {
31
+ function Support({ className, position = "bottom", align = "right", positioning = "fixed", quickOptions, defaultMessages, defaultOpen, locale, content, theme, slots, classNames, children }) {
19
32
  const { website } = useSupport();
20
33
  const isVisitorBlocked = website?.visitor?.isBlocked ?? false;
21
34
  React.useEffect(() => {
22
35
  if (defaultOpen !== void 0) initializeSupportStore({ defaultOpen });
23
36
  }, [defaultOpen]);
24
37
  if (!website || isVisitorBlocked) return null;
25
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SupportRealtimeProvider, { children: /* @__PURE__ */ jsx(SupportTextProvider, {
26
- content,
27
- locale,
28
- children: /* @__PURE__ */ jsx(SupportContent, {
29
- align,
30
- className,
31
- position,
32
- positioning
33
- })
34
- }) }), /* @__PURE__ */ jsx(SupportConfig, {
35
- defaultMessages,
36
- quickOptions
37
- })] });
38
+ return /* @__PURE__ */ jsx(ThemeWrapper, {
39
+ theme,
40
+ children: /* @__PURE__ */ jsxs(PageRegistryProvider, { children: [
41
+ children,
42
+ /* @__PURE__ */ jsx(SupportRealtimeProvider, { children: /* @__PURE__ */ jsx(SupportTextProvider, {
43
+ content,
44
+ locale,
45
+ children: /* @__PURE__ */ jsx(SupportContent, {
46
+ align,
47
+ className,
48
+ classNames,
49
+ position,
50
+ positioning,
51
+ slots,
52
+ children
53
+ })
54
+ }) }),
55
+ /* @__PURE__ */ jsx(SupportConfig, {
56
+ defaultMessages,
57
+ quickOptions
58
+ })
59
+ ] })
60
+ });
38
61
  }
39
62
  var support_default = Support;
40
63
 
41
64
  //#endregion
42
- export { Support, Text, WebSocketProvider, support_default as default, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useWebSocket };
65
+ export { CoButton as Button, Header, Page, Support, Text, WebSocketProvider, support_default as default, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useWebSocket };
43
66
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/support/index.tsx"],"sourcesContent":["import \"./support.css\";\n\nimport type { DefaultMessage } from \"@cossistant/types\";\nimport React, { type ReactElement } from \"react\";\nimport { useSupport } from \"../provider\";\nimport { SupportRealtimeProvider } from \"../realtime\";\nimport { SupportConfig } from \"../support-config\";\nimport { SupportContent } from \"./components/support-content\";\nimport { initializeSupportStore } from \"./store/support-store\";\nimport type { SupportLocale, SupportTextContentOverrides } from \"./text\";\nimport { SupportTextProvider } from \"./text\";\n\nexport type SupportProps<Locale extends string = SupportLocale> = {\n\tclassName?: string;\n\tposition?: \"top\" | \"bottom\";\n\talign?: \"right\" | \"left\";\n\tpositioning?: \"fixed\" | \"absolute\";\n\tquickOptions?: string[];\n\tdefaultMessages?: DefaultMessage[];\n\tdefaultOpen?: boolean;\n\tlocale?: Locale;\n\tcontent?: SupportTextContentOverrides<Locale>;\n};\n\n// Internal component that needs the conversation context\n/**\n * Orchestrates the end-user support experience by nesting realtime and\n * content providers. Renders nothing until website data is available to avoid\n * flashing incomplete UI.\n */\nexport function Support<Locale extends string = SupportLocale>({\n\tclassName,\n\tposition = \"bottom\",\n\talign = \"right\",\n\tpositioning = \"fixed\",\n\tquickOptions,\n\tdefaultMessages,\n\tdefaultOpen,\n\tlocale,\n\tcontent,\n}: SupportProps<Locale>): ReactElement | null {\n\tconst { website } = useSupport();\n\tconst isVisitorBlocked = website?.visitor?.isBlocked ?? false;\n\n\t// Initialize support store with defaultOpen when component mounts or prop changes\n\tReact.useEffect(() => {\n\t\tif (defaultOpen !== undefined) {\n\t\t\tinitializeSupportStore({ defaultOpen });\n\t\t}\n\t}, [defaultOpen]);\n\n\tif (!website || isVisitorBlocked) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<SupportRealtimeProvider>\n\t\t\t\t<SupportTextProvider content={content} locale={locale}>\n\t\t\t\t\t<SupportContent\n\t\t\t\t\t\talign={align}\n\t\t\t\t\t\tclassName={className}\n\t\t\t\t\t\tposition={position}\n\t\t\t\t\t\tpositioning={positioning}\n\t\t\t\t\t/>\n\t\t\t\t</SupportTextProvider>\n\t\t\t</SupportRealtimeProvider>\n\t\t\t<SupportConfig\n\t\t\t\tdefaultMessages={defaultMessages}\n\t\t\t\tquickOptions={quickOptions}\n\t\t\t/>\n\t\t</>\n\t);\n}\n\nexport default Support;\n\nexport type { WebSocketContextValue } from \"./context/websocket\";\nexport { useWebSocket, WebSocketProvider } from \"./context/websocket\";\n// Export the store for direct access if needed\nexport {\n\tuseSupportConfig,\n\tuseSupportNavigation,\n\tuseSupportStore,\n} from \"./store\";\nexport type { SupportLocale, SupportTextContentOverrides } from \"./text\";\nexport { Text, useSupportText } from \"./text\";\n"],"mappings":";;;;;;;;;;;;;;;;;AA8BA,SAAgB,QAA+C,EAC9D,WACA,WAAW,UACX,QAAQ,SACR,cAAc,SACd,cACA,iBACA,aACA,QACA,WAC6C;CAC7C,MAAM,EAAE,YAAY,YAAY;CAChC,MAAM,mBAAmB,SAAS,SAAS,aAAa;AAGxD,OAAM,gBAAgB;AACrB,MAAI,gBAAgB,OACnB,wBAAuB,EAAE,aAAa,CAAC;IAEtC,CAAC,YAAY,CAAC;AAEjB,KAAI,CAAC,WAAW,iBACf,QAAO;AAGR,QACC,4CACC,oBAAC,qCACA,oBAAC;EAA6B;EAAiB;YAC9C,oBAAC;GACO;GACI;GACD;GACG;IACZ;GACmB,GACG,EAC1B,oBAAC;EACiB;EACH;GACb,IACA;;AAIL,sBAAe"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/support/index.tsx"],"sourcesContent":["import \"./support.css\";\n\nimport type { DefaultMessage } from \"@cossistant/types\";\nimport React, { type ReactElement } from \"react\";\nimport { PageRegistryProvider } from \"../primitives\";\nimport { useSupport } from \"../provider\";\nimport { SupportRealtimeProvider } from \"../realtime\";\nimport { SupportConfig } from \"../support-config\";\nimport { SupportContent } from \"./components/support-content\";\nimport { ThemeWrapper } from \"./components/theme-wrapper\";\nimport { initializeSupportStore } from \"./store/support-store\";\nimport type { SupportLocale, SupportTextContentOverrides } from \"./text\";\nimport { SupportTextProvider } from \"./text\";\nimport type {\n\tBubbleSlotProps,\n\tContainerSlotProps,\n\tRouterSlotProps,\n} from \"./types\";\n\nexport type SupportProps<Locale extends string = SupportLocale> = {\n\t// Existing props\n\tclassName?: string;\n\tposition?: \"top\" | \"bottom\";\n\talign?: \"right\" | \"left\";\n\tpositioning?: \"fixed\" | \"absolute\";\n\tquickOptions?: string[];\n\tdefaultMessages?: DefaultMessage[];\n\tdefaultOpen?: boolean;\n\tlocale?: Locale;\n\tcontent?: SupportTextContentOverrides<Locale>;\n\n\t// NEW: Theme control\n\ttheme?: \"light\" | \"dark\";\n\n\t// NEW: Slot customization\n\tslots?: {\n\t\tbubble?: React.ComponentType<BubbleSlotProps>;\n\t\tcontainer?: React.ComponentType<ContainerSlotProps>;\n\t\trouter?: React.ComponentType<RouterSlotProps>;\n\t};\n\n\t// NEW: Granular className overrides\n\tclassNames?: {\n\t\troot?: string;\n\t\tbubble?: string;\n\t\tcontainer?: string;\n\t};\n\n\t// NEW: Allow declarative children (Page components)\n\tchildren?: React.ReactNode;\n};\n\n/**\n * Complete support widget with chat, routing, and real-time features.\n *\n * @example\n * // Zero config\n * <Support />\n *\n * @example\n * // With customization\n * <Support theme=\"dark\" classNames={{ bubble: \"bg-purple-600\" }}>\n * <Page name=\"FAQ\" component={FAQPage} />\n * </Support>\n */\nexport function Support<Locale extends string = SupportLocale>({\n\tclassName,\n\tposition = \"bottom\",\n\talign = \"right\",\n\tpositioning = \"fixed\",\n\tquickOptions,\n\tdefaultMessages,\n\tdefaultOpen,\n\tlocale,\n\tcontent,\n\ttheme,\n\tslots,\n\tclassNames,\n\tchildren,\n}: SupportProps<Locale>): ReactElement | null {\n\tconst { website } = useSupport();\n\tconst isVisitorBlocked = website?.visitor?.isBlocked ?? false;\n\n\t// Initialize support store with defaultOpen when component mounts or prop changes\n\tReact.useEffect(() => {\n\t\tif (defaultOpen !== undefined) {\n\t\t\tinitializeSupportStore({ defaultOpen });\n\t\t}\n\t}, [defaultOpen]);\n\n\tif (!website || isVisitorBlocked) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<ThemeWrapper theme={theme}>\n\t\t\t<PageRegistryProvider>\n\t\t\t\t{children}\n\t\t\t\t<SupportRealtimeProvider>\n\t\t\t\t\t<SupportTextProvider content={content} locale={locale}>\n\t\t\t\t\t\t<SupportContent\n\t\t\t\t\t\t\talign={align}\n\t\t\t\t\t\t\tclassName={className}\n\t\t\t\t\t\t\tclassNames={classNames}\n\t\t\t\t\t\t\tposition={position}\n\t\t\t\t\t\t\tpositioning={positioning}\n\t\t\t\t\t\t\tslots={slots}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{children}\n\t\t\t\t\t\t</SupportContent>\n\t\t\t\t\t</SupportTextProvider>\n\t\t\t\t</SupportRealtimeProvider>\n\t\t\t\t<SupportConfig\n\t\t\t\t\tdefaultMessages={defaultMessages}\n\t\t\t\t\tquickOptions={quickOptions}\n\t\t\t\t/>\n\t\t\t</PageRegistryProvider>\n\t\t</ThemeWrapper>\n\t);\n}\n\nexport default Support;\n\n// Type exports from core\nexport type {\n\tDefaultRoutes,\n\tNavigationState,\n\tRouteRegistry,\n\tSupportPage,\n} from \"@cossistant/core\";\nexport type { PageProps } from \"../primitives\";\n// Page component for declarative routing (re-exported from primitives)\nexport { Page } from \"../primitives\";\nexport { CoButton as Button } from \"./components/button\";\n// UI components for building custom pages\nexport { Header } from \"./components/header\";\n// WebSocket context\nexport type { WebSocketContextValue } from \"./context/websocket\";\nexport { useWebSocket, WebSocketProvider } from \"./context/websocket\";\n// Navigation hooks and store\nexport {\n\tuseSupportConfig,\n\tuseSupportNavigation,\n\tuseSupportStore,\n} from \"./store\";\n// Text and localization\nexport type { SupportLocale, SupportTextContentOverrides } from \"./text\";\nexport { Text, useSupportText } from \"./text\";\n\n// Slot prop types\nexport type {\n\tBubbleSlotProps,\n\tContainerSlotProps,\n\tRouterSlotProps,\n} from \"./types\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiEA,SAAgB,QAA+C,EAC9D,WACA,WAAW,UACX,QAAQ,SACR,cAAc,SACd,cACA,iBACA,aACA,QACA,SACA,OACA,OACA,YACA,YAC6C;CAC7C,MAAM,EAAE,YAAY,YAAY;CAChC,MAAM,mBAAmB,SAAS,SAAS,aAAa;AAGxD,OAAM,gBAAgB;AACrB,MAAI,gBAAgB,OACnB,wBAAuB,EAAE,aAAa,CAAC;IAEtC,CAAC,YAAY,CAAC;AAEjB,KAAI,CAAC,WAAW,iBACf,QAAO;AAGR,QACC,oBAAC;EAAoB;YACpB,qBAAC;GACC;GACD,oBAAC,qCACA,oBAAC;IAA6B;IAAiB;cAC9C,oBAAC;KACO;KACI;KACC;KACF;KACG;KACN;KAEN;MACe;KACI,GACG;GAC1B,oBAAC;IACiB;IACH;KACb;MACoB;GACT;;AAIjB,sBAAe"}
@@ -1,7 +1,10 @@
1
1
  import React from "react";
2
2
 
3
3
  //#region src/support/pages/articles.d.ts
4
- declare const ArticlesPage: React.FC;
4
+ type ArticlesPageProps = {
5
+ params?: undefined;
6
+ };
7
+ declare const ArticlesPage: React.FC<ArticlesPageProps>;
5
8
  //#endregion
6
9
  export { ArticlesPage };
7
10
  //# sourceMappingURL=articles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"articles.d.ts","names":[],"sources":["../../../src/support/pages/articles.tsx"],"sourcesContent":[],"mappings":";;;cAKa,cAAc,KAAA,CAAM"}
1
+ {"version":3,"file":"articles.d.ts","names":[],"sources":["../../../src/support/pages/articles.tsx"],"sourcesContent":[],"mappings":";;;KAKK,iBAAA;;AAL0B,CAAA;AASlB,cAAA,YAAuB,EAAT,KAAA,CAAM,EAAG,CAAA,iBAAD,CAAA"}
@@ -4,7 +4,7 @@ import { NavigationTab } from "../components/navigation-tab.js";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
 
6
6
  //#region src/support/pages/articles.tsx
7
- const ArticlesPage = () => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Header, { children: /* @__PURE__ */ jsx(NavigationTab, {}) }), /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("div", {
7
+ const ArticlesPage = (_props = {}) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Header, { children: /* @__PURE__ */ jsx(NavigationTab, {}) }), /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("div", {
8
8
  className: "p-2",
9
9
  children: /* @__PURE__ */ jsxs("div", {
10
10
  className: "flex flex-col gap-5",
@@ -1 +1 @@
1
- {"version":3,"file":"articles.js","names":["ArticlesPage: React.FC"],"sources":["../../../src/support/pages/articles.tsx"],"sourcesContent":["import type React from \"react\";\nimport { Container } from \"../components/container\";\nimport { Header } from \"../components/header\";\nimport { NavigationTab } from \"../components/navigation-tab\";\n\nexport const ArticlesPage: React.FC = () => (\n\t<>\n\t\t<Header>\n\t\t\t<NavigationTab />\n\t\t</Header>\n\t\t<Container>\n\t\t\t<div className=\"p-2\">\n\t\t\t\t<div className=\"flex flex-col gap-5\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-medium text-base text-co-primary\">\n\t\t\t\t\t\t\tHow do I start a conversation?\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p className=\"text-co-primary/60 text-sm leading-relaxed\">\n\t\t\t\t\t\t\tClick the \"Start New Conversation\" button on the home page to\n\t\t\t\t\t\t\tbegin chatting with our support team.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-medium text-base text-co-primary\">\n\t\t\t\t\t\t\tCan I view previous conversations?\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p className=\"text-co-primary/60 text-sm leading-relaxed\">\n\t\t\t\t\t\t\tYes! Navigate to the Conversation History page to see all your\n\t\t\t\t\t\t\tpast conversations.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-medium text-base text-co-primary\">\n\t\t\t\t\t\t\tHow quickly will I get a response?\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p className=\"text-co-primary/60 text-sm leading-relaxed\">\n\t\t\t\t\t\t\tOur team typically responds within a few minutes during business\n\t\t\t\t\t\t\thours.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</Container>\n\t</>\n);\n"],"mappings":";;;;;;AAKA,MAAaA,qBACZ,4CACC,oBAAC,oBACA,oBAAC,kBAAgB,GACT,EACT,oBAAC,uBACA,oBAAC;CAAI,WAAU;WACd,qBAAC;EAAI,WAAU;;GACd,qBAAC,oBACA,oBAAC;IAAG,WAAU;cAA6C;KAEtD,EACL,oBAAC;IAAE,WAAU;cAA6C;KAGtD,IACC;GACN,qBAAC,oBACA,oBAAC;IAAG,WAAU;cAA6C;KAEtD,EACL,oBAAC;IAAE,WAAU;cAA6C;KAGtD,IACC;GACN,qBAAC,oBACA,oBAAC;IAAG,WAAU;cAA6C;KAEtD,EACL,oBAAC;IAAE,WAAU;cAA6C;KAGtD,IACC;;GACD;EACD,GACK,IACV"}
1
+ {"version":3,"file":"articles.js","names":["ArticlesPage: React.FC<ArticlesPageProps>"],"sources":["../../../src/support/pages/articles.tsx"],"sourcesContent":["import type React from \"react\";\nimport { Container } from \"../components/container\";\nimport { Header } from \"../components/header\";\nimport { NavigationTab } from \"../components/navigation-tab\";\n\ntype ArticlesPageProps = {\n\tparams?: undefined;\n};\n\nexport const ArticlesPage: React.FC<ArticlesPageProps> = (_props = {}) => (\n\t<>\n\t\t<Header>\n\t\t\t<NavigationTab />\n\t\t</Header>\n\t\t<Container>\n\t\t\t<div className=\"p-2\">\n\t\t\t\t<div className=\"flex flex-col gap-5\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-medium text-base text-co-primary\">\n\t\t\t\t\t\t\tHow do I start a conversation?\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p className=\"text-co-primary/60 text-sm leading-relaxed\">\n\t\t\t\t\t\t\tClick the \"Start New Conversation\" button on the home page to\n\t\t\t\t\t\t\tbegin chatting with our support team.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-medium text-base text-co-primary\">\n\t\t\t\t\t\t\tCan I view previous conversations?\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p className=\"text-co-primary/60 text-sm leading-relaxed\">\n\t\t\t\t\t\t\tYes! Navigate to the Conversation History page to see all your\n\t\t\t\t\t\t\tpast conversations.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-medium text-base text-co-primary\">\n\t\t\t\t\t\t\tHow quickly will I get a response?\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p className=\"text-co-primary/60 text-sm leading-relaxed\">\n\t\t\t\t\t\t\tOur team typically responds within a few minutes during business\n\t\t\t\t\t\t\thours.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</Container>\n\t</>\n);\n"],"mappings":";;;;;;AASA,MAAaA,gBAA6C,SAAS,EAAE,KACpE,4CACC,oBAAC,oBACA,oBAAC,kBAAgB,GACT,EACT,oBAAC,uBACA,oBAAC;CAAI,WAAU;WACd,qBAAC;EAAI,WAAU;;GACd,qBAAC,oBACA,oBAAC;IAAG,WAAU;cAA6C;KAEtD,EACL,oBAAC;IAAE,WAAU;cAA6C;KAGtD,IACC;GACN,qBAAC,oBACA,oBAAC;IAAG,WAAU;cAA6C;KAEtD,EACL,oBAAC;IAAE,WAAU;cAA6C;KAGtD,IACC;GACN,qBAAC,oBACA,oBAAC;IAAG,WAAU;cAA6C;KAEtD,EACL,oBAAC;IAAE,WAAU;cAA6C;KAGtD,IACC;;GACD;EACD,GACK,IACV"}
@@ -1,18 +1,13 @@
1
1
  import React from "react";
2
2
 
3
3
  //#region src/support/pages/conversation-history.d.ts
4
-
4
+ type ConversationHistoryPageProps = {
5
+ params?: undefined;
6
+ };
5
7
  /**
6
- * Conversation history page component.
7
- *
8
- * Displays:
9
- * - List of all conversations
10
- * - Pagination controls
11
- * - Button to start new conversation
12
- *
13
- * All logic is handled by the useConversationHistoryPage hook.
8
+ * Conversation history page with list of past conversations and pagination.
14
9
  */
15
- declare const ConversationHistoryPage: React.FC;
10
+ declare const ConversationHistoryPage: React.FC<ConversationHistoryPageProps>;
16
11
  //#endregion
17
12
  export { ConversationHistoryPage };
18
13
  //# sourceMappingURL=conversation-history.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-history.d.ts","names":[],"sources":["../../../src/support/pages/conversation-history.tsx"],"sourcesContent":[],"mappings":";;;;;;AAwBA;;;;;;;;cAAa,yBAAyB,KAAA,CAAM"}
1
+ {"version":3,"file":"conversation-history.d.ts","names":[],"sources":["../../../src/support/pages/conversation-history.tsx"],"sourcesContent":[],"mappings":";;;KAaK,4BAAA;;AAX0B,CAAA;AAkB/B;;;cAAa,yBAAyB,KAAA,CAAM,GAAG"}