@refraction-ui/astro 0.9.0 → 0.10.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.
|
@@ -88,7 +88,7 @@ function isOwn(m: ChatMessage): boolean {
|
|
|
88
88
|
) : (
|
|
89
89
|
timeline.map((message) => {
|
|
90
90
|
const parent = state.threadingMode === 'inline' && message.parentId
|
|
91
|
-
? findMessage(state.messages, message.parentId)
|
|
91
|
+
? findMessage(state.messages, message.replyToId ?? message.parentId)
|
|
92
92
|
: undefined
|
|
93
93
|
const replyCount = getReplyCount(state.messages, message.id)
|
|
94
94
|
return (
|
|
@@ -137,7 +137,7 @@ function isOwn(m: ChatMessage): boolean {
|
|
|
137
137
|
</div>
|
|
138
138
|
)}
|
|
139
139
|
|
|
140
|
-
{
|
|
140
|
+
{replyCount > 0 && (
|
|
141
141
|
<button type="button" class="mt-1 text-xs font-medium text-primary hover:underline" data-rfr-open-thread data-root-id={message.id}>
|
|
142
142
|
💬 {replyCount} {replyCount === 1 ? 'reply' : 'replies'}
|
|
143
143
|
</button>
|
|
@@ -40,6 +40,7 @@ export function createConversation(config: ConversationConfig = {}): Conversatio
|
|
|
40
40
|
const messagesByConv = new Map<string, ChatMessage[]>()
|
|
41
41
|
let activeConversationId: string | null = config.activeConversationId ?? null
|
|
42
42
|
let openThreadRootId: string | null = null
|
|
43
|
+
let replyTarget: string | null = null
|
|
43
44
|
let status: ConversationState['status'] = 'idle'
|
|
44
45
|
let error: string | null = null
|
|
45
46
|
let abortController: AbortController | null = null
|
|
@@ -66,6 +67,7 @@ export function createConversation(config: ConversationConfig = {}): Conversatio
|
|
|
66
67
|
activeConversationId,
|
|
67
68
|
messages: activeConversationId ? (messagesByConv.get(activeConversationId) ?? []) : [],
|
|
68
69
|
openThreadRootId,
|
|
70
|
+
replyTarget,
|
|
69
71
|
threadingMode,
|
|
70
72
|
status,
|
|
71
73
|
error,
|
|
@@ -187,6 +189,7 @@ export function createConversation(config: ConversationConfig = {}): Conversatio
|
|
|
187
189
|
newConversation(opts) {
|
|
188
190
|
const conversation = createConversationInternal(opts ?? {})
|
|
189
191
|
openThreadRootId = null
|
|
192
|
+
replyTarget = null
|
|
190
193
|
emit()
|
|
191
194
|
return conversation
|
|
192
195
|
},
|
|
@@ -195,6 +198,7 @@ export function createConversation(config: ConversationConfig = {}): Conversatio
|
|
|
195
198
|
if (!conversations.has(conversationId) || activeConversationId === conversationId) return
|
|
196
199
|
activeConversationId = conversationId
|
|
197
200
|
openThreadRootId = null
|
|
201
|
+
replyTarget = null
|
|
198
202
|
emit()
|
|
199
203
|
},
|
|
200
204
|
|
|
@@ -205,6 +209,7 @@ export function createConversation(config: ConversationConfig = {}): Conversatio
|
|
|
205
209
|
if (activeConversationId === conversationId) {
|
|
206
210
|
activeConversationId = orderedConversations()[0]?.id ?? null
|
|
207
211
|
openThreadRootId = null
|
|
212
|
+
replyTarget = null
|
|
208
213
|
}
|
|
209
214
|
emit()
|
|
210
215
|
},
|
|
@@ -245,6 +250,7 @@ export function createConversation(config: ConversationConfig = {}): Conversatio
|
|
|
245
250
|
const next = list.filter((m) => !removeIds.has(m.id))
|
|
246
251
|
messagesByConv.set(activeConversationId, next)
|
|
247
252
|
if (openThreadRootId && removeIds.has(openThreadRootId)) openThreadRootId = null
|
|
253
|
+
if (replyTarget && removeIds.has(replyTarget)) replyTarget = openThreadRootId
|
|
248
254
|
emit()
|
|
249
255
|
},
|
|
250
256
|
|
|
@@ -277,7 +283,9 @@ export function createConversation(config: ConversationConfig = {}): Conversatio
|
|
|
277
283
|
|
|
278
284
|
const conversationId = ensureActiveConversation(opts)
|
|
279
285
|
const list = messagesByConv.get(conversationId)!
|
|
286
|
+
// Group under the originating root, but remember the specific message replied to.
|
|
280
287
|
const parentId = opts?.replyTo ? rootIdOf(list, opts.replyTo) : undefined
|
|
288
|
+
const replyToId = opts?.replyTo
|
|
281
289
|
const isFirstRoot = !parentId && selectRoots(list).length === 0
|
|
282
290
|
|
|
283
291
|
const userMsg: ChatMessage = {
|
|
@@ -289,6 +297,7 @@ export function createConversation(config: ConversationConfig = {}): Conversatio
|
|
|
289
297
|
timestamp: new Date(),
|
|
290
298
|
status: 'sent',
|
|
291
299
|
parentId,
|
|
300
|
+
replyToId,
|
|
292
301
|
attachments: opts?.attachments,
|
|
293
302
|
metadata: opts?.metadata,
|
|
294
303
|
}
|
|
@@ -355,12 +364,23 @@ export function createConversation(config: ConversationConfig = {}): Conversatio
|
|
|
355
364
|
|
|
356
365
|
openThread(rootId) {
|
|
357
366
|
openThreadRootId = rootId
|
|
367
|
+
replyTarget = rootId // reply to the root by default
|
|
368
|
+
emit()
|
|
369
|
+
},
|
|
370
|
+
|
|
371
|
+
replyTo(messageId) {
|
|
372
|
+
if (!activeConversationId) return
|
|
373
|
+
const list = messagesByConv.get(activeConversationId)!
|
|
374
|
+
// Open the originating thread, but target the specific message replied to.
|
|
375
|
+
openThreadRootId = rootIdOf(list, messageId)
|
|
376
|
+
replyTarget = messageId
|
|
358
377
|
emit()
|
|
359
378
|
},
|
|
360
379
|
|
|
361
380
|
closeThread() {
|
|
362
|
-
if (openThreadRootId === null) return
|
|
381
|
+
if (openThreadRootId === null && replyTarget === null) return
|
|
363
382
|
openThreadRootId = null
|
|
383
|
+
replyTarget = null
|
|
364
384
|
emit()
|
|
365
385
|
},
|
|
366
386
|
|
|
@@ -68,9 +68,15 @@ export interface ChatMessage {
|
|
|
68
68
|
error?: string
|
|
69
69
|
/**
|
|
70
70
|
* Root message id of the reply-thread this message belongs to. Absent on
|
|
71
|
-
* root/main-timeline messages. Threads are one level deep
|
|
71
|
+
* root/main-timeline messages. Threads are one level deep — a reply to any
|
|
72
|
+
* message in a thread groups under the same originating root.
|
|
72
73
|
*/
|
|
73
74
|
parentId?: string
|
|
75
|
+
/**
|
|
76
|
+
* The specific message this is "in reply to" (for the quote), which may be a
|
|
77
|
+
* mid-thread reply even though `parentId` is always the originating root.
|
|
78
|
+
*/
|
|
79
|
+
replyToId?: string
|
|
74
80
|
/** Emoji reactions */
|
|
75
81
|
reactions?: MessageReaction[]
|
|
76
82
|
/** Attachments (images/gifs/files) */
|
|
@@ -136,6 +142,8 @@ export interface ConversationState {
|
|
|
136
142
|
messages: ChatMessage[]
|
|
137
143
|
/** Root id of the thread shown in the side panel, or null when closed */
|
|
138
144
|
openThreadRootId: string | null
|
|
145
|
+
/** The specific message a reply in the open thread will target (default: the root) */
|
|
146
|
+
replyTarget: string | null
|
|
139
147
|
/** Current threading mode */
|
|
140
148
|
threadingMode: ThreadingMode
|
|
141
149
|
/** Coarse store status */
|
|
@@ -210,8 +218,10 @@ export interface ConversationAPI {
|
|
|
210
218
|
stop(): void
|
|
211
219
|
|
|
212
220
|
// — threads / view —
|
|
213
|
-
/** Open the side panel focused on a message's thread */
|
|
221
|
+
/** Open the side panel focused on a message's thread (reply target = root) */
|
|
214
222
|
openThread(rootId: string): void
|
|
223
|
+
/** Open the originating thread and target a specific message for the next reply */
|
|
224
|
+
replyTo(messageId: string): void
|
|
215
225
|
/** Close the thread side panel */
|
|
216
226
|
closeThread(): void
|
|
217
227
|
/** Switch threading mode */
|