@happyvertical/smrt-chat 0.30.0

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 (169) hide show
  1. package/AGENTS.md +35 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +163 -0
  5. package/dist/__smrt-register__.d.ts +2 -0
  6. package/dist/__smrt-register__.d.ts.map +1 -0
  7. package/dist/chunks/ChatService-Dpzc1Pa5.js +2044 -0
  8. package/dist/chunks/ChatService-Dpzc1Pa5.js.map +1 -0
  9. package/dist/collections/AgentSessionCollection.d.ts +57 -0
  10. package/dist/collections/AgentSessionCollection.d.ts.map +1 -0
  11. package/dist/collections/ChatMessageCollection.d.ts +79 -0
  12. package/dist/collections/ChatMessageCollection.d.ts.map +1 -0
  13. package/dist/collections/ChatParticipantCollection.d.ts +26 -0
  14. package/dist/collections/ChatParticipantCollection.d.ts.map +1 -0
  15. package/dist/collections/ChatReactionCollection.d.ts +23 -0
  16. package/dist/collections/ChatReactionCollection.d.ts.map +1 -0
  17. package/dist/collections/ChatRoomCollection.d.ts +43 -0
  18. package/dist/collections/ChatRoomCollection.d.ts.map +1 -0
  19. package/dist/collections/ChatThreadCollection.d.ts +9 -0
  20. package/dist/collections/ChatThreadCollection.d.ts.map +1 -0
  21. package/dist/index.d.ts +5 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +18 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/internal/agent-runtime.d.ts +16 -0
  26. package/dist/internal/agent-runtime.d.ts.map +1 -0
  27. package/dist/internal/agent-runtime.js +5 -0
  28. package/dist/internal/agent-runtime.js.map +1 -0
  29. package/dist/manifest.json +2811 -0
  30. package/dist/models/AgentSession.d.ts +70 -0
  31. package/dist/models/AgentSession.d.ts.map +1 -0
  32. package/dist/models/ChatMessage.d.ts +55 -0
  33. package/dist/models/ChatMessage.d.ts.map +1 -0
  34. package/dist/models/ChatParticipant.d.ts +32 -0
  35. package/dist/models/ChatParticipant.d.ts.map +1 -0
  36. package/dist/models/ChatReaction.d.ts +19 -0
  37. package/dist/models/ChatReaction.d.ts.map +1 -0
  38. package/dist/models/ChatRoom.d.ts +44 -0
  39. package/dist/models/ChatRoom.d.ts.map +1 -0
  40. package/dist/models/ChatThread.d.ts +24 -0
  41. package/dist/models/ChatThread.d.ts.map +1 -0
  42. package/dist/models/index.d.ts +7 -0
  43. package/dist/models/index.d.ts.map +1 -0
  44. package/dist/playground.d.ts +2 -0
  45. package/dist/playground.d.ts.map +1 -0
  46. package/dist/playground.js +166 -0
  47. package/dist/playground.js.map +1 -0
  48. package/dist/services/ChatService.d.ts +390 -0
  49. package/dist/services/ChatService.d.ts.map +1 -0
  50. package/dist/services/index.d.ts +2 -0
  51. package/dist/services/index.d.ts.map +1 -0
  52. package/dist/smrt-knowledge.json +1507 -0
  53. package/dist/svelte/components/agent/AgentChat.svelte +542 -0
  54. package/dist/svelte/components/agent/AgentChat.svelte.d.ts +21 -0
  55. package/dist/svelte/components/agent/AgentChat.svelte.d.ts.map +1 -0
  56. package/dist/svelte/components/agent/AgentSelector.svelte +175 -0
  57. package/dist/svelte/components/agent/AgentSelector.svelte.d.ts +11 -0
  58. package/dist/svelte/components/agent/AgentSelector.svelte.d.ts.map +1 -0
  59. package/dist/svelte/components/agent/AgentSessionPanel.svelte +322 -0
  60. package/dist/svelte/components/agent/AgentSessionPanel.svelte.d.ts +15 -0
  61. package/dist/svelte/components/agent/AgentSessionPanel.svelte.d.ts.map +1 -0
  62. package/dist/svelte/components/agent/ToolCallDisplay.svelte +335 -0
  63. package/dist/svelte/components/agent/ToolCallDisplay.svelte.d.ts +9 -0
  64. package/dist/svelte/components/agent/ToolCallDisplay.svelte.d.ts.map +1 -0
  65. package/dist/svelte/components/agent/message-blocks.d.ts +12 -0
  66. package/dist/svelte/components/agent/message-blocks.d.ts.map +1 -0
  67. package/dist/svelte/components/agent/message-blocks.js +41 -0
  68. package/dist/svelte/components/agent/message-blocks.test.js +31 -0
  69. package/dist/svelte/components/dialogs/RoomCreateDialog.svelte +403 -0
  70. package/dist/svelte/components/dialogs/RoomCreateDialog.svelte.d.ts +16 -0
  71. package/dist/svelte/components/dialogs/RoomCreateDialog.svelte.d.ts.map +1 -0
  72. package/dist/svelte/components/dialogs/SearchMessages.svelte +457 -0
  73. package/dist/svelte/components/dialogs/SearchMessages.svelte.d.ts +17 -0
  74. package/dist/svelte/components/dialogs/SearchMessages.svelte.d.ts.map +1 -0
  75. package/dist/svelte/components/layout/ChatLayout.svelte +150 -0
  76. package/dist/svelte/components/layout/ChatLayout.svelte.d.ts +18 -0
  77. package/dist/svelte/components/layout/ChatLayout.svelte.d.ts.map +1 -0
  78. package/dist/svelte/components/layout/MemberList.svelte +389 -0
  79. package/dist/svelte/components/layout/MemberList.svelte.d.ts +11 -0
  80. package/dist/svelte/components/layout/MemberList.svelte.d.ts.map +1 -0
  81. package/dist/svelte/components/layout/RoomHeader.svelte +241 -0
  82. package/dist/svelte/components/layout/RoomHeader.svelte.d.ts +15 -0
  83. package/dist/svelte/components/layout/RoomHeader.svelte.d.ts.map +1 -0
  84. package/dist/svelte/components/layout/RoomList.svelte +471 -0
  85. package/dist/svelte/components/layout/RoomList.svelte.d.ts +15 -0
  86. package/dist/svelte/components/layout/RoomList.svelte.d.ts.map +1 -0
  87. package/dist/svelte/components/messages/MessageInput.svelte +232 -0
  88. package/dist/svelte/components/messages/MessageInput.svelte.d.ts +20 -0
  89. package/dist/svelte/components/messages/MessageInput.svelte.d.ts.map +1 -0
  90. package/dist/svelte/components/messages/MessageItem.svelte +431 -0
  91. package/dist/svelte/components/messages/MessageItem.svelte.d.ts +19 -0
  92. package/dist/svelte/components/messages/MessageItem.svelte.d.ts.map +1 -0
  93. package/dist/svelte/components/messages/MessageList.svelte +129 -0
  94. package/dist/svelte/components/messages/MessageList.svelte.d.ts +17 -0
  95. package/dist/svelte/components/messages/MessageList.svelte.d.ts.map +1 -0
  96. package/dist/svelte/components/messages/ThreadPanel.svelte +156 -0
  97. package/dist/svelte/components/messages/ThreadPanel.svelte.d.ts +17 -0
  98. package/dist/svelte/components/messages/ThreadPanel.svelte.d.ts.map +1 -0
  99. package/dist/svelte/components/messages/__tests__/MessageInput.test.js +38 -0
  100. package/dist/svelte/components/shared/Avatar.svelte +30 -0
  101. package/dist/svelte/components/shared/Avatar.svelte.d.ts +14 -0
  102. package/dist/svelte/components/shared/Avatar.svelte.d.ts.map +1 -0
  103. package/dist/svelte/components/shared/FileUpload.svelte +382 -0
  104. package/dist/svelte/components/shared/FileUpload.svelte.d.ts +14 -0
  105. package/dist/svelte/components/shared/FileUpload.svelte.d.ts.map +1 -0
  106. package/dist/svelte/components/shared/LinkPreview.svelte +108 -0
  107. package/dist/svelte/components/shared/LinkPreview.svelte.d.ts +18 -0
  108. package/dist/svelte/components/shared/LinkPreview.svelte.d.ts.map +1 -0
  109. package/dist/svelte/components/shared/MentionAutocomplete.svelte +168 -0
  110. package/dist/svelte/components/shared/MentionAutocomplete.svelte.d.ts +18 -0
  111. package/dist/svelte/components/shared/MentionAutocomplete.svelte.d.ts.map +1 -0
  112. package/dist/svelte/components/shared/MessageBubble.svelte +81 -0
  113. package/dist/svelte/components/shared/MessageBubble.svelte.d.ts +16 -0
  114. package/dist/svelte/components/shared/MessageBubble.svelte.d.ts.map +1 -0
  115. package/dist/svelte/components/shared/ReactionPicker.svelte +103 -0
  116. package/dist/svelte/components/shared/ReactionPicker.svelte.d.ts +10 -0
  117. package/dist/svelte/components/shared/ReactionPicker.svelte.d.ts.map +1 -0
  118. package/dist/svelte/components/shared/ReadReceipts.svelte +127 -0
  119. package/dist/svelte/components/shared/ReadReceipts.svelte.d.ts +13 -0
  120. package/dist/svelte/components/shared/ReadReceipts.svelte.d.ts.map +1 -0
  121. package/dist/svelte/components/shared/TypingIndicator.svelte +90 -0
  122. package/dist/svelte/components/shared/TypingIndicator.svelte.d.ts +12 -0
  123. package/dist/svelte/components/shared/TypingIndicator.svelte.d.ts.map +1 -0
  124. package/dist/svelte/components/shared/UserPresence.svelte +65 -0
  125. package/dist/svelte/components/shared/UserPresence.svelte.d.ts +13 -0
  126. package/dist/svelte/components/shared/UserPresence.svelte.d.ts.map +1 -0
  127. package/dist/svelte/components/shared/__tests__/Avatar.test.js +20 -0
  128. package/dist/svelte/components/shared/__tests__/LinkPreview.test.js +29 -0
  129. package/dist/svelte/components/shared/__tests__/MessageBubble.test.js +21 -0
  130. package/dist/svelte/components/shared/__tests__/ReactionPicker.test.js +35 -0
  131. package/dist/svelte/components/shared/__tests__/ReadReceipts.test.js +28 -0
  132. package/dist/svelte/components/shared/__tests__/TypingIndicator.test.js +27 -0
  133. package/dist/svelte/components/shared/__tests__/UserPresence.test.js +23 -0
  134. package/dist/svelte/components/tabs/ChatTab.svelte +240 -0
  135. package/dist/svelte/components/tabs/ChatTab.svelte.d.ts +21 -0
  136. package/dist/svelte/components/tabs/ChatTab.svelte.d.ts.map +1 -0
  137. package/dist/svelte/components/tabs/ChatTabList.svelte +158 -0
  138. package/dist/svelte/components/tabs/ChatTabList.svelte.d.ts +13 -0
  139. package/dist/svelte/components/tabs/ChatTabList.svelte.d.ts.map +1 -0
  140. package/dist/svelte/components/tabs/ChatTabs.svelte +88 -0
  141. package/dist/svelte/components/tabs/ChatTabs.svelte.d.ts +21 -0
  142. package/dist/svelte/components/tabs/ChatTabs.svelte.d.ts.map +1 -0
  143. package/dist/svelte/components/tabs/MiniChat.svelte +253 -0
  144. package/dist/svelte/components/tabs/MiniChat.svelte.d.ts +15 -0
  145. package/dist/svelte/components/tabs/MiniChat.svelte.d.ts.map +1 -0
  146. package/dist/svelte/i18n.d.ts +51 -0
  147. package/dist/svelte/i18n.d.ts.map +1 -0
  148. package/dist/svelte/i18n.js +72 -0
  149. package/dist/svelte/i18n.messages.d.ts +50 -0
  150. package/dist/svelte/i18n.messages.d.ts.map +1 -0
  151. package/dist/svelte/i18n.messages.js +69 -0
  152. package/dist/svelte/index.d.ts +48 -0
  153. package/dist/svelte/index.d.ts.map +1 -0
  154. package/dist/svelte/index.js +117 -0
  155. package/dist/svelte/playground.d.ts +171 -0
  156. package/dist/svelte/playground.d.ts.map +1 -0
  157. package/dist/svelte/playground.js +161 -0
  158. package/dist/svelte/types.d.ts +116 -0
  159. package/dist/svelte/types.d.ts.map +1 -0
  160. package/dist/svelte/types.js +1 -0
  161. package/dist/types.d.ts +99 -0
  162. package/dist/types.d.ts.map +1 -0
  163. package/dist/types.js +2 -0
  164. package/dist/types.js.map +1 -0
  165. package/dist/ui.d.ts +4 -0
  166. package/dist/ui.d.ts.map +1 -0
  167. package/dist/ui.js +92 -0
  168. package/dist/ui.js.map +1 -0
  169. package/package.json +95 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageItem.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/messages/MessageItem.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMtD,MAAM,WAAW,KAAK;IACpB,6BAA6B;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,wDAAwD;IACxD,KAAK,EAAE,OAAO,CAAC;IACf,qBAAqB;IACrB,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,qBAAqB;IACrB,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,oBAAoB;IACpB,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,sBAAsB;IACtB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAyJD,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,129 @@
1
+ <script lang="ts">
2
+ /**
3
+ * MessageList - Scrollable message feed
4
+ * Renders MessageItem for each message, grouped by date.
5
+ * Supports infinite scroll via onloadmore callback.
6
+ */
7
+
8
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
9
+ import { M } from '../../i18n.messages.js';
10
+ import type { ChatMessageData } from '../../types.js';
11
+ import MessageItem from './MessageItem.svelte';
12
+
13
+ const { t } = useI18n();
14
+
15
+ export interface Props {
16
+ /** Messages to display */
17
+ messages: ChatMessageData[];
18
+ /** Current user's profile ID to determine own messages */
19
+ currentProfileId: string;
20
+ /** Load more messages (infinite scroll) */
21
+ onloadmore?: () => void;
22
+ /** Reply to a message */
23
+ onreply?: (id: string) => void;
24
+ /** React to a message */
25
+ onreact?: (id: string, emoji: string) => void;
26
+ }
27
+
28
+ const { messages, currentProfileId, onloadmore, onreply, onreact }: Props =
29
+ $props();
30
+
31
+ let scrollContainer: HTMLDivElement | undefined = $state();
32
+
33
+ /** Group messages by date for date separator headers */
34
+ const groupedMessages = $derived.by(() => {
35
+ const groups: Array<{ dateLabel: string; messages: ChatMessageData[] }> = [];
36
+ let currentDate = '';
37
+
38
+ for (const msg of messages) {
39
+ const d =
40
+ msg.createdAt instanceof Date ? msg.createdAt : new Date(msg.createdAt);
41
+ const dateStr = d.toLocaleDateString(undefined, {
42
+ year: 'numeric',
43
+ month: 'long',
44
+ day: 'numeric',
45
+ });
46
+
47
+ if (dateStr !== currentDate) {
48
+ currentDate = dateStr;
49
+ groups.push({ dateLabel: dateStr, messages: [] });
50
+ }
51
+ groups[groups.length - 1].messages.push(msg);
52
+ }
53
+
54
+ return groups;
55
+ });
56
+
57
+ function handleScroll(event: Event) {
58
+ if (!onloadmore) return;
59
+ const target = event.target as HTMLElement;
60
+ if (target.scrollTop < 60) {
61
+ onloadmore();
62
+ }
63
+ }
64
+ </script>
65
+
66
+ <div
67
+ class="message-list"
68
+ bind:this={scrollContainer}
69
+ onscroll={handleScroll}
70
+ role="log"
71
+ aria-label={t(M['chat.message_list.messages_label'])}
72
+ >
73
+ {#if messages.length === 0}
74
+ <div class="message-list__empty">
75
+ <span>{t(M['chat.message_list.no_messages'])}</span>
76
+ </div>
77
+ {:else}
78
+ {#each groupedMessages as group}
79
+ <div class="message-list__date-separator" role="separator">
80
+ <span class="message-list__date-label">{group.dateLabel}</span>
81
+ </div>
82
+ {#each group.messages as message (message.id)}
83
+ <MessageItem
84
+ {message}
85
+ isOwn={message.senderProfileId === currentProfileId}
86
+ {onreply}
87
+ {onreact}
88
+ />
89
+ {/each}
90
+ {/each}
91
+ {/if}
92
+ </div>
93
+
94
+ <style>
95
+ .message-list {
96
+ display: flex;
97
+ flex-direction: column;
98
+ gap: var(--smrt-spacing-2, 0.375rem);
99
+ overflow-y: auto;
100
+ flex: 1;
101
+ padding: var(--smrt-spacing-4, 1rem) 0;
102
+ min-height: 0;
103
+ }
104
+
105
+ .message-list__empty {
106
+ display: flex;
107
+ align-items: center;
108
+ justify-content: center;
109
+ flex: 1;
110
+ color: var(--smrt-color-on-surface-variant, #43474e);
111
+ font-size: var(--smrt-typography-body-medium-size, 0.875rem);
112
+ }
113
+
114
+ .message-list__date-separator {
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: center;
118
+ padding: var(--smrt-spacing-3, 0.75rem) var(--smrt-spacing-4, 1rem);
119
+ }
120
+
121
+ .message-list__date-label {
122
+ padding: var(--smrt-spacing-1, 0.25rem) var(--smrt-spacing-3, 0.75rem);
123
+ font-size: var(--smrt-typography-body-small-size, 0.75rem);
124
+ color: var(--smrt-color-on-surface-variant, #43474e);
125
+ background: var(--smrt-color-surface-container, #f3f4f6);
126
+ border-radius: var(--smrt-radius-full, 9999px);
127
+ white-space: nowrap;
128
+ }
129
+ </style>
@@ -0,0 +1,17 @@
1
+ import type { ChatMessageData } from '../../types.js';
2
+ export interface Props {
3
+ /** Messages to display */
4
+ messages: ChatMessageData[];
5
+ /** Current user's profile ID to determine own messages */
6
+ currentProfileId: string;
7
+ /** Load more messages (infinite scroll) */
8
+ onloadmore?: () => void;
9
+ /** Reply to a message */
10
+ onreply?: (id: string) => void;
11
+ /** React to a message */
12
+ onreact?: (id: string, emoji: string) => void;
13
+ }
14
+ declare const MessageList: import("svelte").Component<Props, {}, "">;
15
+ type MessageList = ReturnType<typeof MessageList>;
16
+ export default MessageList;
17
+ //# sourceMappingURL=MessageList.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageList.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/messages/MessageList.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,MAAM,WAAW,KAAK;IACpB,0BAA0B;IAC1B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,0DAA0D;IAC1D,gBAAgB,EAAE,MAAM,CAAC;IACzB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,yBAAyB;IACzB,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,yBAAyB;IACzB,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAuED,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,156 @@
1
+ <script lang="ts">
2
+ /**
3
+ * ThreadPanel - Side panel for threaded conversation
4
+ * Shows the root message, thread replies, and an input for new replies.
5
+ */
6
+
7
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
8
+ import { M } from '../../i18n.messages.js';
9
+ import type { ChatMessageData, ChatThreadData } from '../../types.js';
10
+ import MessageInput from './MessageInput.svelte';
11
+ import MessageList from './MessageList.svelte';
12
+
13
+ const { t } = useI18n();
14
+
15
+ export interface Props {
16
+ /** Thread metadata */
17
+ thread: ChatThreadData;
18
+ /** Messages in the thread */
19
+ messages: ChatMessageData[];
20
+ /** Current user's profile ID */
21
+ currentProfileId: string;
22
+ /** Send a reply to the thread */
23
+ onsend: (content: string) => void;
24
+ /** Close the thread panel */
25
+ onclose: () => void;
26
+ }
27
+
28
+ const { thread, messages, currentProfileId, onsend, onclose }: Props = $props();
29
+
30
+ const threadTitle = $derived(thread.title || 'Thread');
31
+ const replyCount = $derived(
32
+ thread.messageCount > 0 ? thread.messageCount - 1 : 0,
33
+ );
34
+ </script>
35
+
36
+ <aside class="thread-panel" aria-label={t(M['chat.thread_panel.thread_label'], { title: threadTitle })}>
37
+ <header class="thread-panel__header">
38
+ <div class="thread-panel__header-text">
39
+ <h3 class="thread-panel__title">{threadTitle}</h3>
40
+ <span class="thread-panel__meta">
41
+ {replyCount} {replyCount === 1 ? 'reply' : 'replies'}
42
+ {#if thread.participantCount > 0}
43
+ &middot; {thread.participantCount} {thread.participantCount === 1 ? 'participant' : 'participants'}
44
+ {/if}
45
+ </span>
46
+ </div>
47
+ {#if thread.isResolved}
48
+ <span class="thread-panel__resolved">Resolved</span>
49
+ {/if}
50
+ <button
51
+ class="thread-panel__close"
52
+ type="button"
53
+ onclick={onclose}
54
+ aria-label={t(M['chat.thread_panel.close'])}
55
+ >
56
+ <svg viewBox="0 0 16 16" width="16" height="16">
57
+ <path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
58
+ </svg>
59
+ </button>
60
+ </header>
61
+
62
+ <div class="thread-panel__messages">
63
+ <MessageList
64
+ {messages}
65
+ {currentProfileId}
66
+ />
67
+ </div>
68
+
69
+ <div class="thread-panel__input">
70
+ <MessageInput
71
+ {onsend}
72
+ placeholder={t(M['chat.thread_panel.reply_placeholder'])}
73
+ />
74
+ </div>
75
+ </aside>
76
+
77
+ <style>
78
+ .thread-panel {
79
+ display: flex;
80
+ flex-direction: column;
81
+ height: 100%;
82
+ width: 100%;
83
+ background: var(--smrt-color-surface, #ffffff);
84
+ border-left: 1px solid var(--smrt-color-outline-variant, #c4c6cf);
85
+ }
86
+
87
+ .thread-panel__header {
88
+ display: flex;
89
+ align-items: center;
90
+ gap: var(--smrt-spacing-3, 0.75rem);
91
+ padding: var(--smrt-spacing-4, 1rem);
92
+ border-bottom: 1px solid var(--smrt-color-outline-variant, #c4c6cf);
93
+ flex-shrink: 0;
94
+ }
95
+
96
+ .thread-panel__header-text {
97
+ flex: 1;
98
+ min-width: 0;
99
+ }
100
+
101
+ .thread-panel__title {
102
+ margin: 0;
103
+ font-size: var(--smrt-typography-body-medium-size, 0.875rem);
104
+ font-weight: var(--smrt-typography-weight-semibold, 600);
105
+ color: var(--smrt-color-on-surface, #1b1b1f);
106
+ white-space: nowrap;
107
+ overflow: hidden;
108
+ text-overflow: ellipsis;
109
+ }
110
+
111
+ .thread-panel__meta {
112
+ font-size: var(--smrt-typography-body-small-size, 0.75rem);
113
+ color: var(--smrt-color-on-surface-variant, #43474e);
114
+ }
115
+
116
+ .thread-panel__resolved {
117
+ padding: var(--smrt-spacing-1, 4px) var(--smrt-spacing-2, 8px);
118
+ font-size: var(--smrt-typography-body-small-size, 0.75rem);
119
+ font-weight: var(--smrt-typography-weight-medium, 500);
120
+ color: var(--smrt-color-on-success-container, #2e7d32);
121
+ background: var(--smrt-color-success-container, #e8f5e9);
122
+ border-radius: var(--smrt-radius-full, 9999px);
123
+ white-space: nowrap;
124
+ flex-shrink: 0;
125
+ }
126
+
127
+ .thread-panel__close {
128
+ display: flex;
129
+ align-items: center;
130
+ justify-content: center;
131
+ width: 32px;
132
+ height: 32px;
133
+ border: none;
134
+ border-radius: var(--smrt-radius-small, 0.25rem);
135
+ background: transparent;
136
+ color: var(--smrt-color-on-surface-variant, #43474e);
137
+ cursor: pointer;
138
+ flex-shrink: 0;
139
+ transition: background var(--smrt-duration-short2, 150ms) var(--smrt-easing-standard, ease);
140
+ }
141
+
142
+ .thread-panel__close:hover {
143
+ background: var(--smrt-color-surface-container-high, #e1e3e8);
144
+ }
145
+
146
+ .thread-panel__messages {
147
+ flex: 1;
148
+ min-height: 0;
149
+ display: flex;
150
+ flex-direction: column;
151
+ }
152
+
153
+ .thread-panel__input {
154
+ flex-shrink: 0;
155
+ }
156
+ </style>
@@ -0,0 +1,17 @@
1
+ import type { ChatMessageData, ChatThreadData } from '../../types.js';
2
+ export interface Props {
3
+ /** Thread metadata */
4
+ thread: ChatThreadData;
5
+ /** Messages in the thread */
6
+ messages: ChatMessageData[];
7
+ /** Current user's profile ID */
8
+ currentProfileId: string;
9
+ /** Send a reply to the thread */
10
+ onsend: (content: string) => void;
11
+ /** Close the thread panel */
12
+ onclose: () => void;
13
+ }
14
+ declare const ThreadPanel: import("svelte").Component<Props, {}, "">;
15
+ type ThreadPanel = ReturnType<typeof ThreadPanel>;
16
+ export default ThreadPanel;
17
+ //# sourceMappingURL=ThreadPanel.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThreadPanel.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/messages/ThreadPanel.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKtE,MAAM,WAAW,KAAK;IACpB,sBAAsB;IACtB,MAAM,EAAE,cAAc,CAAC;IACvB,6BAA6B;IAC7B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,gCAAgC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,iCAAiC;IACjC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,6BAA6B;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAsDD,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,38 @@
1
+ // @vitest-environment jsdom
2
+ /**
3
+ * Component coverage for MessageInput via the shared S11 harness (#1416).
4
+ */
5
+ import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
6
+ import { describe, expect, it, vi } from 'vitest';
7
+ import MessageInput from '../MessageInput.svelte';
8
+ describe('MessageInput', () => {
9
+ it('sends the trimmed content on Enter', async () => {
10
+ const onsend = vi.fn();
11
+ render(MessageInput, { props: { onsend } });
12
+ await userEvent.type(screen.getByLabelText('Message input'), 'Hello{Enter}');
13
+ expect(onsend).toHaveBeenCalledWith('Hello');
14
+ });
15
+ it('does not send empty content', async () => {
16
+ const onsend = vi.fn();
17
+ render(MessageInput, { props: { onsend } });
18
+ await userEvent.type(screen.getByLabelText('Message input'), '{Enter}');
19
+ expect(onsend).not.toHaveBeenCalled();
20
+ });
21
+ it('shows a reply banner and cancels it', async () => {
22
+ const oncancelreply = vi.fn();
23
+ render(MessageInput, {
24
+ props: {
25
+ onsend: vi.fn(),
26
+ replyTo: { id: 'm1', senderName: 'Ada', content: 'earlier message' },
27
+ oncancelreply,
28
+ },
29
+ });
30
+ expect(screen.getByText('Ada')).toBeInTheDocument();
31
+ await userEvent.click(screen.getByRole('button', { name: 'Cancel reply' }));
32
+ expect(oncancelreply).toHaveBeenCalledTimes(1);
33
+ });
34
+ it('is axe-clean', async () => {
35
+ const { container } = render(MessageInput, { props: { onsend: vi.fn() } });
36
+ await expectNoA11yViolations(container);
37
+ });
38
+ });
@@ -0,0 +1,30 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Avatar — chat profile avatar with online-presence indicator.
4
+ *
5
+ * Thin adapter over the shared `@happyvertical/smrt-ui` `Avatar` primitive
6
+ * (S10 consolidation, #1415): it keeps chat's prop vocabulary
7
+ * (`avatarUrl` / `onlineStatus`) but delegates rendering, the initials +
8
+ * image-error fallback, presence dot, tokens, and a11y to the library so that
9
+ * logic lives in exactly one place.
10
+ */
11
+ import { Avatar as UiAvatar } from '@happyvertical/smrt-ui';
12
+
13
+ export interface Props {
14
+ /** Display name used for initials fallback. */
15
+ name: string;
16
+ /** URL for the avatar image. */
17
+ avatarUrl?: string;
18
+ /** Online presence status. */
19
+ onlineStatus?: 'online' | 'away' | 'dnd' | 'offline';
20
+ /** Avatar size. */
21
+ size?: 'sm' | 'md' | 'lg';
22
+ }
23
+
24
+ const { name, avatarUrl, onlineStatus, size = 'md' }: Props = $props();
25
+
26
+ // chat's "dnd" maps to the library's "busy" presence value.
27
+ const status = $derived(onlineStatus === 'dnd' ? 'busy' : onlineStatus);
28
+ </script>
29
+
30
+ <UiAvatar {name} src={avatarUrl} {size} {status} />
@@ -0,0 +1,14 @@
1
+ export interface Props {
2
+ /** Display name used for initials fallback. */
3
+ name: string;
4
+ /** URL for the avatar image. */
5
+ avatarUrl?: string;
6
+ /** Online presence status. */
7
+ onlineStatus?: 'online' | 'away' | 'dnd' | 'offline';
8
+ /** Avatar size. */
9
+ size?: 'sm' | 'md' | 'lg';
10
+ }
11
+ declare const Avatar: import("svelte").Component<Props, {}, "">;
12
+ type Avatar = ReturnType<typeof Avatar>;
13
+ export default Avatar;
14
+ //# sourceMappingURL=Avatar.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/shared/Avatar.svelte.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,KAAK;IACpB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,YAAY,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IACrD,mBAAmB;IACnB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CAC3B;AAgBD,QAAA,MAAM,MAAM,2CAAwC,CAAC;AACrD,KAAK,MAAM,GAAG,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC;AACxC,eAAe,MAAM,CAAC"}