@eshal-bot/chat-widget 0.2.39 → 0.2.41

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.
@@ -1 +1 @@
1
- export{S as default}from"./chat-widget-index--xs5FWxs.esm.js";import"react";import"react-dom/client";import"react/jsx-runtime";import"react-dom";
1
+ export{S as default}from"./chat-widget-index-i7Tp1iNw.esm.js";import"react";import"react-dom/client";import"react/jsx-runtime";import"react-dom";
@@ -9313,6 +9313,7 @@
9313
9313
  verifyDone: "Verified as {target}",
9314
9314
  verifyResumeMessage: "I've confirmed it's me.",
9315
9315
  verifyTriesLeft: "That code doesn't match. {count} tries left.",
9316
+ verifyTryLeft: "That code doesn't match. 1 try left.",
9316
9317
  verifyGenericError: "Something went wrong. Try again.",
9317
9318
  verifyInputBlocked: "Enter your code above to continue",
9318
9319
  verifyCancel: "Cancel",
@@ -16496,6 +16497,49 @@
16496
16497
  return typeof u === 'string' && /^https?:\/\//i.test(u) ? u : undefined;
16497
16498
  }
16498
16499
 
16500
+ /**
16501
+ * What a Copy button puts on the clipboard (EV-4817, extended to every chat
16502
+ * surface): the words of a message without its card specs.
16503
+ *
16504
+ * A reply can carry ```eshal-ui``` blocks (buttons, forms, cards) that the
16505
+ * chat renders as controls. Copying the raw message put that JSON on the
16506
+ * clipboard. Same fences and tidy-up as the backend's
16507
+ * channels/utils/emailFormat.ts stripA2uiFences, so both sides agree on what
16508
+ * a fence is. Shared by the frontend (Inbox, Testing lab), the widget and
16509
+ * the agent-sdk.
16510
+ *
16511
+ * Plain JavaScript (types in clipboardText.d.ts), conservative syntax: the
16512
+ * widget's Rollup/Babel build compiles neither TypeScript nor this file.
16513
+ */
16514
+
16515
+ const A2UI_FENCE_TAGS = /(?:eshal-ui|eshal-chart|chart)\b/;
16516
+ function a2uiFenceRe() {
16517
+ return /```[ \t]*(?:eshal-ui|eshal-chart|chart)\b[ \t]*\r?\n([\s\S]*?)```/g;
16518
+ }
16519
+ function stripA2uiFences(text) {
16520
+ if (!text || !A2UI_FENCE_TAGS.test(text)) return text;
16521
+ return text.replace(a2uiFenceRe(), '').replace(/\n{3,}/g, '\n\n').trim();
16522
+ }
16523
+
16524
+ /**
16525
+ * The whole-chat "Copy Chat" text: one "Role: words" stanza per message,
16526
+ * blank line between. A message that is only a card has no words, so it is
16527
+ * left out like any other empty message.
16528
+ */
16529
+ function formatChatForClipboard(messages, assistantName) {
16530
+ if (!Array.isArray(messages)) return '';
16531
+ const label = assistantName || 'Assistant';
16532
+ const lines = [];
16533
+ for (let i = 0; i < messages.length; i++) {
16534
+ const msg = messages[i];
16535
+ if (!msg || typeof msg.content !== 'string') continue;
16536
+ const words = stripA2uiFences(msg.content);
16537
+ if (!words || words.trim() === '') continue;
16538
+ lines.push((msg.role === 'user' ? 'You' : label) + ': ' + words);
16539
+ }
16540
+ return lines.join('\n\n');
16541
+ }
16542
+
16499
16543
  /**
16500
16544
  * WidgetCitationContext - the message's `sources` array + download handler,
16501
16545
  * supplied by `<MessageBubble>` and consumed by every `<CitationPill>` that
@@ -17254,6 +17298,9 @@
17254
17298
  // `stripCitationMarkers` call and the separate `<MessageSources>`
17255
17299
  // footer were removed in the same refactor.
17256
17300
  const displayContent = rawContent;
17301
+ // Copy puts the words on the clipboard, not the ```eshal-ui``` card JSON;
17302
+ // a card-only reply has no words, so it gets no Copy button.
17303
+ const copyText = reactExports.useMemo(() => stripA2uiFences(displayContent), [displayContent]);
17257
17304
  const isTypingMessage = message.isProcessing && (!displayContent || displayContent.length === 0);
17258
17305
  // EV-2351: direction must follow THIS message's own text, not the agent's
17259
17306
  // configured default language. The blanket branding `isRtl` forced English
@@ -17475,8 +17522,8 @@
17475
17522
  className: `text-xs leading-none ${isDark ? "text-gray-400" : "text-gray-500"}`,
17476
17523
  dir: "auto",
17477
17524
  children: formatTime(message.timestamp)
17478
- }), !isTypingMessage && !message.isProcessing && displayContent && /*#__PURE__*/jsxRuntimeExports.jsx(CopyMessageButton, {
17479
- content: displayContent,
17525
+ }), !isTypingMessage && !message.isProcessing && copyText && /*#__PURE__*/jsxRuntimeExports.jsx(CopyMessageButton, {
17526
+ content: copyText,
17480
17527
  isDark: isDark,
17481
17528
  t: t
17482
17529
  }), allowFeedback !== false && onFeedback && !isTypingMessage && !message.isProcessing && displayContent && message.type !== 'welcome' && !message.isWelcome && /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
@@ -23238,7 +23285,7 @@
23238
23285
  * value by its own test (that constant sat at 0.1.113 while this package was
23239
23286
  * at 0.2.2 precisely because nothing enforced it - EV-2431).
23240
23287
  */
23241
- const WIDGET_VERSION = '0.2.39';
23288
+ const WIDGET_VERSION = '0.2.41';
23242
23289
 
23243
23290
  /**
23244
23291
  * API utility functions
@@ -23760,10 +23807,8 @@
23760
23807
 
23761
23808
  // Copy chat handler - copy all messages to clipboard
23762
23809
  const handleCopyChat = reactExports.useCallback(() => {
23763
- const text = messages.filter(msg => msg.content && msg.content.trim() !== "").map(msg => {
23764
- const role = msg.role === "user" ? "You" : widgetConfig?.conciergeName || "Assistant";
23765
- return `${role}: ${msg.content}`;
23766
- }).join("\n\n");
23810
+ // Words only: ```eshal-ui``` card JSON stays out of the transcript.
23811
+ const text = formatChatForClipboard(messages, widgetConfig?.conciergeName);
23767
23812
  if (text) {
23768
23813
  navigator.clipboard.writeText(text).catch(() => {});
23769
23814
  }