@runtypelabs/persona 1.43.5 → 1.43.6
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.
- package/dist/index.cjs +29 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.global.js +53 -53
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +29 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/message-bubble.ts +9 -116
- package/src/ui.ts +83 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runtypelabs/persona",
|
|
3
|
-
"version": "1.43.
|
|
3
|
+
"version": "1.43.6",
|
|
4
4
|
"description": "Themeable, pluggable streaming agent widget for websites, in plain JS with support for voice input and reasoning / tool output.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -250,7 +250,7 @@ const getBubbleClasses = (
|
|
|
250
250
|
export const createMessageActions = (
|
|
251
251
|
message: AgentWidgetMessage,
|
|
252
252
|
actionsConfig: AgentWidgetMessageActionsConfig,
|
|
253
|
-
|
|
253
|
+
_callbacks?: MessageActionCallbacks
|
|
254
254
|
): HTMLElement => {
|
|
255
255
|
const showCopy = actionsConfig.showCopy ?? true;
|
|
256
256
|
const showUpvote = actionsConfig.showUpvote ?? true;
|
|
@@ -282,145 +282,38 @@ export const createMessageActions = (
|
|
|
282
282
|
container.id = `actions-${message.id}`;
|
|
283
283
|
container.setAttribute("data-actions-for", message.id);
|
|
284
284
|
|
|
285
|
-
// Track vote state for this message
|
|
286
|
-
let currentVote: "upvote" | "downvote" | null = null;
|
|
287
|
-
|
|
288
285
|
const createActionButton = (
|
|
289
286
|
iconName: string,
|
|
290
287
|
label: string,
|
|
291
|
-
|
|
292
|
-
dataAction?: string
|
|
288
|
+
dataAction: string
|
|
293
289
|
): HTMLButtonElement => {
|
|
294
290
|
const button = document.createElement("button");
|
|
295
291
|
button.className = "tvw-message-action-btn";
|
|
296
292
|
button.setAttribute("aria-label", label);
|
|
297
293
|
button.setAttribute("title", label);
|
|
298
|
-
|
|
299
|
-
button.setAttribute("data-action", dataAction);
|
|
300
|
-
}
|
|
294
|
+
button.setAttribute("data-action", dataAction);
|
|
301
295
|
|
|
302
296
|
const icon = renderLucideIcon(iconName, 14, "currentColor", 2);
|
|
303
297
|
if (icon) {
|
|
304
298
|
button.appendChild(icon);
|
|
305
299
|
}
|
|
306
300
|
|
|
307
|
-
button.addEventListener("click", (e) => {
|
|
308
|
-
e.preventDefault();
|
|
309
|
-
e.stopPropagation();
|
|
310
|
-
onClick();
|
|
311
|
-
});
|
|
312
|
-
|
|
313
301
|
return button;
|
|
314
302
|
};
|
|
315
303
|
|
|
316
|
-
// Copy button
|
|
304
|
+
// Copy button - click handled via event delegation in ui.ts
|
|
317
305
|
if (showCopy) {
|
|
318
|
-
|
|
319
|
-
// Copy to clipboard
|
|
320
|
-
const textToCopy = message.content || "";
|
|
321
|
-
navigator.clipboard.writeText(textToCopy).then(() => {
|
|
322
|
-
// Show success feedback - swap icon temporarily
|
|
323
|
-
copyButton.classList.add("tvw-message-action-success");
|
|
324
|
-
const checkIcon = renderLucideIcon("check", 14, "currentColor", 2);
|
|
325
|
-
if (checkIcon) {
|
|
326
|
-
copyButton.innerHTML = "";
|
|
327
|
-
copyButton.appendChild(checkIcon);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Restore original icon after 2 seconds
|
|
331
|
-
setTimeout(() => {
|
|
332
|
-
copyButton.classList.remove("tvw-message-action-success");
|
|
333
|
-
const originalIcon = renderLucideIcon("copy", 14, "currentColor", 2);
|
|
334
|
-
if (originalIcon) {
|
|
335
|
-
copyButton.innerHTML = "";
|
|
336
|
-
copyButton.appendChild(originalIcon);
|
|
337
|
-
}
|
|
338
|
-
}, 2000);
|
|
339
|
-
}).catch((err) => {
|
|
340
|
-
if (typeof console !== "undefined") {
|
|
341
|
-
console.error("[AgentWidget] Failed to copy message:", err);
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
// Trigger callback
|
|
346
|
-
if (callbacks?.onCopy) {
|
|
347
|
-
callbacks.onCopy(message);
|
|
348
|
-
}
|
|
349
|
-
if (actionsConfig.onCopy) {
|
|
350
|
-
actionsConfig.onCopy(message);
|
|
351
|
-
}
|
|
352
|
-
}, "copy");
|
|
353
|
-
container.appendChild(copyButton);
|
|
306
|
+
container.appendChild(createActionButton("copy", "Copy message", "copy"));
|
|
354
307
|
}
|
|
355
308
|
|
|
356
|
-
// Upvote button
|
|
309
|
+
// Upvote button - click handled via event delegation in ui.ts
|
|
357
310
|
if (showUpvote) {
|
|
358
|
-
|
|
359
|
-
const wasActive = currentVote === "upvote";
|
|
360
|
-
|
|
361
|
-
// Toggle state
|
|
362
|
-
if (wasActive) {
|
|
363
|
-
currentVote = null;
|
|
364
|
-
upvoteButton.classList.remove("tvw-message-action-active");
|
|
365
|
-
} else {
|
|
366
|
-
// Remove downvote if active
|
|
367
|
-
const downvoteBtn = container.querySelector('[data-action="downvote"]');
|
|
368
|
-
if (downvoteBtn) {
|
|
369
|
-
downvoteBtn.classList.remove("tvw-message-action-active");
|
|
370
|
-
}
|
|
371
|
-
currentVote = "upvote";
|
|
372
|
-
upvoteButton.classList.add("tvw-message-action-active");
|
|
373
|
-
|
|
374
|
-
// Trigger feedback
|
|
375
|
-
const feedback: AgentWidgetMessageFeedback = {
|
|
376
|
-
type: "upvote",
|
|
377
|
-
messageId: message.id,
|
|
378
|
-
message
|
|
379
|
-
};
|
|
380
|
-
if (callbacks?.onFeedback) {
|
|
381
|
-
callbacks.onFeedback(feedback);
|
|
382
|
-
}
|
|
383
|
-
if (actionsConfig.onFeedback) {
|
|
384
|
-
actionsConfig.onFeedback(feedback);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}, "upvote");
|
|
388
|
-
container.appendChild(upvoteButton);
|
|
311
|
+
container.appendChild(createActionButton("thumbs-up", "Upvote", "upvote"));
|
|
389
312
|
}
|
|
390
313
|
|
|
391
|
-
// Downvote button
|
|
314
|
+
// Downvote button - click handled via event delegation in ui.ts
|
|
392
315
|
if (showDownvote) {
|
|
393
|
-
|
|
394
|
-
const wasActive = currentVote === "downvote";
|
|
395
|
-
|
|
396
|
-
// Toggle state
|
|
397
|
-
if (wasActive) {
|
|
398
|
-
currentVote = null;
|
|
399
|
-
downvoteButton.classList.remove("tvw-message-action-active");
|
|
400
|
-
} else {
|
|
401
|
-
// Remove upvote if active
|
|
402
|
-
const upvoteBtn = container.querySelector('[data-action="upvote"]');
|
|
403
|
-
if (upvoteBtn) {
|
|
404
|
-
upvoteBtn.classList.remove("tvw-message-action-active");
|
|
405
|
-
}
|
|
406
|
-
currentVote = "downvote";
|
|
407
|
-
downvoteButton.classList.add("tvw-message-action-active");
|
|
408
|
-
|
|
409
|
-
// Trigger feedback
|
|
410
|
-
const feedback: AgentWidgetMessageFeedback = {
|
|
411
|
-
type: "downvote",
|
|
412
|
-
messageId: message.id,
|
|
413
|
-
message
|
|
414
|
-
};
|
|
415
|
-
if (callbacks?.onFeedback) {
|
|
416
|
-
callbacks.onFeedback(feedback);
|
|
417
|
-
}
|
|
418
|
-
if (actionsConfig.onFeedback) {
|
|
419
|
-
actionsConfig.onFeedback(feedback);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}, "downvote");
|
|
423
|
-
container.appendChild(downvoteButton);
|
|
316
|
+
container.appendChild(createActionButton("thumbs-down", "Downvote", "downvote"));
|
|
424
317
|
}
|
|
425
318
|
|
|
426
319
|
return container;
|
package/src/ui.ts
CHANGED
|
@@ -823,6 +823,89 @@ export const createAgentExperience = (
|
|
|
823
823
|
}
|
|
824
824
|
});
|
|
825
825
|
|
|
826
|
+
// Add event delegation for message action buttons (upvote, downvote, copy)
|
|
827
|
+
// This handles clicks even after idiomorph morphs the DOM and strips inline listeners
|
|
828
|
+
const messageVoteState = new Map<string, "upvote" | "downvote">();
|
|
829
|
+
|
|
830
|
+
messagesWrapper.addEventListener('click', (event) => {
|
|
831
|
+
const target = event.target as HTMLElement;
|
|
832
|
+
const actionBtn = target.closest('.tvw-message-action-btn[data-action]') as HTMLElement;
|
|
833
|
+
if (!actionBtn) return;
|
|
834
|
+
|
|
835
|
+
event.preventDefault();
|
|
836
|
+
event.stopPropagation();
|
|
837
|
+
|
|
838
|
+
const actionsContainer = actionBtn.closest('[data-actions-for]') as HTMLElement;
|
|
839
|
+
if (!actionsContainer) return;
|
|
840
|
+
|
|
841
|
+
const messageId = actionsContainer.getAttribute('data-actions-for');
|
|
842
|
+
if (!messageId) return;
|
|
843
|
+
|
|
844
|
+
const action = actionBtn.getAttribute('data-action');
|
|
845
|
+
|
|
846
|
+
if (action === 'copy') {
|
|
847
|
+
const messages = session.getMessages();
|
|
848
|
+
const message = messages.find(m => m.id === messageId);
|
|
849
|
+
if (message && messageActionCallbacks.onCopy) {
|
|
850
|
+
// Copy to clipboard
|
|
851
|
+
const textToCopy = message.content || "";
|
|
852
|
+
navigator.clipboard.writeText(textToCopy).then(() => {
|
|
853
|
+
// Show success feedback - swap icon temporarily
|
|
854
|
+
actionBtn.classList.add("tvw-message-action-success");
|
|
855
|
+
const checkIcon = renderLucideIcon("check", 14, "currentColor", 2);
|
|
856
|
+
if (checkIcon) {
|
|
857
|
+
actionBtn.innerHTML = "";
|
|
858
|
+
actionBtn.appendChild(checkIcon);
|
|
859
|
+
}
|
|
860
|
+
setTimeout(() => {
|
|
861
|
+
actionBtn.classList.remove("tvw-message-action-success");
|
|
862
|
+
const originalIcon = renderLucideIcon("copy", 14, "currentColor", 2);
|
|
863
|
+
if (originalIcon) {
|
|
864
|
+
actionBtn.innerHTML = "";
|
|
865
|
+
actionBtn.appendChild(originalIcon);
|
|
866
|
+
}
|
|
867
|
+
}, 2000);
|
|
868
|
+
}).catch((err) => {
|
|
869
|
+
if (typeof console !== "undefined") {
|
|
870
|
+
// eslint-disable-next-line no-console
|
|
871
|
+
console.error("[AgentWidget] Failed to copy message:", err);
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
messageActionCallbacks.onCopy(message);
|
|
875
|
+
}
|
|
876
|
+
} else if (action === 'upvote' || action === 'downvote') {
|
|
877
|
+
const currentVote = messageVoteState.get(messageId) ?? null;
|
|
878
|
+
const wasActive = currentVote === action;
|
|
879
|
+
|
|
880
|
+
if (wasActive) {
|
|
881
|
+
// Toggle off
|
|
882
|
+
messageVoteState.delete(messageId);
|
|
883
|
+
actionBtn.classList.remove("tvw-message-action-active");
|
|
884
|
+
} else {
|
|
885
|
+
// Clear opposite vote button
|
|
886
|
+
const oppositeAction = action === 'upvote' ? 'downvote' : 'upvote';
|
|
887
|
+
const oppositeBtn = actionsContainer.querySelector(`[data-action="${oppositeAction}"]`);
|
|
888
|
+
if (oppositeBtn) {
|
|
889
|
+
oppositeBtn.classList.remove("tvw-message-action-active");
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
messageVoteState.set(messageId, action);
|
|
893
|
+
actionBtn.classList.add("tvw-message-action-active");
|
|
894
|
+
|
|
895
|
+
// Trigger feedback
|
|
896
|
+
const messages = session.getMessages();
|
|
897
|
+
const message = messages.find(m => m.id === messageId);
|
|
898
|
+
if (message && messageActionCallbacks.onFeedback) {
|
|
899
|
+
messageActionCallbacks.onFeedback({
|
|
900
|
+
type: action,
|
|
901
|
+
messageId: message.id,
|
|
902
|
+
message
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
});
|
|
908
|
+
|
|
826
909
|
panel.appendChild(container);
|
|
827
910
|
mount.appendChild(wrapper);
|
|
828
911
|
|