@cossistant/react 0.0.32 → 0.0.33

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 (111) hide show
  1. package/hooks/index.d.ts +2 -2
  2. package/hooks/index.js +2 -2
  3. package/hooks/private/use-grouped-messages.d.ts +27 -2
  4. package/hooks/private/use-grouped-messages.d.ts.map +1 -1
  5. package/hooks/private/use-grouped-messages.js +154 -106
  6. package/hooks/private/use-grouped-messages.js.map +1 -1
  7. package/hooks/use-new-message-sound.d.ts.map +1 -1
  8. package/hooks/use-new-message-sound.js +2 -2
  9. package/hooks/use-new-message-sound.js.map +1 -1
  10. package/hooks/use-typing-sound.d.ts.map +1 -1
  11. package/hooks/use-typing-sound.js +2 -2
  12. package/hooks/use-typing-sound.js.map +1 -1
  13. package/index.d.ts +2 -2
  14. package/index.js +2 -2
  15. package/package.json +3 -5
  16. package/packages/tiny-markdown/src/context/index.d.ts +1 -0
  17. package/packages/tiny-markdown/src/context/tiny-markdown-context.d.ts +3 -0
  18. package/packages/tiny-markdown/src/hooks/index.d.ts +4 -0
  19. package/packages/tiny-markdown/src/hooks/use-caret-position.d.ts +1 -0
  20. package/packages/tiny-markdown/src/hooks/use-tiny-markdown.d.ts +1 -0
  21. package/packages/tiny-markdown/src/hooks/use-tiny-mention.d.ts +1 -0
  22. package/packages/tiny-markdown/src/hooks/use-tiny-shortcuts.d.ts +1 -0
  23. package/packages/tiny-markdown/src/index.d.ts +4 -0
  24. package/packages/tiny-markdown/src/types.d.ts +75 -0
  25. package/packages/tiny-markdown/src/types.d.ts.map +1 -0
  26. package/packages/tiny-markdown/src/utils/index.d.ts +3 -0
  27. package/packages/tiny-markdown/src/utils/markdown-parser.d.ts +1 -0
  28. package/packages/tiny-markdown/src/utils/mention-parser.d.ts +1 -0
  29. package/packages/tiny-markdown/src/utils/merge-refs.d.ts +1 -0
  30. package/packages/types/src/api/conversation.d.ts +304 -4
  31. package/packages/types/src/api/conversation.d.ts.map +1 -1
  32. package/packages/types/src/api/timeline-item.d.ts +228 -3
  33. package/packages/types/src/api/timeline-item.d.ts.map +1 -1
  34. package/packages/types/src/realtime-events.d.ts +229 -4
  35. package/packages/types/src/realtime-events.d.ts.map +1 -1
  36. package/packages/types/src/schemas.d.ts +76 -1
  37. package/packages/types/src/schemas.d.ts.map +1 -1
  38. package/primitives/command-block-utils.d.ts +26 -0
  39. package/primitives/command-block-utils.d.ts.map +1 -0
  40. package/primitives/command-block-utils.js +310 -0
  41. package/primitives/command-block-utils.js.map +1 -0
  42. package/primitives/index.d.ts +7 -3
  43. package/primitives/index.js +11 -2
  44. package/primitives/index.parts.d.ts +6 -2
  45. package/primitives/index.parts.js +5 -1
  46. package/primitives/multimodal-input.d.ts +2 -2
  47. package/primitives/multimodal-input.d.ts.map +1 -1
  48. package/primitives/timeline-code-block.d.ts +32 -0
  49. package/primitives/timeline-code-block.d.ts.map +1 -0
  50. package/primitives/timeline-code-block.js +66 -0
  51. package/primitives/timeline-code-block.js.map +1 -0
  52. package/primitives/timeline-command-block.d.ts +29 -0
  53. package/primitives/timeline-command-block.d.ts.map +1 -0
  54. package/primitives/timeline-command-block.js +97 -0
  55. package/primitives/timeline-command-block.js.map +1 -0
  56. package/primitives/timeline-item-group.d.ts.map +1 -1
  57. package/primitives/timeline-item-group.js +5 -15
  58. package/primitives/timeline-item-group.js.map +1 -1
  59. package/primitives/timeline-item.d.ts +21 -1
  60. package/primitives/timeline-item.d.ts.map +1 -1
  61. package/primitives/timeline-item.js +148 -83
  62. package/primitives/timeline-item.js.map +1 -1
  63. package/primitives/timeline-message-layout.d.ts +9 -0
  64. package/primitives/timeline-message-layout.d.ts.map +1 -0
  65. package/primitives/timeline-message-layout.js +20 -0
  66. package/primitives/timeline-message-layout.js.map +1 -0
  67. package/realtime/event-filter.js +4 -3
  68. package/realtime/event-filter.js.map +1 -1
  69. package/sounds/sound-data.d.ts +6 -0
  70. package/sounds/sound-data.d.ts.map +1 -0
  71. package/sounds/sound-data.js +7 -0
  72. package/sounds/sound-data.js.map +1 -0
  73. package/support/components/button.d.ts +2 -2
  74. package/support/components/button.d.ts.map +1 -1
  75. package/support/components/button.js +1 -0
  76. package/support/components/button.js.map +1 -1
  77. package/support/components/conversation-event.d.ts +3 -0
  78. package/support/components/conversation-event.d.ts.map +1 -1
  79. package/support/components/conversation-event.js +46 -15
  80. package/support/components/conversation-event.js.map +1 -1
  81. package/support/components/conversation-timeline.d.ts.map +1 -1
  82. package/support/components/conversation-timeline.js +12 -0
  83. package/support/components/conversation-timeline.js.map +1 -1
  84. package/support/components/index.d.ts +2 -1
  85. package/support/components/index.js +2 -1
  86. package/support/components/timeline-activity-group.d.ts +25 -0
  87. package/support/components/timeline-activity-group.d.ts.map +1 -0
  88. package/support/components/timeline-activity-group.js +104 -0
  89. package/support/components/timeline-activity-group.js.map +1 -0
  90. package/support/components/timeline-code-block.d.ts +14 -0
  91. package/support/components/timeline-code-block.d.ts.map +1 -0
  92. package/support/components/timeline-code-block.js +44 -0
  93. package/support/components/timeline-code-block.js.map +1 -0
  94. package/support/components/timeline-command-block.d.ts +12 -0
  95. package/support/components/timeline-command-block.d.ts.map +1 -0
  96. package/support/components/timeline-command-block.js +42 -0
  97. package/support/components/timeline-command-block.js.map +1 -0
  98. package/support/components/timeline-message-item.d.ts +2 -1
  99. package/support/components/timeline-message-item.d.ts.map +1 -1
  100. package/support/components/timeline-message-item.js +23 -3
  101. package/support/components/timeline-message-item.js.map +1 -1
  102. package/support/index.d.ts +4 -4
  103. package/support/store/support-store.d.ts +5 -5
  104. package/utils/metadata-hash.d.ts +1 -1
  105. package/utils/metadata-hash.js +9 -4
  106. package/utils/metadata-hash.js.map +1 -1
  107. package/utils/timeline-item-sender.d.ts +17 -0
  108. package/utils/timeline-item-sender.d.ts.map +1 -0
  109. package/utils/timeline-item-sender.js +43 -0
  110. package/utils/timeline-item-sender.js.map +1 -0
  111. package/utils/use-render-element.d.ts.map +1 -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 type { DaySeparatorItem } from \"../../hooks/private/use-grouped-messages\";\nimport { useConversationTimeline } from \"../../hooks/use-conversation-timeline\";\nimport { useTypingSound } from \"../../hooks/use-typing-sound\";\nimport {\n\tConversationTimelineContainer,\n\tConversationTimeline as PrimitiveConversationTimeline,\n} from \"../../primitives/conversation-timeline\";\nimport {\n\tDaySeparator,\n\tDaySeparatorLabel,\n\tDaySeparatorLine,\n\tdefaultFormatDate,\n} from \"../../primitives/day-separator\";\nimport { cn } from \"../utils\";\nimport { ConversationEvent } from \"./conversation-event\";\nimport { filterSeenByIdsForViewer } from \"./conversation-timeline-utils\";\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\trenderDaySeparator?: (props: {\n\t\titem: DaySeparatorItem;\n\t\tformatDate: (date: Date) => string;\n\t}) => React.ReactNode;\n};\n\nexport const ConversationTimelineList: React.FC<ConversationTimelineProps> = ({\n\tconversationId,\n\titems: timelineItems,\n\tclassName,\n\tavailableAIAgents = [],\n\tavailableHumanAgents = [],\n\tcurrentVisitorId,\n\ttools,\n\trenderDaySeparator,\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\t// Play typing sound when someone is typing\n\tuseTypingSound(typingIndicatorParticipants.length > 0, {\n\t\tvolume: 1,\n\t\tplaybackRate: 1.3,\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 px-3 py-6\",\n\t\t\t\t\"co-scrollbar-thin\",\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-5\">\n\t\t\t\t{timeline.groupedMessages.items.map((item, index) => {\n\t\t\t\t\tif (item.type === \"day_separator\") {\n\t\t\t\t\t\t// Render day separator - allow custom rendering via prop\n\t\t\t\t\t\tif (renderDaySeparator) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div key={`day-separator-${item.dateString}`}>\n\t\t\t\t\t\t\t\t\t{renderDaySeparator({\n\t\t\t\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t\t\t\tformatDate: defaultFormatDate,\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Default day separator using the primitive\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<DaySeparator\n\t\t\t\t\t\t\t\tclassName=\"flex items-center justify-center py-2\"\n\t\t\t\t\t\t\t\tdate={item.date}\n\t\t\t\t\t\t\t\tdateString={item.dateString}\n\t\t\t\t\t\t\t\tkey={`day-separator-${item.dateString}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{({ formattedDate }) => (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLine className=\"flex-1 border-gray-300/20 border-t dark:border-gray-600/20\" />\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLabel\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"px-3 text-gray-400/50 text-xs dark:text-gray-500/50\"\n\t\t\t\t\t\t\t\t\t\t\tformattedDate={formattedDate}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLine className=\"flex-1 border-gray-300/20 border-t dark:border-gray-600/20\" />\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</DaySeparator>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\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 rawSeenByIds =\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 seenByIds = filterSeenByIdsForViewer(\n\t\t\t\t\t\trawSeenByIds,\n\t\t\t\t\t\tcurrentVisitorId\n\t\t\t\t\t);\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":"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"}
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","groupKey"],"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 type { DaySeparatorItem } from \"../../hooks/private/use-grouped-messages\";\nimport { useConversationTimeline } from \"../../hooks/use-conversation-timeline\";\nimport { useTypingSound } from \"../../hooks/use-typing-sound\";\nimport {\n\tConversationTimelineContainer,\n\tConversationTimeline as PrimitiveConversationTimeline,\n} from \"../../primitives/conversation-timeline\";\nimport {\n\tDaySeparator,\n\tDaySeparatorLabel,\n\tDaySeparatorLine,\n\tdefaultFormatDate,\n} from \"../../primitives/day-separator\";\nimport { cn } from \"../utils\";\nimport { ConversationEvent } from \"./conversation-event\";\nimport { filterSeenByIdsForViewer } from \"./conversation-timeline-utils\";\nimport { TimelineActivityGroup } from \"./timeline-activity-group\";\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\trenderDaySeparator?: (props: {\n\t\titem: DaySeparatorItem;\n\t\tformatDate: (date: Date) => string;\n\t}) => React.ReactNode;\n};\n\nexport const ConversationTimelineList: React.FC<ConversationTimelineProps> = ({\n\tconversationId,\n\titems: timelineItems,\n\tclassName,\n\tavailableAIAgents = [],\n\tavailableHumanAgents = [],\n\tcurrentVisitorId,\n\ttools,\n\trenderDaySeparator,\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\t// Play typing sound when someone is typing\n\tuseTypingSound(typingIndicatorParticipants.length > 0, {\n\t\tvolume: 1,\n\t\tplaybackRate: 1.3,\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 px-3 py-6\",\n\t\t\t\t\"co-scrollbar-thin\",\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-5\">\n\t\t\t\t{timeline.groupedMessages.items.map((item, index) => {\n\t\t\t\t\tif (item.type === \"day_separator\") {\n\t\t\t\t\t\t// Render day separator - allow custom rendering via prop\n\t\t\t\t\t\tif (renderDaySeparator) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div key={`day-separator-${item.dateString}`}>\n\t\t\t\t\t\t\t\t\t{renderDaySeparator({\n\t\t\t\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t\t\t\tformatDate: defaultFormatDate,\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Default day separator using the primitive\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<DaySeparator\n\t\t\t\t\t\t\t\tclassName=\"flex items-center justify-center py-2\"\n\t\t\t\t\t\t\t\tdate={item.date}\n\t\t\t\t\t\t\t\tdateString={item.dateString}\n\t\t\t\t\t\t\t\tkey={`day-separator-${item.dateString}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{({ formattedDate }) => (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLine className=\"flex-1 border-gray-300/20 border-t dark:border-gray-600/20\" />\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLabel\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"px-3 text-gray-400/50 text-xs dark:text-gray-500/50\"\n\t\t\t\t\t\t\t\t\t\t\tformattedDate={formattedDate}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLine className=\"flex-1 border-gray-300/20 border-t dark:border-gray-600/20\" />\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</DaySeparator>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\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\tif (item.type === \"activity_group\") {\n\t\t\t\t\t\tconst groupKey =\n\t\t\t\t\t\t\titem.firstItemId ??\n\t\t\t\t\t\t\titem.items?.[0]?.id ??\n\t\t\t\t\t\t\t`activity-group-${item.items?.[0]?.createdAt ?? index}`;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<TimelineActivityGroup\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\tconversationId={conversationId}\n\t\t\t\t\t\t\t\tcurrentVisitorId={currentVisitorId}\n\t\t\t\t\t\t\t\tgroup={item}\n\t\t\t\t\t\t\t\tkey={groupKey}\n\t\t\t\t\t\t\t\ttools={tools}\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 rawSeenByIds =\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 seenByIds = filterSeenByIdsForViewer(\n\t\t\t\t\t\trawSeenByIds,\n\t\t\t\t\t\tcurrentVisitorId\n\t\t\t\t\t);\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":"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"}
@@ -7,7 +7,8 @@ import { ConversationTimelineList, ConversationTimelineProps } from "./conversat
7
7
  import { Icon, IconName, IconProps, IconVariant } from "./icons.js";
8
8
  import { SendButton } from "./multimodal-input.js";
9
9
  import { Root, RootProps } from "./root.js";
10
+ import { TimelineActivityGroup } from "./timeline-activity-group.js";
10
11
  import { TimelineMessageGroup, TimelineMessageGroupProps } from "./timeline-message-group.js";
11
12
  import { TimelineMessageItem, TimelineMessageItemProps } from "./timeline-message-item.js";
12
13
  import { DefaultTrigger, DefaultTriggerProps } from "./trigger.js";
13
- export { Content, type ContentProps, ConversationEvent, type ConversationEventProps, ConversationResolvedFeedback, ConversationTimelineList, type ConversationTimelineProps, DefaultTrigger, type DefaultTriggerProps, Icon, type IconName, type IconProps, type IconVariant, Root, type RootProps, SendButton, TimelineMessageGroup, type TimelineMessageGroupProps, TimelineMessageItem, type TimelineMessageItemProps, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType };
14
+ export { Content, type ContentProps, ConversationEvent, type ConversationEventProps, ConversationResolvedFeedback, ConversationTimelineList, type ConversationTimelineProps, DefaultTrigger, type DefaultTriggerProps, Icon, type IconName, type IconProps, type IconVariant, Root, type RootProps, SendButton, TimelineActivityGroup, TimelineMessageGroup, type TimelineMessageGroupProps, TimelineMessageItem, type TimelineMessageItemProps, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType };
@@ -5,9 +5,10 @@ import { Root } from "./root.js";
5
5
  import { DefaultTrigger } from "./trigger.js";
6
6
  import { ConversationResolvedFeedback } from "./conversation-resolved-feedback.js";
7
7
  import { ConversationEvent } from "./conversation-event.js";
8
+ import { TimelineActivityGroup } from "./timeline-activity-group.js";
8
9
  import { TimelineMessageItem } from "./timeline-message-item.js";
9
10
  import { TimelineMessageGroup } from "./timeline-message-group.js";
10
11
  import { ConversationTimelineList } from "./conversation-timeline.js";
11
12
  import { SendButton } from "./multimodal-input.js";
12
13
 
13
- export { Content, ConversationEvent, ConversationResolvedFeedback, ConversationTimelineList, DefaultTrigger, icons_default as Icon, Root, SendButton, TimelineMessageGroup, TimelineMessageItem, TypingIndicator };
14
+ export { Content, ConversationEvent, ConversationResolvedFeedback, ConversationTimelineList, DefaultTrigger, icons_default as Icon, Root, SendButton, TimelineActivityGroup, TimelineMessageGroup, TimelineMessageItem, TypingIndicator };
@@ -0,0 +1,25 @@
1
+ import { TimelineItem } from "../../packages/types/src/api/timeline-item.js";
2
+ import { GroupedActivity } from "../../hooks/private/use-grouped-messages.js";
3
+ import React from "react";
4
+ import { AvailableAIAgent, AvailableHumanAgent } from "@cossistant/types";
5
+
6
+ //#region src/support/components/timeline-activity-group.d.ts
7
+ type TimelineActivityToolProps = {
8
+ item: TimelineItem;
9
+ conversationId: string;
10
+ };
11
+ type TimelineActivityTools = Record<string, {
12
+ component: React.ComponentType<TimelineActivityToolProps>;
13
+ }>;
14
+ type TimelineActivityGroupProps = {
15
+ group: GroupedActivity;
16
+ conversationId: string;
17
+ availableAIAgents: AvailableAIAgent[];
18
+ availableHumanAgents: AvailableHumanAgent[];
19
+ currentVisitorId?: string;
20
+ tools?: TimelineActivityTools;
21
+ };
22
+ declare const TimelineActivityGroup: React.FC<TimelineActivityGroupProps>;
23
+ //#endregion
24
+ export { TimelineActivityGroup };
25
+ //# sourceMappingURL=timeline-activity-group.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-activity-group.d.ts","names":[],"sources":["../../../src/support/components/timeline-activity-group.tsx"],"sourcesContent":[],"mappings":";;;;;;KAkBK,yBAAA;QACE;EADF,cAAA,EAAA,MAAA;AACc,CAAA;KAId,qBAAA,GAAwB,MAGI,CAAA,MAAA,EAAA;EAApB,SAAM,EAAN,KAAA,CAAM,aAAA,CAAc,yBAAd,CAAA;CAHU,CAAA;KAOxB,0BAAA,GAP8B;EAO9B,KAAA,EACG,eADH;EACG,cAAA,EAAA,MAAA;EAEY,iBAAA,EAAA,gBAAA,EAAA;EACG,oBAAA,EAAA,mBAAA,EAAA;EAEd,gBAAA,CAAA,EAAA,MAAA;EAAqB,KAAA,CAAA,EAArB,qBAAqB;AAmD9B,CAAA;cAAa,uBAAuB,KAAA,CAAM,GAAG"}
@@ -0,0 +1,104 @@
1
+ import { Avatar } from "./avatar.js";
2
+ import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent } from "../../primitives/timeline-item-group.js";
3
+ import { ConversationEvent } from "./conversation-event.js";
4
+ import { useMemo } from "react";
5
+ import { SenderType } from "@cossistant/types";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+
8
+ //#region src/support/components/timeline-activity-group.tsx
9
+ function extractEventPart(item) {
10
+ if (item.type !== "event") return null;
11
+ return item.parts.find((part) => part.type === "event") || null;
12
+ }
13
+ function getToolNameFromTimelineItem(item) {
14
+ if (item.tool) return item.tool;
15
+ for (const part of item.parts) if (typeof part === "object" && part !== null && "type" in part && "toolName" in part && typeof part.type === "string" && part.type.startsWith("tool-") && typeof part.toolName === "string") return part.toolName;
16
+ return null;
17
+ }
18
+ const TimelineActivityGroup = ({ group, conversationId, availableAIAgents, availableHumanAgents, currentVisitorId, tools }) => {
19
+ const activityRows = useMemo(() => {
20
+ const rows = [];
21
+ for (let index = 0; index < group.items.length; index++) {
22
+ const item = group.items[index];
23
+ if (!item) continue;
24
+ if (item.type === "event") {
25
+ const eventPart = extractEventPart(item);
26
+ if (!eventPart) continue;
27
+ rows.push({
28
+ type: "event",
29
+ key: item.id ?? `activity-event-${item.createdAt}-${index}`,
30
+ item,
31
+ event: eventPart
32
+ });
33
+ continue;
34
+ }
35
+ if (item.type === "tool") {
36
+ const toolName = getToolNameFromTimelineItem(item);
37
+ if (!toolName) continue;
38
+ const toolDefinition = tools?.[toolName];
39
+ if (!toolDefinition) continue;
40
+ rows.push({
41
+ type: "tool",
42
+ key: item.id ?? `activity-tool-${item.createdAt}-${index}`,
43
+ item,
44
+ ToolComponent: toolDefinition.component
45
+ });
46
+ }
47
+ }
48
+ return rows;
49
+ }, [group.items, tools]);
50
+ if (activityRows.length === 0) return null;
51
+ const humanAgent = availableHumanAgents.find((agent) => agent.id === group.senderId);
52
+ const aiAgent = availableAIAgents.find((agent) => agent.id === group.senderId);
53
+ return /* @__PURE__ */ jsx(TimelineItemGroup, {
54
+ items: group.items,
55
+ viewerId: currentVisitorId,
56
+ viewerType: SenderType.VISITOR,
57
+ children: ({ isAI, isTeamMember }) => /* @__PURE__ */ jsxs("div", {
58
+ className: "flex w-full flex-row gap-2",
59
+ children: [/* @__PURE__ */ jsx(TimelineItemGroupAvatar, {
60
+ className: "flex shrink-0 flex-col justify-start",
61
+ children: isAI ? /* @__PURE__ */ jsx(Avatar, {
62
+ className: "size-6",
63
+ image: aiAgent?.image,
64
+ isAI: true,
65
+ name: aiAgent?.name || "AI Assistant",
66
+ showBackground: !!aiAgent?.image
67
+ }) : /* @__PURE__ */ jsx(Avatar, {
68
+ className: "size-6",
69
+ image: humanAgent?.image,
70
+ name: isTeamMember ? humanAgent?.name || "Support" : "Visitor"
71
+ })
72
+ }), /* @__PURE__ */ jsx(TimelineItemGroupContent, {
73
+ className: "flex min-w-0 flex-1 flex-col gap-1",
74
+ children: /* @__PURE__ */ jsx("div", {
75
+ className: "flex w-full min-w-0 flex-col gap-2",
76
+ children: activityRows.map((row) => {
77
+ if (row.type === "event") return /* @__PURE__ */ jsx(ConversationEvent, {
78
+ availableAIAgents,
79
+ availableHumanAgents,
80
+ className: "w-full",
81
+ compact: true,
82
+ createdAt: row.item.createdAt,
83
+ event: row.event,
84
+ showAvatar: false
85
+ }, row.key);
86
+ const ToolComponent = row.ToolComponent;
87
+ return /* @__PURE__ */ jsx("div", {
88
+ className: "w-full",
89
+ children: /* @__PURE__ */ jsx(ToolComponent, {
90
+ conversationId,
91
+ item: row.item
92
+ })
93
+ }, row.key);
94
+ })
95
+ })
96
+ })]
97
+ })
98
+ });
99
+ };
100
+ TimelineActivityGroup.displayName = "TimelineActivityGroup";
101
+
102
+ //#endregion
103
+ export { TimelineActivityGroup };
104
+ //# sourceMappingURL=timeline-activity-group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-activity-group.js","names":["TimelineActivityGroup: React.FC<TimelineActivityGroupProps>","rows: ActivityRow[]","PrimitiveTimelineItemGroup"],"sources":["../../../src/support/components/timeline-activity-group.tsx"],"sourcesContent":["import type {\n\tAvailableAIAgent,\n\tAvailableHumanAgent,\n\tTimelinePartEvent,\n} from \"@cossistant/types\";\nimport { SenderType } from \"@cossistant/types\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport type { GroupedActivity } from \"../../hooks/private/use-grouped-messages\";\nimport {\n\tTimelineItemGroup as PrimitiveTimelineItemGroup,\n\tTimelineItemGroupAvatar,\n\tTimelineItemGroupContent,\n} from \"../../primitives/timeline-item-group\";\nimport { Avatar } from \"./avatar\";\nimport { ConversationEvent } from \"./conversation-event\";\n\ntype TimelineActivityToolProps = {\n\titem: TimelineItem;\n\tconversationId: string;\n};\n\ntype TimelineActivityTools = Record<\n\tstring,\n\t{\n\t\tcomponent: React.ComponentType<TimelineActivityToolProps>;\n\t}\n>;\n\ntype TimelineActivityGroupProps = {\n\tgroup: GroupedActivity;\n\tconversationId: string;\n\tavailableAIAgents: AvailableAIAgent[];\n\tavailableHumanAgents: AvailableHumanAgent[];\n\tcurrentVisitorId?: string;\n\ttools?: TimelineActivityTools;\n};\n\ntype ActivityRow =\n\t| {\n\t\t\ttype: \"event\";\n\t\t\tkey: string;\n\t\t\titem: TimelineItem;\n\t\t\tevent: TimelinePartEvent;\n\t }\n\t| {\n\t\t\ttype: \"tool\";\n\t\t\tkey: string;\n\t\t\titem: TimelineItem;\n\t\t\tToolComponent: React.ComponentType<TimelineActivityToolProps>;\n\t };\n\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\nfunction getToolNameFromTimelineItem(item: TimelineItem): string | null {\n\tif (item.tool) {\n\t\treturn item.tool;\n\t}\n\n\tfor (const part of item.parts) {\n\t\tif (\n\t\t\ttypeof part === \"object\" &&\n\t\t\tpart !== null &&\n\t\t\t\"type\" in part &&\n\t\t\t\"toolName\" in part &&\n\t\t\ttypeof part.type === \"string\" &&\n\t\t\tpart.type.startsWith(\"tool-\") &&\n\t\t\ttypeof part.toolName === \"string\"\n\t\t) {\n\t\t\treturn part.toolName;\n\t\t}\n\t}\n\n\treturn null;\n}\n\nexport const TimelineActivityGroup: React.FC<TimelineActivityGroupProps> = ({\n\tgroup,\n\tconversationId,\n\tavailableAIAgents,\n\tavailableHumanAgents,\n\tcurrentVisitorId,\n\ttools,\n}) => {\n\tconst activityRows = useMemo<ActivityRow[]>(() => {\n\t\tconst rows: ActivityRow[] = [];\n\n\t\tfor (let index = 0; index < group.items.length; index++) {\n\t\t\tconst item = group.items[index];\n\t\t\tif (!item) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (item.type === \"event\") {\n\t\t\t\tconst eventPart = extractEventPart(item);\n\t\t\t\tif (!eventPart) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\trows.push({\n\t\t\t\t\ttype: \"event\",\n\t\t\t\t\tkey: item.id ?? `activity-event-${item.createdAt}-${index}`,\n\t\t\t\t\titem,\n\t\t\t\t\tevent: eventPart,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (item.type === \"tool\") {\n\t\t\t\tconst toolName = getToolNameFromTimelineItem(item);\n\t\t\t\tif (!toolName) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst toolDefinition = tools?.[toolName];\n\t\t\t\tif (!toolDefinition) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\trows.push({\n\t\t\t\t\ttype: \"tool\",\n\t\t\t\t\tkey: item.id ?? `activity-tool-${item.createdAt}-${index}`,\n\t\t\t\t\titem,\n\t\t\t\t\tToolComponent: toolDefinition.component,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn rows;\n\t}, [group.items, tools]);\n\n\tif (activityRows.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst humanAgent = availableHumanAgents.find(\n\t\t(agent) => agent.id === group.senderId\n\t);\n\tconst aiAgent = availableAIAgents.find(\n\t\t(agent) => agent.id === group.senderId\n\t);\n\n\treturn (\n\t\t<PrimitiveTimelineItemGroup\n\t\t\titems={group.items}\n\t\t\tviewerId={currentVisitorId}\n\t\t\tviewerType={SenderType.VISITOR}\n\t\t>\n\t\t\t{({ isAI, isTeamMember }) => (\n\t\t\t\t<div className=\"flex w-full flex-row gap-2\">\n\t\t\t\t\t<TimelineItemGroupAvatar className=\"flex shrink-0 flex-col justify-start\">\n\t\t\t\t\t\t{isAI ? (\n\t\t\t\t\t\t\t<Avatar\n\t\t\t\t\t\t\t\tclassName=\"size-6\"\n\t\t\t\t\t\t\t\timage={aiAgent?.image}\n\t\t\t\t\t\t\t\tisAI\n\t\t\t\t\t\t\t\tname={aiAgent?.name || \"AI Assistant\"}\n\t\t\t\t\t\t\t\tshowBackground={!!aiAgent?.image}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<Avatar\n\t\t\t\t\t\t\t\tclassName=\"size-6\"\n\t\t\t\t\t\t\t\timage={humanAgent?.image}\n\t\t\t\t\t\t\t\tname={isTeamMember ? humanAgent?.name || \"Support\" : \"Visitor\"}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</TimelineItemGroupAvatar>\n\n\t\t\t\t\t<TimelineItemGroupContent className=\"flex min-w-0 flex-1 flex-col gap-1\">\n\t\t\t\t\t\t<div className=\"flex w-full min-w-0 flex-col gap-2\">\n\t\t\t\t\t\t\t{activityRows.map((row) => {\n\t\t\t\t\t\t\t\tif (row.type === \"event\") {\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<ConversationEvent\n\t\t\t\t\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"w-full\"\n\t\t\t\t\t\t\t\t\t\t\tcompact\n\t\t\t\t\t\t\t\t\t\t\tcreatedAt={row.item.createdAt}\n\t\t\t\t\t\t\t\t\t\t\tevent={row.event}\n\t\t\t\t\t\t\t\t\t\t\tkey={row.key}\n\t\t\t\t\t\t\t\t\t\t\tshowAvatar={false}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst ToolComponent = row.ToolComponent;\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<div className=\"w-full\" key={row.key}>\n\t\t\t\t\t\t\t\t\t\t<ToolComponent\n\t\t\t\t\t\t\t\t\t\t\tconversationId={conversationId}\n\t\t\t\t\t\t\t\t\t\t\titem={row.item}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</TimelineItemGroupContent>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</PrimitiveTimelineItemGroup>\n\t);\n};\n\nTimelineActivityGroup.displayName = \"TimelineActivityGroup\";\n"],"mappings":";;;;;;;;AAqDA,SAAS,iBAAiB,MAA8C;AACvE,KAAI,KAAK,SAAS,QACjB,QAAO;AAOR,QAJkB,KAAK,MAAM,MAC3B,SAAoC,KAAK,SAAS,QACnD,IAEmB;;AAGrB,SAAS,4BAA4B,MAAmC;AACvE,KAAI,KAAK,KACR,QAAO,KAAK;AAGb,MAAK,MAAM,QAAQ,KAAK,MACvB,KACC,OAAO,SAAS,YAChB,SAAS,QACT,UAAU,QACV,cAAc,QACd,OAAO,KAAK,SAAS,YACrB,KAAK,KAAK,WAAW,QAAQ,IAC7B,OAAO,KAAK,aAAa,SAEzB,QAAO,KAAK;AAId,QAAO;;AAGR,MAAaA,yBAA+D,EAC3E,OACA,gBACA,mBACA,sBACA,kBACA,YACK;CACL,MAAM,eAAe,cAA6B;EACjD,MAAMC,OAAsB,EAAE;AAE9B,OAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,MAAM,QAAQ,SAAS;GACxD,MAAM,OAAO,MAAM,MAAM;AACzB,OAAI,CAAC,KACJ;AAGD,OAAI,KAAK,SAAS,SAAS;IAC1B,MAAM,YAAY,iBAAiB,KAAK;AACxC,QAAI,CAAC,UACJ;AAGD,SAAK,KAAK;KACT,MAAM;KACN,KAAK,KAAK,MAAM,kBAAkB,KAAK,UAAU,GAAG;KACpD;KACA,OAAO;KACP,CAAC;AACF;;AAGD,OAAI,KAAK,SAAS,QAAQ;IACzB,MAAM,WAAW,4BAA4B,KAAK;AAClD,QAAI,CAAC,SACJ;IAGD,MAAM,iBAAiB,QAAQ;AAC/B,QAAI,CAAC,eACJ;AAGD,SAAK,KAAK;KACT,MAAM;KACN,KAAK,KAAK,MAAM,iBAAiB,KAAK,UAAU,GAAG;KACnD;KACA,eAAe,eAAe;KAC9B,CAAC;;;AAIJ,SAAO;IACL,CAAC,MAAM,OAAO,MAAM,CAAC;AAExB,KAAI,aAAa,WAAW,EAC3B,QAAO;CAGR,MAAM,aAAa,qBAAqB,MACtC,UAAU,MAAM,OAAO,MAAM,SAC9B;CACD,MAAM,UAAU,kBAAkB,MAChC,UAAU,MAAM,OAAO,MAAM,SAC9B;AAED,QACC,oBAACC;EACA,OAAO,MAAM;EACb,UAAU;EACV,YAAY,WAAW;aAErB,EAAE,MAAM,mBACT,qBAAC;GAAI,WAAU;cACd,oBAAC;IAAwB,WAAU;cACjC,OACA,oBAAC;KACA,WAAU;KACV,OAAO,SAAS;KAChB;KACA,MAAM,SAAS,QAAQ;KACvB,gBAAgB,CAAC,CAAC,SAAS;MAC1B,GAEF,oBAAC;KACA,WAAU;KACV,OAAO,YAAY;KACnB,MAAM,eAAe,YAAY,QAAQ,YAAY;MACpD;KAEsB,EAE1B,oBAAC;IAAyB,WAAU;cACnC,oBAAC;KAAI,WAAU;eACb,aAAa,KAAK,QAAQ;AAC1B,UAAI,IAAI,SAAS,QAChB,QACC,oBAAC;OACmB;OACG;OACtB,WAAU;OACV;OACA,WAAW,IAAI,KAAK;OACpB,OAAO,IAAI;OAEX,YAAY;SADP,IAAI,IAER;MAIJ,MAAM,gBAAgB,IAAI;AAC1B,aACC,oBAAC;OAAI,WAAU;iBACd,oBAAC;QACgB;QAChB,MAAM,IAAI;SACT;SAJ0B,IAAI,IAK3B;OAEN;MACG;KACoB;IACtB;GAEqB;;AAI/B,sBAAsB,cAAc"}
@@ -0,0 +1,14 @@
1
+ import { TimelineCodeBlockProps as TimelineCodeBlockProps$1 } from "../../primitives/timeline-code-block.js";
2
+ import React from "react";
3
+
4
+ //#region src/support/components/timeline-code-block.d.ts
5
+ type TimelineCodeBlockProps = TimelineCodeBlockProps$1;
6
+ declare function TimelineCodeBlock({
7
+ code,
8
+ language,
9
+ fileName,
10
+ className
11
+ }: TimelineCodeBlockProps): React.ReactElement;
12
+ //#endregion
13
+ export { TimelineCodeBlock, TimelineCodeBlockProps };
14
+ //# sourceMappingURL=timeline-code-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-code-block.d.ts","names":[],"sources":["../../../src/support/components/timeline-code-block.tsx"],"sourcesContent":[],"mappings":";;;;KAOY,sBAAA,GAAyB;iBAErB,iBAAA;;;;;GAKb,yBAAyB,KAAA,CAAM"}
@@ -0,0 +1,44 @@
1
+ import { TimelineCodeBlock as TimelineCodeBlock$1 } from "../../primitives/timeline-code-block.js";
2
+ import { CoButton } from "./button.js";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+
5
+ //#region src/support/components/timeline-code-block.tsx
6
+ function TimelineCodeBlock({ code, language, fileName, className }) {
7
+ return /* @__PURE__ */ jsx(TimelineCodeBlock$1, {
8
+ className: `mt-1 w-full overflow-hidden rounded border border-co-border bg-co-background-200 ${className ?? ""}`.trim(),
9
+ code,
10
+ fileName,
11
+ language,
12
+ children: ({ code: content, codeClassName, fileName: resolvedFileName, languageLabel, hasCopied, onCopy }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
13
+ className: "flex items-center justify-between gap-2 px-2 py-1.5",
14
+ children: [/* @__PURE__ */ jsxs("div", {
15
+ className: "flex min-w-0 items-center gap-2",
16
+ children: [resolvedFileName ? /* @__PURE__ */ jsx("span", {
17
+ className: "truncate font-medium text-xs",
18
+ children: resolvedFileName
19
+ }) : null, /* @__PURE__ */ jsx("span", {
20
+ className: "rounded border border-co-border/70 bg-co-background-500 px-1.5 py-0.5 font-medium text-[10px] uppercase tracking-wide",
21
+ children: languageLabel
22
+ })]
23
+ }), /* @__PURE__ */ jsx(CoButton, {
24
+ onClick: () => {
25
+ onCopy();
26
+ },
27
+ size: "small",
28
+ type: "button",
29
+ variant: "ghost",
30
+ children: hasCopied ? "Copied" : "Copy"
31
+ })]
32
+ }), /* @__PURE__ */ jsx("pre", {
33
+ className: "no-scrollbar overflow-x-auto p-3 text-xs leading-relaxed",
34
+ children: /* @__PURE__ */ jsx("code", {
35
+ className: codeClassName,
36
+ children: content
37
+ })
38
+ })] })
39
+ });
40
+ }
41
+
42
+ //#endregion
43
+ export { TimelineCodeBlock };
44
+ //# sourceMappingURL=timeline-code-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-code-block.js","names":["PrimitiveTimelineCodeBlock"],"sources":["../../../src/support/components/timeline-code-block.tsx"],"sourcesContent":["import type React from \"react\";\nimport {\n\tTimelineCodeBlock as PrimitiveTimelineCodeBlock,\n\ttype TimelineCodeBlockProps as PrimitiveTimelineCodeBlockProps,\n} from \"../../primitives/timeline-code-block\";\nimport { CoButton } from \"./button\";\n\nexport type TimelineCodeBlockProps = PrimitiveTimelineCodeBlockProps;\n\nexport function TimelineCodeBlock({\n\tcode,\n\tlanguage,\n\tfileName,\n\tclassName,\n}: TimelineCodeBlockProps): React.ReactElement {\n\treturn (\n\t\t<PrimitiveTimelineCodeBlock\n\t\t\tclassName={`mt-1 w-full overflow-hidden rounded border border-co-border bg-co-background-200 ${className ?? \"\"}`.trim()}\n\t\t\tcode={code}\n\t\t\tfileName={fileName}\n\t\t\tlanguage={language}\n\t\t>\n\t\t\t{({\n\t\t\t\tcode: content,\n\t\t\t\tcodeClassName,\n\t\t\t\tfileName: resolvedFileName,\n\t\t\t\tlanguageLabel,\n\t\t\t\thasCopied,\n\t\t\t\tonCopy,\n\t\t\t}) => (\n\t\t\t\t<>\n\t\t\t\t\t<div className=\"flex items-center justify-between gap-2 px-2 py-1.5\">\n\t\t\t\t\t\t<div className=\"flex min-w-0 items-center gap-2\">\n\t\t\t\t\t\t\t{resolvedFileName ? (\n\t\t\t\t\t\t\t\t<span className=\"truncate font-medium text-xs\">\n\t\t\t\t\t\t\t\t\t{resolvedFileName}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t<span className=\"rounded border border-co-border/70 bg-co-background-500 px-1.5 py-0.5 font-medium text-[10px] uppercase tracking-wide\">\n\t\t\t\t\t\t\t\t{languageLabel}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t<CoButton\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tvoid onCopy();\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{hasCopied ? \"Copied\" : \"Copy\"}\n\t\t\t\t\t\t</CoButton>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<pre className=\"no-scrollbar overflow-x-auto p-3 text-xs leading-relaxed\">\n\t\t\t\t\t\t<code className={codeClassName}>{content}</code>\n\t\t\t\t\t</pre>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</PrimitiveTimelineCodeBlock>\n\t);\n}\n"],"mappings":";;;;;AASA,SAAgB,kBAAkB,EACjC,MACA,UACA,UACA,aAC8C;AAC9C,QACC,oBAACA;EACA,WAAW,oFAAoF,aAAa,KAAK,MAAM;EACjH;EACI;EACA;aAER,EACD,MAAM,SACN,eACA,UAAU,kBACV,eACA,WACA,aAEA,4CACC,qBAAC;GAAI,WAAU;cACd,qBAAC;IAAI,WAAU;eACb,mBACA,oBAAC;KAAK,WAAU;eACd;MACK,GACJ,MACJ,oBAAC;KAAK,WAAU;eACd;MACK;KACF,EAEN,oBAAC;IACA,eAAe;AACd,KAAK,QAAQ;;IAEd,MAAK;IACL,MAAK;IACL,SAAQ;cAEP,YAAY,WAAW;KACd;IACN,EAEN,oBAAC;GAAI,WAAU;aACd,oBAAC;IAAK,WAAW;cAAgB;KAAe;IAC3C,IACJ;GAEwB"}
@@ -0,0 +1,12 @@
1
+ import { TimelineCommandBlockProps as TimelineCommandBlockProps$1 } from "../../primitives/timeline-command-block.js";
2
+ import React from "react";
3
+
4
+ //#region src/support/components/timeline-command-block.d.ts
5
+ type TimelineCommandBlockProps = TimelineCommandBlockProps$1;
6
+ declare function TimelineCommandBlock({
7
+ commands,
8
+ className
9
+ }: TimelineCommandBlockProps): React.ReactElement;
10
+ //#endregion
11
+ export { TimelineCommandBlock, TimelineCommandBlockProps };
12
+ //# sourceMappingURL=timeline-command-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-command-block.d.ts","names":[],"sources":["../../../src/support/components/timeline-command-block.tsx"],"sourcesContent":[],"mappings":";;;;KAOY,yBAAA,GAA4B;iBAExB,oBAAA;;;GAGb,4BAA4B,KAAA,CAAM"}
@@ -0,0 +1,42 @@
1
+ import { TimelineCommandBlock as TimelineCommandBlock$1 } from "../../primitives/timeline-command-block.js";
2
+ import { CoButton } from "./button.js";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+
5
+ //#region src/support/components/timeline-command-block.tsx
6
+ function TimelineCommandBlock({ commands, className }) {
7
+ return /* @__PURE__ */ jsx(TimelineCommandBlock$1, {
8
+ className: `mt-1 w-full overflow-hidden rounded border border-co-border bg-co-background-200 ${className ?? ""}`.trim(),
9
+ commands,
10
+ children: ({ activeCommand, activePackageManager, hasCopied, onCopy, packageManagers, setPackageManager }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
11
+ className: "flex items-center justify-between gap-2 px-2 py-1.5",
12
+ children: [/* @__PURE__ */ jsx("div", {
13
+ className: "flex items-center gap-1",
14
+ children: packageManagers.map((packageManager) => /* @__PURE__ */ jsx(CoButton, {
15
+ onClick: () => setPackageManager(packageManager),
16
+ size: "small",
17
+ type: "button",
18
+ variant: activePackageManager === packageManager ? "outline" : "ghost",
19
+ children: packageManager
20
+ }, packageManager))
21
+ }), /* @__PURE__ */ jsx(CoButton, {
22
+ onClick: () => {
23
+ onCopy();
24
+ },
25
+ size: "small",
26
+ type: "button",
27
+ variant: "ghost",
28
+ children: hasCopied ? "Copied" : "Copy"
29
+ })]
30
+ }), /* @__PURE__ */ jsx("pre", {
31
+ className: "no-scrollbar overflow-x-auto p-3 text-xs leading-relaxed",
32
+ children: /* @__PURE__ */ jsx("code", {
33
+ className: "language-bash",
34
+ children: activeCommand
35
+ })
36
+ })] })
37
+ });
38
+ }
39
+
40
+ //#endregion
41
+ export { TimelineCommandBlock };
42
+ //# sourceMappingURL=timeline-command-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-command-block.js","names":["PrimitiveTimelineCommandBlock"],"sources":["../../../src/support/components/timeline-command-block.tsx"],"sourcesContent":["import type React from \"react\";\nimport {\n\tTimelineCommandBlock as PrimitiveTimelineCommandBlock,\n\ttype TimelineCommandBlockProps as PrimitiveTimelineCommandBlockProps,\n} from \"../../primitives/timeline-command-block\";\nimport { CoButton } from \"./button\";\n\nexport type TimelineCommandBlockProps = PrimitiveTimelineCommandBlockProps;\n\nexport function TimelineCommandBlock({\n\tcommands,\n\tclassName,\n}: TimelineCommandBlockProps): React.ReactElement {\n\treturn (\n\t\t<PrimitiveTimelineCommandBlock\n\t\t\tclassName={`mt-1 w-full overflow-hidden rounded border border-co-border bg-co-background-200 ${className ?? \"\"}`.trim()}\n\t\t\tcommands={commands}\n\t\t>\n\t\t\t{({\n\t\t\t\tactiveCommand,\n\t\t\t\tactivePackageManager,\n\t\t\t\thasCopied,\n\t\t\t\tonCopy,\n\t\t\t\tpackageManagers,\n\t\t\t\tsetPackageManager,\n\t\t\t}) => (\n\t\t\t\t<>\n\t\t\t\t\t<div className=\"flex items-center justify-between gap-2 px-2 py-1.5\">\n\t\t\t\t\t\t<div className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t{packageManagers.map((packageManager) => (\n\t\t\t\t\t\t\t\t<CoButton\n\t\t\t\t\t\t\t\t\tkey={packageManager}\n\t\t\t\t\t\t\t\t\tonClick={() => setPackageManager(packageManager)}\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tvariant={\n\t\t\t\t\t\t\t\t\t\tactivePackageManager === packageManager\n\t\t\t\t\t\t\t\t\t\t\t? \"outline\"\n\t\t\t\t\t\t\t\t\t\t\t: \"ghost\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{packageManager}\n\t\t\t\t\t\t\t\t</CoButton>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t<CoButton\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tvoid onCopy();\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{hasCopied ? \"Copied\" : \"Copy\"}\n\t\t\t\t\t\t</CoButton>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<pre className=\"no-scrollbar overflow-x-auto p-3 text-xs leading-relaxed\">\n\t\t\t\t\t\t<code className=\"language-bash\">{activeCommand}</code>\n\t\t\t\t\t</pre>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</PrimitiveTimelineCommandBlock>\n\t);\n}\n"],"mappings":";;;;;AASA,SAAgB,qBAAqB,EACpC,UACA,aACiD;AACjD,QACC,oBAACA;EACA,WAAW,oFAAoF,aAAa,KAAK,MAAM;EAC7G;aAER,EACD,eACA,sBACA,WACA,QACA,iBACA,wBAEA,4CACC,qBAAC;GAAI,WAAU;cACd,oBAAC;IAAI,WAAU;cACb,gBAAgB,KAAK,mBACrB,oBAAC;KAEA,eAAe,kBAAkB,eAAe;KAChD,MAAK;KACL,MAAK;KACL,SACC,yBAAyB,iBACtB,YACA;eAGH;OAVI,eAWK,CACV;KACG,EAEN,oBAAC;IACA,eAAe;AACd,KAAK,QAAQ;;IAEd,MAAK;IACL,MAAK;IACL,SAAQ;cAEP,YAAY,WAAW;KACd;IACN,EAEN,oBAAC;GAAI,WAAU;aACd,oBAAC;IAAK,WAAU;cAAiB;KAAqB;IACjD,IACJ;GAE2B"}
@@ -7,6 +7,7 @@ type TimelineMessageItemProps = {
7
7
  isLast?: boolean;
8
8
  isSentByViewer?: boolean;
9
9
  };
10
+ declare function getSupportMessageWidthClasses(text: string | null | undefined): string;
10
11
  /**
11
12
  * Message bubble renderer that adapts layout depending on whether the visitor
12
13
  * or an agent sent the message.
@@ -17,5 +18,5 @@ declare function TimelineMessageItem({
17
18
  isSentByViewer
18
19
  }: TimelineMessageItemProps): React.ReactElement;
19
20
  //#endregion
20
- export { TimelineMessageItem, TimelineMessageItemProps };
21
+ export { TimelineMessageItem, TimelineMessageItemProps, getSupportMessageWidthClasses };
21
22
  //# sourceMappingURL=timeline-message-item.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"timeline-message-item.d.ts","names":[],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":[],"mappings":";;;;KAkBY,wBAAA;QACL;EADK,MAAA,CAAA,EAAA,OAAA;EAUI,cAAA,CAAA,EAAA,OAAmB;CAClC;;;;;AAG+C,iBAJhC,mBAAA,CAIgC;EAAA,IAAA;EAAA,MAAA;EAAA;AAAA,CAAA,EAA7C,wBAA6C,CAAA,EAAlB,KAAA,CAAM,YAAY"}
1
+ {"version":3,"file":"timeline-message-item.d.ts","names":[],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":[],"mappings":";;;;KAsBY,wBAAA;QACL;EADK,MAAA,CAAA,EAAA,OAAA;EAMI,cAAA,CAAA,EAAA,OAAA;AAYhB,CAAA;AACC,iBAbe,6BAAA,CAaf,IAAA,EAAA,MAAA,GAAA,IAAA,GAAA,SAAA,CAAA,EAAA,MAAA;;;;;AAG+C,iBAJhC,mBAAA,CAIgC;EAAA,IAAA;EAAA,MAAA;EAAA;AAAA,CAAA,EAA7C,wBAA6C,CAAA,EAAlB,KAAA,CAAM,YAAY"}
@@ -1,14 +1,20 @@
1
1
  import { cn } from "../utils/index.js";
2
2
  import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "../../primitives/timeline-item.js";
3
3
  import { extractFileParts, extractImageParts } from "../../primitives/timeline-item-attachments.js";
4
+ import { hasExpandedTimelineContent } from "../../primitives/timeline-message-layout.js";
4
5
  import icons_default from "./icons.js";
5
6
  import { useSupportText } from "../text/index.js";
6
7
  import { ImageLightbox } from "./image-lightbox.js";
7
- import { useState } from "react";
8
+ import { TimelineCodeBlock } from "./timeline-code-block.js";
9
+ import { TimelineCommandBlock } from "./timeline-command-block.js";
10
+ import { useMemo, useState } from "react";
8
11
  import { formatFileSize } from "@cossistant/core";
9
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
13
 
11
14
  //#region src/support/components/timeline-message-item.tsx
15
+ function getSupportMessageWidthClasses(text) {
16
+ return hasExpandedTimelineContent(text) ? "w-full max-w-full" : "max-w-[300px]";
17
+ }
12
18
  /**
13
19
  * Message bubble renderer that adapts layout depending on whether the visitor
14
20
  * or an agent sent the message.
@@ -21,6 +27,19 @@ function TimelineMessageItem({ item, isLast = false, isSentByViewer = false }) {
21
27
  const files = extractFileParts(item.parts);
22
28
  const hasAttachments = images.length > 0 || files.length > 0;
23
29
  const hasText = item.text && item.text.trim().length > 0;
30
+ const messageWidthClassName = getSupportMessageWidthClasses(item.text);
31
+ const markdownRenderers = useMemo(() => ({
32
+ codeBlock: ({ code, fileName, language }) => /* @__PURE__ */ jsx(TimelineCodeBlock, {
33
+ code,
34
+ fileName,
35
+ language
36
+ }),
37
+ commandBlock: ({ commands }) => /* @__PURE__ */ jsx(TimelineCommandBlock, { commands }),
38
+ inlineCode: ({ code }) => /* @__PURE__ */ jsx("code", {
39
+ className: "rounded bg-co-background-300 px-1 py-0.5 text-xs",
40
+ children: code
41
+ })
42
+ }), []);
24
43
  const openLightbox = (index) => {
25
44
  setLightboxIndex(index);
26
45
  setLightboxOpen(true);
@@ -35,12 +54,13 @@ function TimelineMessageItem({ item, isLast = false, isSentByViewer = false }) {
35
54
  className: cn("flex w-full min-w-0 flex-1 flex-col gap-1", isSentByViewerFinal && "items-end"),
36
55
  children: [
37
56
  hasText && /* @__PURE__ */ jsx(TimelineItemContent, {
38
- className: cn("block min-w-0 max-w-[300px] break-words rounded-lg px-3.5 py-2.5 text-sm", {
57
+ className: cn("block min-w-0 break-words rounded-lg px-3.5 py-2.5 text-sm", messageWidthClassName, {
39
58
  "bg-co-background-300 text-co-foreground dark:bg-co-background-600": !isSentByViewerFinal,
40
59
  "bg-co-primary text-co-primary-foreground": isSentByViewerFinal,
41
60
  "rounded-br-sm": isLast && isSentByViewerFinal && !hasAttachments,
42
61
  "rounded-bl-sm": isLast && !isSentByViewerFinal && !hasAttachments
43
62
  }),
63
+ markdownRenderers,
44
64
  renderMarkdown: true,
45
65
  text: item.text
46
66
  }),
@@ -106,5 +126,5 @@ function TimelineMessageItem({ item, isLast = false, isSentByViewer = false }) {
106
126
  }
107
127
 
108
128
  //#endregion
109
- export { TimelineMessageItem };
129
+ export { TimelineMessageItem, getSupportMessageWidthClasses };
110
130
  //# sourceMappingURL=timeline-message-item.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"timeline-message-item.js","names":["PrimitiveTimelineItem","Icon"],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":["import { formatFileSize } from \"@cossistant/core\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport { useState } from \"react\";\nimport {\n\tTimelineItem as PrimitiveTimelineItem,\n\tTimelineItemContent,\n\tTimelineItemTimestamp,\n} from \"../../primitives/timeline-item\";\nimport {\n\textractFileParts,\n\textractImageParts,\n} from \"../../primitives/timeline-item-attachments\";\nimport { useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\nimport { ImageLightbox } from \"./image-lightbox\";\n\nexport type TimelineMessageItemProps = {\n\titem: TimelineItem;\n\tisLast?: boolean;\n\tisSentByViewer?: boolean;\n};\n\n/**\n * Message bubble renderer that adapts layout depending on whether the visitor\n * or an agent sent the message.\n */\nexport function TimelineMessageItem({\n\titem,\n\tisLast = false,\n\tisSentByViewer = false,\n}: TimelineMessageItemProps): React.ReactElement {\n\tconst text = useSupportText();\n\tconst [lightboxOpen, setLightboxOpen] = useState(false);\n\tconst [lightboxIndex, setLightboxIndex] = useState(0);\n\n\t// Extract image and file parts\n\tconst images = extractImageParts(item.parts);\n\tconst files = extractFileParts(item.parts);\n\tconst hasAttachments = images.length > 0 || files.length > 0;\n\tconst hasText = item.text && item.text.trim().length > 0;\n\n\tconst openLightbox = (index: number) => {\n\t\tsetLightboxIndex(index);\n\t\tsetLightboxOpen(true);\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<PrimitiveTimelineItem item={item}>\n\t\t\t\t{({ isAI, timestamp }) => {\n\t\t\t\t\t// isSentByViewer defaults to false, meaning messages are treated as received\n\t\t\t\t\t// (left side with background) unless explicitly marked as sent by viewer\n\t\t\t\t\tconst isSentByViewerFinal = isSentByViewer;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"flex w-full gap-2\",\n\t\t\t\t\t\t\t\tisSentByViewerFinal && \"flex-row-reverse\",\n\t\t\t\t\t\t\t\t!isSentByViewerFinal && \"flex-row\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\"flex w-full min-w-0 flex-1 flex-col gap-1\",\n\t\t\t\t\t\t\t\t\tisSentByViewerFinal && \"items-end\"\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{/* Text content */}\n\t\t\t\t\t\t\t\t{hasText && (\n\t\t\t\t\t\t\t\t\t<TimelineItemContent\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"block min-w-0 max-w-[300px] break-words rounded-lg px-3.5 py-2.5 text-sm\",\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground dark:bg-co-background-600\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-primary text-co-primary-foreground\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\"rounded-br-sm\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisLast && isSentByViewerFinal && !hasAttachments,\n\t\t\t\t\t\t\t\t\t\t\t\t\"rounded-bl-sm\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisLast && !isSentByViewerFinal && !hasAttachments,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\trenderMarkdown\n\t\t\t\t\t\t\t\t\t\ttext={item.text}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* Image attachments */}\n\t\t\t\t\t\t\t\t{images.length > 0 && (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"flex flex-wrap gap-2\",\n\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal && \"justify-end\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{images.map((image, index) => (\n\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"group relative overflow-hidden rounded-lg focus:outline-none focus:ring-2 focus:ring-co-primary/50\"\n\t\t\t\t\t\t\t\t\t\t\t\tkey={image.url}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => openLightbox(index)}\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{/* biome-ignore lint/performance/noImgElement: React package, not Next.js specific */}\n\t\t\t\t\t\t\t\t\t\t\t\t{/* biome-ignore lint/nursery/useImageSize: Dynamic image dimensions not known at render time */}\n\t\t\t\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\t\t\t\talt={image.filename || `Image ${index + 1}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"max-h-[150px] max-w-[200px] cursor-pointer rounded-lg object-cover transition-transform group-hover:scale-105\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tsrc={image.url}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* File attachments */}\n\t\t\t\t\t\t\t\t{files.length > 0 && (\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t\t\t\t\t{files.map((file) => (\n\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"flex items-center gap-2 rounded-lg px-3 py-2 text-xs transition-colors\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground hover:bg-co-background-400 dark:bg-co-background-600 dark:hover:bg-co-background-500\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-primary/80 text-co-primary-foreground hover:bg-co-primary\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tdownload={file.filename}\n\t\t\t\t\t\t\t\t\t\t\t\thref={file.url}\n\t\t\t\t\t\t\t\t\t\t\t\tkey={file.url}\n\t\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon className=\"h-4 w-4 shrink-0\" name=\"file\" />\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex-1 truncate font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{file.filename || \"Download file\"}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t{file.size && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-co-muted-foreground opacity-70\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(file.size)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{isLast && (\n\t\t\t\t\t\t\t\t\t<TimelineItemTimestamp\n\t\t\t\t\t\t\t\t\t\tclassName=\"px-1 text-co-muted-foreground text-xs\"\n\t\t\t\t\t\t\t\t\t\ttimestamp={timestamp}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{() => (\n\t\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t\t{timestamp.toLocaleTimeString([], {\n\t\t\t\t\t\t\t\t\t\t\t\t\thour: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tminute: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t{isAI &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t` ${text(\"component.message.timestamp.aiIndicator\")}`}\n\t\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</TimelineItemTimestamp>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t}}\n\t\t\t</PrimitiveTimelineItem>\n\n\t\t\t{/* Lightbox for images */}\n\t\t\t{images.length > 0 && (\n\t\t\t\t<ImageLightbox\n\t\t\t\t\timages={images}\n\t\t\t\t\tinitialIndex={lightboxIndex}\n\t\t\t\t\tisOpen={lightboxOpen}\n\t\t\t\t\tonClose={() => setLightboxOpen(false)}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,SAAgB,oBAAoB,EACnC,MACA,SAAS,OACT,iBAAiB,SAC+B;CAChD,MAAM,OAAO,gBAAgB;CAC7B,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CACvD,MAAM,CAAC,eAAe,oBAAoB,SAAS,EAAE;CAGrD,MAAM,SAAS,kBAAkB,KAAK,MAAM;CAC5C,MAAM,QAAQ,iBAAiB,KAAK,MAAM;CAC1C,MAAM,iBAAiB,OAAO,SAAS,KAAK,MAAM,SAAS;CAC3D,MAAM,UAAU,KAAK,QAAQ,KAAK,KAAK,MAAM,CAAC,SAAS;CAEvD,MAAM,gBAAgB,UAAkB;AACvC,mBAAiB,MAAM;AACvB,kBAAgB,KAAK;;AAGtB,QACC,4CACC,oBAACA;EAA4B;aAC1B,EAAE,MAAM,gBAAgB;GAGzB,MAAM,sBAAsB;AAE5B,UACC,oBAAC;IACA,WAAW,GACV,qBACA,uBAAuB,oBACvB,CAAC,uBAAuB,WACxB;cAED,qBAAC;KACA,WAAW,GACV,6CACA,uBAAuB,YACvB;;MAGA,WACA,oBAAC;OACA,WAAW,GACV,4EACA;QACC,qEACC,CAAC;QACF,4CACC;QACD,iBACC,UAAU,uBAAuB,CAAC;QACnC,iBACC,UAAU,CAAC,uBAAuB,CAAC;QACpC,CACD;OACD;OACA,MAAM,KAAK;QACV;MAIF,OAAO,SAAS,KAChB,oBAAC;OACA,WAAW,GACV,wBACA,uBAAuB,cACvB;iBAEA,OAAO,KAAK,OAAO,UACnB,oBAAC;QACA,WAAU;QAEV,eAAe,aAAa,MAAM;QAClC,MAAK;kBAIL,oBAAC;SACA,KAAK,MAAM,YAAY,SAAS,QAAQ;SACxC,WAAU;SACV,SAAQ;SACR,KAAK,MAAM;UACV;UAXG,MAAM,IAYH,CACR;QACG;MAIN,MAAM,SAAS,KACf,oBAAC;OAAI,WAAU;iBACb,MAAM,KAAK,SACX,qBAAC;QACA,WAAW,GACV,0EACA;SACC,gIACC,CAAC;SACF,mEACC;SACD,CACD;QACD,UAAU,KAAK;QACf,MAAM,KAAK;QAEX,KAAI;QACJ,QAAO;;SAEP,oBAACC;UAAK,WAAU;UAAmB,MAAK;WAAS;SACjD,oBAAC;UAAK,WAAU;oBACd,KAAK,YAAY;WACZ;SACN,KAAK,QACL,oBAAC;UAAK,WAAU;oBACd,eAAe,KAAK,KAAK;WACpB;;UAXH,KAAK,IAaP,CACH;QACG;MAGN,UACA,oBAAC;OACA,WAAU;OACC;uBAGV,4CACE,UAAU,mBAAmB,EAAE,EAAE;QACjC,MAAM;QACN,QAAQ;QACR,CAAC,EACD,QACA,IAAI,KAAK,0CAA0C,MAClD;QAEmB;;MAEpB;KACD;;GAGe,EAGvB,OAAO,SAAS,KAChB,oBAAC;EACQ;EACR,cAAc;EACd,QAAQ;EACR,eAAe,gBAAgB,MAAM;GACpC,IAED"}
1
+ {"version":3,"file":"timeline-message-item.js","names":["PrimitiveTimelineItem","Icon"],"sources":["../../../src/support/components/timeline-message-item.tsx"],"sourcesContent":["import { formatFileSize } from \"@cossistant/core\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport { useMemo, useState } from \"react\";\nimport {\n\tTimelineItem as PrimitiveTimelineItem,\n\tTimelineItemContent,\n\ttype TimelineItemContentMarkdownRenderers,\n\tTimelineItemTimestamp,\n} from \"../../primitives/timeline-item\";\nimport {\n\textractFileParts,\n\textractImageParts,\n} from \"../../primitives/timeline-item-attachments\";\nimport { hasExpandedTimelineContent } from \"../../primitives/timeline-message-layout\";\nimport { useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\nimport { ImageLightbox } from \"./image-lightbox\";\nimport { TimelineCodeBlock } from \"./timeline-code-block\";\nimport { TimelineCommandBlock } from \"./timeline-command-block\";\n\nexport type TimelineMessageItemProps = {\n\titem: TimelineItem;\n\tisLast?: boolean;\n\tisSentByViewer?: boolean;\n};\n\nexport function getSupportMessageWidthClasses(\n\ttext: string | null | undefined\n): string {\n\treturn hasExpandedTimelineContent(text)\n\t\t? \"w-full max-w-full\"\n\t\t: \"max-w-[300px]\";\n}\n\n/**\n * Message bubble renderer that adapts layout depending on whether the visitor\n * or an agent sent the message.\n */\nexport function TimelineMessageItem({\n\titem,\n\tisLast = false,\n\tisSentByViewer = false,\n}: TimelineMessageItemProps): React.ReactElement {\n\tconst text = useSupportText();\n\tconst [lightboxOpen, setLightboxOpen] = useState(false);\n\tconst [lightboxIndex, setLightboxIndex] = useState(0);\n\n\t// Extract image and file parts\n\tconst images = extractImageParts(item.parts);\n\tconst files = extractFileParts(item.parts);\n\tconst hasAttachments = images.length > 0 || files.length > 0;\n\tconst hasText = item.text && item.text.trim().length > 0;\n\tconst messageWidthClassName = getSupportMessageWidthClasses(item.text);\n\tconst markdownRenderers = useMemo<TimelineItemContentMarkdownRenderers>(\n\t\t() => ({\n\t\t\tcodeBlock: ({ code, fileName, language }) => (\n\t\t\t\t<TimelineCodeBlock\n\t\t\t\t\tcode={code}\n\t\t\t\t\tfileName={fileName}\n\t\t\t\t\tlanguage={language}\n\t\t\t\t/>\n\t\t\t),\n\t\t\tcommandBlock: ({ commands }) => (\n\t\t\t\t<TimelineCommandBlock commands={commands} />\n\t\t\t),\n\t\t\tinlineCode: ({ code }) => (\n\t\t\t\t<code className=\"rounded bg-co-background-300 px-1 py-0.5 text-xs\">\n\t\t\t\t\t{code}\n\t\t\t\t</code>\n\t\t\t),\n\t\t}),\n\t\t[]\n\t);\n\n\tconst openLightbox = (index: number) => {\n\t\tsetLightboxIndex(index);\n\t\tsetLightboxOpen(true);\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<PrimitiveTimelineItem item={item}>\n\t\t\t\t{({ isAI, timestamp }) => {\n\t\t\t\t\t// isSentByViewer defaults to false, meaning messages are treated as received\n\t\t\t\t\t// (left side with background) unless explicitly marked as sent by viewer\n\t\t\t\t\tconst isSentByViewerFinal = isSentByViewer;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"flex w-full gap-2\",\n\t\t\t\t\t\t\t\tisSentByViewerFinal && \"flex-row-reverse\",\n\t\t\t\t\t\t\t\t!isSentByViewerFinal && \"flex-row\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\"flex w-full min-w-0 flex-1 flex-col gap-1\",\n\t\t\t\t\t\t\t\t\tisSentByViewerFinal && \"items-end\"\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{/* Text content */}\n\t\t\t\t\t\t\t\t{hasText && (\n\t\t\t\t\t\t\t\t\t<TimelineItemContent\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"block min-w-0 break-words rounded-lg px-3.5 py-2.5 text-sm\",\n\t\t\t\t\t\t\t\t\t\t\tmessageWidthClassName,\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground dark:bg-co-background-600\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-primary text-co-primary-foreground\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\"rounded-br-sm\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisLast && isSentByViewerFinal && !hasAttachments,\n\t\t\t\t\t\t\t\t\t\t\t\t\"rounded-bl-sm\":\n\t\t\t\t\t\t\t\t\t\t\t\t\tisLast && !isSentByViewerFinal && !hasAttachments,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tmarkdownRenderers={markdownRenderers}\n\t\t\t\t\t\t\t\t\t\trenderMarkdown\n\t\t\t\t\t\t\t\t\t\ttext={item.text}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* Image attachments */}\n\t\t\t\t\t\t\t\t{images.length > 0 && (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"flex flex-wrap gap-2\",\n\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal && \"justify-end\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{images.map((image, index) => (\n\t\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"group relative overflow-hidden rounded-lg focus:outline-none focus:ring-2 focus:ring-co-primary/50\"\n\t\t\t\t\t\t\t\t\t\t\t\tkey={image.url}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => openLightbox(index)}\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{/* biome-ignore lint/performance/noImgElement: React package, not Next.js specific */}\n\t\t\t\t\t\t\t\t\t\t\t\t{/* biome-ignore lint/nursery/useImageSize: Dynamic image dimensions not known at render time */}\n\t\t\t\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\t\t\t\talt={image.filename || `Image ${index + 1}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"max-h-[150px] max-w-[200px] cursor-pointer rounded-lg object-cover transition-transform group-hover:scale-105\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tsrc={image.url}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* File attachments */}\n\t\t\t\t\t\t\t\t{files.length > 0 && (\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t\t\t\t\t{files.map((file) => (\n\t\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"flex items-center gap-2 rounded-lg px-3 py-2 text-xs transition-colors\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-background-300 text-co-foreground hover:bg-co-background-400 dark:bg-co-background-600 dark:hover:bg-co-background-500\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!isSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"bg-co-primary/80 text-co-primary-foreground hover:bg-co-primary\":\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisSentByViewerFinal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tdownload={file.filename}\n\t\t\t\t\t\t\t\t\t\t\t\thref={file.url}\n\t\t\t\t\t\t\t\t\t\t\t\tkey={file.url}\n\t\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon className=\"h-4 w-4 shrink-0\" name=\"file\" />\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex-1 truncate font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{file.filename || \"Download file\"}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t{file.size && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-co-muted-foreground opacity-70\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{formatFileSize(file.size)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{isLast && (\n\t\t\t\t\t\t\t\t\t<TimelineItemTimestamp\n\t\t\t\t\t\t\t\t\t\tclassName=\"px-1 text-co-muted-foreground text-xs\"\n\t\t\t\t\t\t\t\t\t\ttimestamp={timestamp}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{() => (\n\t\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t\t{timestamp.toLocaleTimeString([], {\n\t\t\t\t\t\t\t\t\t\t\t\t\thour: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tminute: \"2-digit\",\n\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t{isAI &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t` ${text(\"component.message.timestamp.aiIndicator\")}`}\n\t\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</TimelineItemTimestamp>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t}}\n\t\t\t</PrimitiveTimelineItem>\n\n\t\t\t{/* Lightbox for images */}\n\t\t\t{images.length > 0 && (\n\t\t\t\t<ImageLightbox\n\t\t\t\t\timages={images}\n\t\t\t\t\tinitialIndex={lightboxIndex}\n\t\t\t\t\tisOpen={lightboxOpen}\n\t\t\t\t\tonClose={() => setLightboxOpen(false)}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;AA4BA,SAAgB,8BACf,MACS;AACT,QAAO,2BAA2B,KAAK,GACpC,sBACA;;;;;;AAOJ,SAAgB,oBAAoB,EACnC,MACA,SAAS,OACT,iBAAiB,SAC+B;CAChD,MAAM,OAAO,gBAAgB;CAC7B,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CACvD,MAAM,CAAC,eAAe,oBAAoB,SAAS,EAAE;CAGrD,MAAM,SAAS,kBAAkB,KAAK,MAAM;CAC5C,MAAM,QAAQ,iBAAiB,KAAK,MAAM;CAC1C,MAAM,iBAAiB,OAAO,SAAS,KAAK,MAAM,SAAS;CAC3D,MAAM,UAAU,KAAK,QAAQ,KAAK,KAAK,MAAM,CAAC,SAAS;CACvD,MAAM,wBAAwB,8BAA8B,KAAK,KAAK;CACtE,MAAM,oBAAoB,eAClB;EACN,YAAY,EAAE,MAAM,UAAU,eAC7B,oBAAC;GACM;GACI;GACA;IACT;EAEH,eAAe,EAAE,eAChB,oBAAC,wBAA+B,WAAY;EAE7C,aAAa,EAAE,WACd,oBAAC;GAAK,WAAU;aACd;IACK;EAER,GACD,EAAE,CACF;CAED,MAAM,gBAAgB,UAAkB;AACvC,mBAAiB,MAAM;AACvB,kBAAgB,KAAK;;AAGtB,QACC,4CACC,oBAACA;EAA4B;aAC1B,EAAE,MAAM,gBAAgB;GAGzB,MAAM,sBAAsB;AAE5B,UACC,oBAAC;IACA,WAAW,GACV,qBACA,uBAAuB,oBACvB,CAAC,uBAAuB,WACxB;cAED,qBAAC;KACA,WAAW,GACV,6CACA,uBAAuB,YACvB;;MAGA,WACA,oBAAC;OACA,WAAW,GACV,8DACA,uBACA;QACC,qEACC,CAAC;QACF,4CACC;QACD,iBACC,UAAU,uBAAuB,CAAC;QACnC,iBACC,UAAU,CAAC,uBAAuB,CAAC;QACpC,CACD;OACkB;OACnB;OACA,MAAM,KAAK;QACV;MAIF,OAAO,SAAS,KAChB,oBAAC;OACA,WAAW,GACV,wBACA,uBAAuB,cACvB;iBAEA,OAAO,KAAK,OAAO,UACnB,oBAAC;QACA,WAAU;QAEV,eAAe,aAAa,MAAM;QAClC,MAAK;kBAIL,oBAAC;SACA,KAAK,MAAM,YAAY,SAAS,QAAQ;SACxC,WAAU;SACV,SAAQ;SACR,KAAK,MAAM;UACV;UAXG,MAAM,IAYH,CACR;QACG;MAIN,MAAM,SAAS,KACf,oBAAC;OAAI,WAAU;iBACb,MAAM,KAAK,SACX,qBAAC;QACA,WAAW,GACV,0EACA;SACC,gIACC,CAAC;SACF,mEACC;SACD,CACD;QACD,UAAU,KAAK;QACf,MAAM,KAAK;QAEX,KAAI;QACJ,QAAO;;SAEP,oBAACC;UAAK,WAAU;UAAmB,MAAK;WAAS;SACjD,oBAAC;UAAK,WAAU;oBACd,KAAK,YAAY;WACZ;SACN,KAAK,QACL,oBAAC;UAAK,WAAU;oBACd,eAAe,KAAK,KAAK;WACpB;;UAXH,KAAK,IAaP,CACH;QACG;MAGN,UACA,oBAAC;OACA,WAAU;OACC;uBAGV,4CACE,UAAU,mBAAmB,EAAE,EAAE;QACjC,MAAM;QACN,QAAQ;QACR,CAAC,EACD,QACA,IAAI,KAAK,0CAA0C,MAClD;QAEmB;;MAEpB;KACD;;GAGe,EAGvB,OAAO,SAAS,KAChB,oBAAC;EACQ;EACR,cAAc;EACd,QAAQ;EACR,eAAe,gBAAgB,MAAM;GACpC,IAED"}
@@ -11,7 +11,7 @@ import { WebSocketContextValue, WebSocketProvider, useWebSocket } from "./contex
11
11
  import { useSupportConfig, useSupportNavigation, useSupportStore } from "./store/support-store.js";
12
12
  import "./store/index.js";
13
13
  import * as React$1 from "react";
14
- import * as _cossistant_core0 from "@cossistant/core";
14
+ import * as _cossistant_core7 from "@cossistant/core";
15
15
  import { DefaultRoutes, NavigationState, RouteRegistry, SupportPage as SupportPageType } from "@cossistant/core";
16
16
  import { DefaultMessage } from "@cossistant/types";
17
17
 
@@ -179,10 +179,10 @@ type SupportRouterProps = {
179
179
  */
180
180
  children?: React$1.ReactNode;
181
181
  };
182
- type SupportPageProps<K extends keyof _cossistant_core0.RouteRegistry = keyof _cossistant_core0.RouteRegistry> = {
182
+ type SupportPageProps<K extends keyof _cossistant_core7.RouteRegistry = keyof _cossistant_core7.RouteRegistry> = {
183
183
  name: K;
184
184
  component: React$1.ComponentType<{
185
- params?: _cossistant_core0.RouteRegistry[K];
185
+ params?: _cossistant_core7.RouteRegistry[K];
186
186
  }>;
187
187
  };
188
188
  type SupportRootProps = {
@@ -250,7 +250,7 @@ declare const Support: (<Locale extends string = SupportLocale>(props: SupportPr
250
250
  } & React$1.RefAttributes<HTMLButtonElement>>;
251
251
  Content: React$1.FC<SupportContentProps>;
252
252
  Router: React$1.FC<SupportRouterProps>;
253
- Page: <K extends keyof _cossistant_core0.RouteRegistry>(_props: PageProps<K>) => null;
253
+ Page: <K extends keyof _cossistant_core7.RouteRegistry>(_props: PageProps<K>) => null;
254
254
  Header: React$1.FC<SlotProps>;
255
255
  Footer: React$1.FC<SlotProps>;
256
256
  };
@@ -1,4 +1,4 @@
1
- import * as _cossistant_core3 from "@cossistant/core";
1
+ import * as _cossistant_core0 from "@cossistant/core";
2
2
  import { SupportConfig, SupportStore, SupportStoreState } from "@cossistant/core";
3
3
 
4
4
  //#region src/support/store/support-store.d.ts
@@ -43,15 +43,15 @@ declare const useSupportConfig: () => UseSupportConfigResult;
43
43
  * const { navigate, goBack, page, params } = useSupportNavigation();
44
44
  */
45
45
  declare const useSupportNavigation: () => {
46
- current: _cossistant_core3.NavigationState<_cossistant_core3.RouteRegistry>;
46
+ current: _cossistant_core0.NavigationState<_cossistant_core0.RouteRegistry>;
47
47
  page: "HOME" | "ARTICLES" | "CONVERSATION" | "CONVERSATION_HISTORY";
48
48
  params: {
49
49
  conversationId: string;
50
50
  initialMessage?: string;
51
51
  } | undefined;
52
- previousPages: _cossistant_core3.NavigationState<_cossistant_core3.RouteRegistry>[];
53
- navigate: (state: _cossistant_core3.NavigationState<_cossistant_core3.RouteRegistry>) => void;
54
- replace: (state: _cossistant_core3.NavigationState<_cossistant_core3.RouteRegistry>) => void;
52
+ previousPages: _cossistant_core0.NavigationState<_cossistant_core0.RouteRegistry>[];
53
+ navigate: (state: _cossistant_core0.NavigationState<_cossistant_core0.RouteRegistry>) => void;
54
+ replace: (state: _cossistant_core0.NavigationState<_cossistant_core0.RouteRegistry>) => void;
55
55
  goBack: () => void;
56
56
  canGoBack: boolean;
57
57
  };
@@ -4,7 +4,7 @@
4
4
  * This is used to check if metadata has changed without comparing the entire object.
5
5
  * Returns a short hash string (first 8 characters of SHA256).
6
6
  *
7
- * Note: This uses SubtleCrypto API in the browser and crypto module in Node.js
7
+ * Uses Web Crypto when available and falls back to a deterministic non-crypto hash.
8
8
  */
9
9
  declare function computeMetadataHash(metadata: Record<string, unknown> | null | undefined): Promise<string>;
10
10
  //#endregion