@runtypelabs/persona 3.10.0 → 3.10.1

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.
@@ -13406,6 +13406,15 @@ function getClipboardImageFiles(clipboardData) {
13406
13406
  }
13407
13407
  return imageFiles;
13408
13408
  }
13409
+ function dataTransferHasFiles(dataTransfer) {
13410
+ if (!dataTransfer) return false;
13411
+ const types = dataTransfer.types;
13412
+ if (!types) return false;
13413
+ if (typeof types.contains === "function") {
13414
+ return types.contains("Files");
13415
+ }
13416
+ return Array.from(types).includes("Files");
13417
+ }
13409
13418
  function normalizePersistStateConfig(config) {
13410
13419
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
13411
13420
  if (!config) return null;
@@ -13497,8 +13506,36 @@ var buildPostprocessor = (cfg, actionManager, onResubmitRequested) => {
13497
13506
  return sanitize ? sanitize(html) : html;
13498
13507
  };
13499
13508
  };
13509
+ function buildDropOverlay(dropCfg) {
13510
+ var _a, _b, _c, _d;
13511
+ const overlay = createElement("div", "persona-attachment-drop-overlay");
13512
+ if (dropCfg == null ? void 0 : dropCfg.background) overlay.style.setProperty("--persona-drop-overlay-bg", dropCfg.background);
13513
+ if ((dropCfg == null ? void 0 : dropCfg.backdropBlur) !== void 0) overlay.style.setProperty("--persona-drop-overlay-blur", dropCfg.backdropBlur);
13514
+ if (dropCfg == null ? void 0 : dropCfg.border) overlay.style.setProperty("--persona-drop-overlay-border", dropCfg.border);
13515
+ if (dropCfg == null ? void 0 : dropCfg.borderRadius) overlay.style.setProperty("--persona-drop-overlay-radius", dropCfg.borderRadius);
13516
+ if (dropCfg == null ? void 0 : dropCfg.inset) overlay.style.setProperty("--persona-drop-overlay-inset", dropCfg.inset);
13517
+ if (dropCfg == null ? void 0 : dropCfg.labelSize) overlay.style.setProperty("--persona-drop-overlay-label-size", dropCfg.labelSize);
13518
+ if (dropCfg == null ? void 0 : dropCfg.labelColor) overlay.style.setProperty("--persona-drop-overlay-label-color", dropCfg.labelColor);
13519
+ const iconName = (_a = dropCfg == null ? void 0 : dropCfg.iconName) != null ? _a : "upload";
13520
+ const iconSize = (_b = dropCfg == null ? void 0 : dropCfg.iconSize) != null ? _b : "48px";
13521
+ const iconColor = (_c = dropCfg == null ? void 0 : dropCfg.iconColor) != null ? _c : "rgba(59, 130, 246, 0.6)";
13522
+ const iconStrokeWidth = (_d = dropCfg == null ? void 0 : dropCfg.iconStrokeWidth) != null ? _d : 0.5;
13523
+ const iconSvg = renderLucideIcon(iconName, iconSize, iconColor, iconStrokeWidth);
13524
+ if (iconSvg) overlay.appendChild(iconSvg);
13525
+ if (dropCfg == null ? void 0 : dropCfg.label) {
13526
+ const labelEl = createElement("span", "persona-drop-overlay-label");
13527
+ labelEl.textContent = dropCfg.label;
13528
+ overlay.appendChild(labelEl);
13529
+ }
13530
+ return overlay;
13531
+ }
13500
13532
  var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
13501
13533
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N;
13534
+ if (mount == null) {
13535
+ throw new Error(
13536
+ 'createAgentExperience: mount must be a non-null HTMLElement (e.g. pass document.getElementById("my-root") after the node exists).'
13537
+ );
13538
+ }
13502
13539
  if (mount.id && !mount.getAttribute("data-persona-instance")) {
13503
13540
  mount.setAttribute("data-persona-instance", mount.id);
13504
13541
  }
@@ -13902,8 +13939,22 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
13902
13939
  return composerElements.footer;
13903
13940
  },
13904
13941
  onSubmit: (text) => {
13905
- if (session && !session.isStreaming()) {
13906
- session.sendMessage(text);
13942
+ var _a2;
13943
+ if (!session || session.isStreaming()) return;
13944
+ const value = text.trim();
13945
+ const hasAttachments = (_a2 = attachmentManager == null ? void 0 : attachmentManager.hasAttachments()) != null ? _a2 : false;
13946
+ if (!value && !hasAttachments) return;
13947
+ let contentParts;
13948
+ if (hasAttachments) {
13949
+ contentParts = [];
13950
+ contentParts.push(...attachmentManager.getContentParts());
13951
+ if (value) {
13952
+ contentParts.push(createTextPart(value));
13953
+ }
13954
+ }
13955
+ session.sendMessage(value, { contentParts });
13956
+ if (hasAttachments) {
13957
+ attachmentManager.clearAttachments();
13907
13958
  }
13908
13959
  },
13909
13960
  streaming: false,
@@ -13982,6 +14033,9 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
13982
14033
  attachmentManager == null ? void 0 : attachmentManager.handleFileSelect(target.files);
13983
14034
  target.value = "";
13984
14035
  });
14036
+ const dropCfg = config.attachments.dropOverlay;
14037
+ const overlay = buildDropOverlay(dropCfg);
14038
+ container.appendChild(overlay);
13985
14039
  }
13986
14040
  const renderSlots = () => {
13987
14041
  var _a2, _b2;
@@ -14775,6 +14829,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14775
14829
  let lastScrollTop = 0;
14776
14830
  let scrollRAF = null;
14777
14831
  let isAutoScrolling = false;
14832
+ let hasPendingAutoScroll = false;
14778
14833
  const USER_SCROLL_THRESHOLD = 1;
14779
14834
  const BOTTOM_THRESHOLD = 8;
14780
14835
  const messageState = /* @__PURE__ */ new Map();
@@ -14867,6 +14922,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14867
14922
  cancelAnimationFrame(scrollRAF);
14868
14923
  scrollRAF = null;
14869
14924
  }
14925
+ hasPendingAutoScroll = false;
14870
14926
  cancelSmoothScroll();
14871
14927
  };
14872
14928
  const syncScrollToBottomButton = () => {
@@ -14896,9 +14952,14 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14896
14952
  const scheduleAutoScroll = (force = false) => {
14897
14953
  if (!autoFollow.isFollowing()) return;
14898
14954
  if (!force && !isStreaming) return;
14899
- cancelAutoScroll();
14955
+ if (scrollRAF !== null) {
14956
+ cancelAnimationFrame(scrollRAF);
14957
+ scrollRAF = null;
14958
+ }
14959
+ hasPendingAutoScroll = true;
14900
14960
  scrollRAF = requestAnimationFrame(() => {
14901
14961
  scrollRAF = null;
14962
+ hasPendingAutoScroll = false;
14902
14963
  if (!autoFollow.isFollowing()) return;
14903
14964
  smoothScrollToBottom(getScrollableContainer(), force ? 220 : 140);
14904
14965
  });
@@ -16217,7 +16278,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16217
16278
  lastScrollTop,
16218
16279
  nearBottom: isElementNearBottom(body, BOTTOM_THRESHOLD),
16219
16280
  userScrollThreshold: USER_SCROLL_THRESHOLD,
16220
- isAutoScrolling,
16281
+ isAutoScrolling: isAutoScrolling || hasPendingAutoScroll,
16221
16282
  pauseOnUpwardScroll: true,
16222
16283
  pauseWhenAwayFromBottom: false,
16223
16284
  resumeRequiresDownwardScroll: true
@@ -16332,6 +16393,61 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16332
16393
  }
16333
16394
  textarea == null ? void 0 : textarea.addEventListener("keydown", handleInputEnter);
16334
16395
  textarea == null ? void 0 : textarea.addEventListener("paste", handleInputPaste);
16396
+ const ATTACHMENT_DROP_ACTIVE_CLASS = "persona-attachment-drop-active";
16397
+ let attachmentFileDragDepth = 0;
16398
+ const clearAttachmentDropVisual = () => {
16399
+ attachmentFileDragDepth = 0;
16400
+ container.classList.remove(ATTACHMENT_DROP_ACTIVE_CLASS);
16401
+ };
16402
+ const attachmentDropHandlingActive = () => {
16403
+ var _a2;
16404
+ return ((_a2 = config.attachments) == null ? void 0 : _a2.enabled) === true && attachmentManager !== null;
16405
+ };
16406
+ const handleAttachmentDragEnterCapture = (e) => {
16407
+ if (!dataTransferHasFiles(e.dataTransfer) || !attachmentDropHandlingActive()) return;
16408
+ attachmentFileDragDepth++;
16409
+ if (attachmentFileDragDepth === 1) {
16410
+ container.classList.add(ATTACHMENT_DROP_ACTIVE_CLASS);
16411
+ }
16412
+ };
16413
+ const handleAttachmentDragLeaveCapture = (e) => {
16414
+ if (!dataTransferHasFiles(e.dataTransfer) || !attachmentDropHandlingActive()) return;
16415
+ attachmentFileDragDepth--;
16416
+ if (attachmentFileDragDepth <= 0) {
16417
+ clearAttachmentDropVisual();
16418
+ }
16419
+ };
16420
+ const handleAttachmentDragOverCapture = (e) => {
16421
+ if (!dataTransferHasFiles(e.dataTransfer) || !attachmentDropHandlingActive()) return;
16422
+ e.preventDefault();
16423
+ e.dataTransfer.dropEffect = "copy";
16424
+ };
16425
+ const handleAttachmentDropCapture = (e) => {
16426
+ var _a2;
16427
+ if (!dataTransferHasFiles(e.dataTransfer) || !attachmentDropHandlingActive()) return;
16428
+ e.preventDefault();
16429
+ e.stopPropagation();
16430
+ clearAttachmentDropVisual();
16431
+ const files = Array.from((_a2 = e.dataTransfer.files) != null ? _a2 : []);
16432
+ if (files.length === 0) return;
16433
+ void attachmentManager.handleFiles(files);
16434
+ };
16435
+ const attachmentDropCapture = true;
16436
+ container.addEventListener("dragenter", handleAttachmentDragEnterCapture, attachmentDropCapture);
16437
+ container.addEventListener("dragleave", handleAttachmentDragLeaveCapture, attachmentDropCapture);
16438
+ mount.addEventListener("dragover", handleAttachmentDragOverCapture, attachmentDropCapture);
16439
+ mount.addEventListener("drop", handleAttachmentDropCapture, attachmentDropCapture);
16440
+ const ownerDoc = mount.ownerDocument;
16441
+ const handleDocDragOver = (e) => {
16442
+ if (!attachmentDropHandlingActive()) return;
16443
+ e.preventDefault();
16444
+ };
16445
+ const handleDocDrop = (e) => {
16446
+ if (!attachmentDropHandlingActive()) return;
16447
+ e.preventDefault();
16448
+ };
16449
+ ownerDoc.addEventListener("dragover", handleDocDragOver);
16450
+ ownerDoc.addEventListener("drop", handleDocDrop);
16335
16451
  destroyCallbacks.push(() => {
16336
16452
  if (composerForm) {
16337
16453
  composerForm.removeEventListener("submit", handleSubmit);
@@ -16339,6 +16455,15 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16339
16455
  textarea == null ? void 0 : textarea.removeEventListener("keydown", handleInputEnter);
16340
16456
  textarea == null ? void 0 : textarea.removeEventListener("paste", handleInputPaste);
16341
16457
  });
16458
+ destroyCallbacks.push(() => {
16459
+ container.removeEventListener("dragenter", handleAttachmentDragEnterCapture, attachmentDropCapture);
16460
+ container.removeEventListener("dragleave", handleAttachmentDragLeaveCapture, attachmentDropCapture);
16461
+ mount.removeEventListener("dragover", handleAttachmentDragOverCapture, attachmentDropCapture);
16462
+ mount.removeEventListener("drop", handleAttachmentDropCapture, attachmentDropCapture);
16463
+ ownerDoc.removeEventListener("dragover", handleDocDragOver);
16464
+ ownerDoc.removeEventListener("drop", handleDocDrop);
16465
+ clearAttachmentDropVisual();
16466
+ });
16342
16467
  destroyCallbacks.push(() => {
16343
16468
  session.cancel();
16344
16469
  });
@@ -16353,7 +16478,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16353
16478
  }
16354
16479
  const controller = {
16355
16480
  update(nextConfig) {
16356
- var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2, _o2, _p2, _q2, _r2, _s2, _t2, _u2, _v2, _w2, _x2, _y2, _z2, _A2, _B2, _C2, _D2, _E2, _F2, _G2, _H2, _I2, _J2, _K2, _L2, _M2, _N2, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a;
16481
+ var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2, _o2, _p2, _q2, _r2, _s2, _t2, _u2, _v2, _w2, _x2, _y2, _z2, _A2, _B2, _C2, _D2, _E2, _F2, _G2, _H2, _I2, _J2, _K2, _L2, _M2, _N2, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab;
16357
16482
  const previousToolCallConfig = config.toolCall;
16358
16483
  const previousMessageActions = config.messageActions;
16359
16484
  const previousLayoutMessages = (_a2 = config.layout) == null ? void 0 : _a2.messages;
@@ -17111,6 +17236,9 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17111
17236
  }
17112
17237
  });
17113
17238
  }
17239
+ if (!container.querySelector(".persona-attachment-drop-overlay")) {
17240
+ container.appendChild(buildDropOverlay(attachmentsConfig.dropOverlay));
17241
+ }
17114
17242
  } else {
17115
17243
  attachmentButtonWrapper.style.display = "";
17116
17244
  const attachmentsConfig = (_Oa = config.attachments) != null ? _Oa : {};
@@ -17133,14 +17261,15 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17133
17261
  if (attachmentManager) {
17134
17262
  attachmentManager.clearAttachments();
17135
17263
  }
17264
+ (_Ra = container.querySelector(".persona-attachment-drop-overlay")) == null ? void 0 : _Ra.remove();
17136
17265
  }
17137
- const sendButtonConfig = (_Ra = config.sendButton) != null ? _Ra : {};
17138
- const useIcon = (_Sa = sendButtonConfig.useIcon) != null ? _Sa : false;
17139
- const iconText = (_Ta = sendButtonConfig.iconText) != null ? _Ta : "\u2191";
17266
+ const sendButtonConfig = (_Sa = config.sendButton) != null ? _Sa : {};
17267
+ const useIcon = (_Ta = sendButtonConfig.useIcon) != null ? _Ta : false;
17268
+ const iconText = (_Ua = sendButtonConfig.iconText) != null ? _Ua : "\u2191";
17140
17269
  const iconName = sendButtonConfig.iconName;
17141
- const tooltipText = (_Ua = sendButtonConfig.tooltipText) != null ? _Ua : "Send message";
17142
- const showTooltip = (_Va = sendButtonConfig.showTooltip) != null ? _Va : false;
17143
- const buttonSize = (_Wa = sendButtonConfig.size) != null ? _Wa : "40px";
17270
+ const tooltipText = (_Va = sendButtonConfig.tooltipText) != null ? _Va : "Send message";
17271
+ const showTooltip = (_Wa = sendButtonConfig.showTooltip) != null ? _Wa : false;
17272
+ const buttonSize = (_Xa = sendButtonConfig.size) != null ? _Xa : "40px";
17144
17273
  const backgroundColor = sendButtonConfig.backgroundColor;
17145
17274
  const textColor = sendButtonConfig.textColor;
17146
17275
  if (useIcon) {
@@ -17177,7 +17306,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17177
17306
  sendButton.classList.add("persona-bg-persona-primary");
17178
17307
  }
17179
17308
  } else {
17180
- sendButton.textContent = (_Ya = (_Xa = config.copy) == null ? void 0 : _Xa.sendButtonLabel) != null ? _Ya : "Send";
17309
+ sendButton.textContent = (_Za = (_Ya = config.copy) == null ? void 0 : _Ya.sendButtonLabel) != null ? _Za : "Send";
17181
17310
  sendButton.style.width = "";
17182
17311
  sendButton.style.height = "";
17183
17312
  sendButton.style.minWidth = "";
@@ -17237,7 +17366,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17237
17366
  } else if (tooltip) {
17238
17367
  tooltip.style.display = "none";
17239
17368
  }
17240
- const updatedContentMaxWidth = (_Za = config.layout) == null ? void 0 : _Za.contentMaxWidth;
17369
+ const updatedContentMaxWidth = (__a = config.layout) == null ? void 0 : __a.contentMaxWidth;
17241
17370
  if (updatedContentMaxWidth) {
17242
17371
  messagesWrapper.style.maxWidth = updatedContentMaxWidth;
17243
17372
  messagesWrapper.style.marginLeft = "auto";
@@ -17269,8 +17398,8 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17269
17398
  suggestions.style.marginRight = "";
17270
17399
  }
17271
17400
  }
17272
- const statusIndicatorConfig = (__a = config.statusIndicator) != null ? __a : {};
17273
- const isVisible = (_$a = statusIndicatorConfig.visible) != null ? _$a : true;
17401
+ const statusIndicatorConfig = (_$a = config.statusIndicator) != null ? _$a : {};
17402
+ const isVisible = (_ab = statusIndicatorConfig.visible) != null ? _ab : true;
17274
17403
  statusText.style.display = isVisible ? "" : "none";
17275
17404
  if (session) {
17276
17405
  const currentStatus = session.getStatus();
@@ -2412,6 +2412,35 @@ type AgentWidgetAttachmentsConfig = {
2412
2412
  * Callback when a file is rejected (wrong type or too large).
2413
2413
  */
2414
2414
  onFileRejected?: (file: File, reason: 'type' | 'size' | 'count') => void;
2415
+ /**
2416
+ * Customize the drag-and-drop overlay that appears when files are dragged over the widget.
2417
+ */
2418
+ dropOverlay?: {
2419
+ /** Background color/value of the overlay. @default 'rgba(59, 130, 246, 0.08)' */
2420
+ background?: string;
2421
+ /** Backdrop blur applied behind the overlay (CSS value). @default '8px' */
2422
+ backdropBlur?: string;
2423
+ /** Border style shown during drag. @default '2px dashed rgba(59, 130, 246, 0.4)' */
2424
+ border?: string;
2425
+ /** Border radius of the overlay. @default 'inherit' */
2426
+ borderRadius?: string;
2427
+ /** Inset/margin pulling the overlay away from the container edges (CSS value). @default '0' */
2428
+ inset?: string;
2429
+ /** Lucide icon name displayed in the center. @default 'upload' */
2430
+ iconName?: string;
2431
+ /** Icon size (CSS value). @default '48px' */
2432
+ iconSize?: string;
2433
+ /** Icon stroke color. @default 'rgba(59, 130, 246, 0.6)' */
2434
+ iconColor?: string;
2435
+ /** Icon stroke width. @default 0.5 */
2436
+ iconStrokeWidth?: number;
2437
+ /** Optional label text shown below the icon. */
2438
+ label?: string;
2439
+ /** Label font size. @default '0.875rem' */
2440
+ labelSize?: string;
2441
+ /** Label color. @default 'rgba(59, 130, 246, 0.8)' */
2442
+ labelColor?: string;
2443
+ };
2415
2444
  };
2416
2445
  /**
2417
2446
  * Configuration for persisting widget state across page navigations.
@@ -2412,6 +2412,35 @@ type AgentWidgetAttachmentsConfig = {
2412
2412
  * Callback when a file is rejected (wrong type or too large).
2413
2413
  */
2414
2414
  onFileRejected?: (file: File, reason: 'type' | 'size' | 'count') => void;
2415
+ /**
2416
+ * Customize the drag-and-drop overlay that appears when files are dragged over the widget.
2417
+ */
2418
+ dropOverlay?: {
2419
+ /** Background color/value of the overlay. @default 'rgba(59, 130, 246, 0.08)' */
2420
+ background?: string;
2421
+ /** Backdrop blur applied behind the overlay (CSS value). @default '8px' */
2422
+ backdropBlur?: string;
2423
+ /** Border style shown during drag. @default '2px dashed rgba(59, 130, 246, 0.4)' */
2424
+ border?: string;
2425
+ /** Border radius of the overlay. @default 'inherit' */
2426
+ borderRadius?: string;
2427
+ /** Inset/margin pulling the overlay away from the container edges (CSS value). @default '0' */
2428
+ inset?: string;
2429
+ /** Lucide icon name displayed in the center. @default 'upload' */
2430
+ iconName?: string;
2431
+ /** Icon size (CSS value). @default '48px' */
2432
+ iconSize?: string;
2433
+ /** Icon stroke color. @default 'rgba(59, 130, 246, 0.6)' */
2434
+ iconColor?: string;
2435
+ /** Icon stroke width. @default 0.5 */
2436
+ iconStrokeWidth?: number;
2437
+ /** Optional label text shown below the icon. */
2438
+ label?: string;
2439
+ /** Label font size. @default '0.875rem' */
2440
+ labelSize?: string;
2441
+ /** Label color. @default 'rgba(59, 130, 246, 0.8)' */
2442
+ labelColor?: string;
2443
+ };
2415
2444
  };
2416
2445
  /**
2417
2446
  * Configuration for persisting widget state across page navigations.
@@ -13297,6 +13297,15 @@ function getClipboardImageFiles(clipboardData) {
13297
13297
  }
13298
13298
  return imageFiles;
13299
13299
  }
13300
+ function dataTransferHasFiles(dataTransfer) {
13301
+ if (!dataTransfer) return false;
13302
+ const types = dataTransfer.types;
13303
+ if (!types) return false;
13304
+ if (typeof types.contains === "function") {
13305
+ return types.contains("Files");
13306
+ }
13307
+ return Array.from(types).includes("Files");
13308
+ }
13300
13309
  function normalizePersistStateConfig(config) {
13301
13310
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
13302
13311
  if (!config) return null;
@@ -13388,8 +13397,36 @@ var buildPostprocessor = (cfg, actionManager, onResubmitRequested) => {
13388
13397
  return sanitize ? sanitize(html) : html;
13389
13398
  };
13390
13399
  };
13400
+ function buildDropOverlay(dropCfg) {
13401
+ var _a, _b, _c, _d;
13402
+ const overlay = createElement("div", "persona-attachment-drop-overlay");
13403
+ if (dropCfg == null ? void 0 : dropCfg.background) overlay.style.setProperty("--persona-drop-overlay-bg", dropCfg.background);
13404
+ if ((dropCfg == null ? void 0 : dropCfg.backdropBlur) !== void 0) overlay.style.setProperty("--persona-drop-overlay-blur", dropCfg.backdropBlur);
13405
+ if (dropCfg == null ? void 0 : dropCfg.border) overlay.style.setProperty("--persona-drop-overlay-border", dropCfg.border);
13406
+ if (dropCfg == null ? void 0 : dropCfg.borderRadius) overlay.style.setProperty("--persona-drop-overlay-radius", dropCfg.borderRadius);
13407
+ if (dropCfg == null ? void 0 : dropCfg.inset) overlay.style.setProperty("--persona-drop-overlay-inset", dropCfg.inset);
13408
+ if (dropCfg == null ? void 0 : dropCfg.labelSize) overlay.style.setProperty("--persona-drop-overlay-label-size", dropCfg.labelSize);
13409
+ if (dropCfg == null ? void 0 : dropCfg.labelColor) overlay.style.setProperty("--persona-drop-overlay-label-color", dropCfg.labelColor);
13410
+ const iconName = (_a = dropCfg == null ? void 0 : dropCfg.iconName) != null ? _a : "upload";
13411
+ const iconSize = (_b = dropCfg == null ? void 0 : dropCfg.iconSize) != null ? _b : "48px";
13412
+ const iconColor = (_c = dropCfg == null ? void 0 : dropCfg.iconColor) != null ? _c : "rgba(59, 130, 246, 0.6)";
13413
+ const iconStrokeWidth = (_d = dropCfg == null ? void 0 : dropCfg.iconStrokeWidth) != null ? _d : 0.5;
13414
+ const iconSvg = renderLucideIcon(iconName, iconSize, iconColor, iconStrokeWidth);
13415
+ if (iconSvg) overlay.appendChild(iconSvg);
13416
+ if (dropCfg == null ? void 0 : dropCfg.label) {
13417
+ const labelEl = createElement("span", "persona-drop-overlay-label");
13418
+ labelEl.textContent = dropCfg.label;
13419
+ overlay.appendChild(labelEl);
13420
+ }
13421
+ return overlay;
13422
+ }
13391
13423
  var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
13392
13424
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N;
13425
+ if (mount == null) {
13426
+ throw new Error(
13427
+ 'createAgentExperience: mount must be a non-null HTMLElement (e.g. pass document.getElementById("my-root") after the node exists).'
13428
+ );
13429
+ }
13393
13430
  if (mount.id && !mount.getAttribute("data-persona-instance")) {
13394
13431
  mount.setAttribute("data-persona-instance", mount.id);
13395
13432
  }
@@ -13793,8 +13830,22 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
13793
13830
  return composerElements.footer;
13794
13831
  },
13795
13832
  onSubmit: (text) => {
13796
- if (session && !session.isStreaming()) {
13797
- session.sendMessage(text);
13833
+ var _a2;
13834
+ if (!session || session.isStreaming()) return;
13835
+ const value = text.trim();
13836
+ const hasAttachments = (_a2 = attachmentManager == null ? void 0 : attachmentManager.hasAttachments()) != null ? _a2 : false;
13837
+ if (!value && !hasAttachments) return;
13838
+ let contentParts;
13839
+ if (hasAttachments) {
13840
+ contentParts = [];
13841
+ contentParts.push(...attachmentManager.getContentParts());
13842
+ if (value) {
13843
+ contentParts.push(createTextPart(value));
13844
+ }
13845
+ }
13846
+ session.sendMessage(value, { contentParts });
13847
+ if (hasAttachments) {
13848
+ attachmentManager.clearAttachments();
13798
13849
  }
13799
13850
  },
13800
13851
  streaming: false,
@@ -13873,6 +13924,9 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
13873
13924
  attachmentManager == null ? void 0 : attachmentManager.handleFileSelect(target.files);
13874
13925
  target.value = "";
13875
13926
  });
13927
+ const dropCfg = config.attachments.dropOverlay;
13928
+ const overlay = buildDropOverlay(dropCfg);
13929
+ container.appendChild(overlay);
13876
13930
  }
13877
13931
  const renderSlots = () => {
13878
13932
  var _a2, _b2;
@@ -14666,6 +14720,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14666
14720
  let lastScrollTop = 0;
14667
14721
  let scrollRAF = null;
14668
14722
  let isAutoScrolling = false;
14723
+ let hasPendingAutoScroll = false;
14669
14724
  const USER_SCROLL_THRESHOLD = 1;
14670
14725
  const BOTTOM_THRESHOLD = 8;
14671
14726
  const messageState = /* @__PURE__ */ new Map();
@@ -14758,6 +14813,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14758
14813
  cancelAnimationFrame(scrollRAF);
14759
14814
  scrollRAF = null;
14760
14815
  }
14816
+ hasPendingAutoScroll = false;
14761
14817
  cancelSmoothScroll();
14762
14818
  };
14763
14819
  const syncScrollToBottomButton = () => {
@@ -14787,9 +14843,14 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14787
14843
  const scheduleAutoScroll = (force = false) => {
14788
14844
  if (!autoFollow.isFollowing()) return;
14789
14845
  if (!force && !isStreaming) return;
14790
- cancelAutoScroll();
14846
+ if (scrollRAF !== null) {
14847
+ cancelAnimationFrame(scrollRAF);
14848
+ scrollRAF = null;
14849
+ }
14850
+ hasPendingAutoScroll = true;
14791
14851
  scrollRAF = requestAnimationFrame(() => {
14792
14852
  scrollRAF = null;
14853
+ hasPendingAutoScroll = false;
14793
14854
  if (!autoFollow.isFollowing()) return;
14794
14855
  smoothScrollToBottom(getScrollableContainer(), force ? 220 : 140);
14795
14856
  });
@@ -16108,7 +16169,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16108
16169
  lastScrollTop,
16109
16170
  nearBottom: isElementNearBottom(body, BOTTOM_THRESHOLD),
16110
16171
  userScrollThreshold: USER_SCROLL_THRESHOLD,
16111
- isAutoScrolling,
16172
+ isAutoScrolling: isAutoScrolling || hasPendingAutoScroll,
16112
16173
  pauseOnUpwardScroll: true,
16113
16174
  pauseWhenAwayFromBottom: false,
16114
16175
  resumeRequiresDownwardScroll: true
@@ -16223,6 +16284,61 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16223
16284
  }
16224
16285
  textarea == null ? void 0 : textarea.addEventListener("keydown", handleInputEnter);
16225
16286
  textarea == null ? void 0 : textarea.addEventListener("paste", handleInputPaste);
16287
+ const ATTACHMENT_DROP_ACTIVE_CLASS = "persona-attachment-drop-active";
16288
+ let attachmentFileDragDepth = 0;
16289
+ const clearAttachmentDropVisual = () => {
16290
+ attachmentFileDragDepth = 0;
16291
+ container.classList.remove(ATTACHMENT_DROP_ACTIVE_CLASS);
16292
+ };
16293
+ const attachmentDropHandlingActive = () => {
16294
+ var _a2;
16295
+ return ((_a2 = config.attachments) == null ? void 0 : _a2.enabled) === true && attachmentManager !== null;
16296
+ };
16297
+ const handleAttachmentDragEnterCapture = (e) => {
16298
+ if (!dataTransferHasFiles(e.dataTransfer) || !attachmentDropHandlingActive()) return;
16299
+ attachmentFileDragDepth++;
16300
+ if (attachmentFileDragDepth === 1) {
16301
+ container.classList.add(ATTACHMENT_DROP_ACTIVE_CLASS);
16302
+ }
16303
+ };
16304
+ const handleAttachmentDragLeaveCapture = (e) => {
16305
+ if (!dataTransferHasFiles(e.dataTransfer) || !attachmentDropHandlingActive()) return;
16306
+ attachmentFileDragDepth--;
16307
+ if (attachmentFileDragDepth <= 0) {
16308
+ clearAttachmentDropVisual();
16309
+ }
16310
+ };
16311
+ const handleAttachmentDragOverCapture = (e) => {
16312
+ if (!dataTransferHasFiles(e.dataTransfer) || !attachmentDropHandlingActive()) return;
16313
+ e.preventDefault();
16314
+ e.dataTransfer.dropEffect = "copy";
16315
+ };
16316
+ const handleAttachmentDropCapture = (e) => {
16317
+ var _a2;
16318
+ if (!dataTransferHasFiles(e.dataTransfer) || !attachmentDropHandlingActive()) return;
16319
+ e.preventDefault();
16320
+ e.stopPropagation();
16321
+ clearAttachmentDropVisual();
16322
+ const files = Array.from((_a2 = e.dataTransfer.files) != null ? _a2 : []);
16323
+ if (files.length === 0) return;
16324
+ void attachmentManager.handleFiles(files);
16325
+ };
16326
+ const attachmentDropCapture = true;
16327
+ container.addEventListener("dragenter", handleAttachmentDragEnterCapture, attachmentDropCapture);
16328
+ container.addEventListener("dragleave", handleAttachmentDragLeaveCapture, attachmentDropCapture);
16329
+ mount.addEventListener("dragover", handleAttachmentDragOverCapture, attachmentDropCapture);
16330
+ mount.addEventListener("drop", handleAttachmentDropCapture, attachmentDropCapture);
16331
+ const ownerDoc = mount.ownerDocument;
16332
+ const handleDocDragOver = (e) => {
16333
+ if (!attachmentDropHandlingActive()) return;
16334
+ e.preventDefault();
16335
+ };
16336
+ const handleDocDrop = (e) => {
16337
+ if (!attachmentDropHandlingActive()) return;
16338
+ e.preventDefault();
16339
+ };
16340
+ ownerDoc.addEventListener("dragover", handleDocDragOver);
16341
+ ownerDoc.addEventListener("drop", handleDocDrop);
16226
16342
  destroyCallbacks.push(() => {
16227
16343
  if (composerForm) {
16228
16344
  composerForm.removeEventListener("submit", handleSubmit);
@@ -16230,6 +16346,15 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16230
16346
  textarea == null ? void 0 : textarea.removeEventListener("keydown", handleInputEnter);
16231
16347
  textarea == null ? void 0 : textarea.removeEventListener("paste", handleInputPaste);
16232
16348
  });
16349
+ destroyCallbacks.push(() => {
16350
+ container.removeEventListener("dragenter", handleAttachmentDragEnterCapture, attachmentDropCapture);
16351
+ container.removeEventListener("dragleave", handleAttachmentDragLeaveCapture, attachmentDropCapture);
16352
+ mount.removeEventListener("dragover", handleAttachmentDragOverCapture, attachmentDropCapture);
16353
+ mount.removeEventListener("drop", handleAttachmentDropCapture, attachmentDropCapture);
16354
+ ownerDoc.removeEventListener("dragover", handleDocDragOver);
16355
+ ownerDoc.removeEventListener("drop", handleDocDrop);
16356
+ clearAttachmentDropVisual();
16357
+ });
16233
16358
  destroyCallbacks.push(() => {
16234
16359
  session.cancel();
16235
16360
  });
@@ -16244,7 +16369,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16244
16369
  }
16245
16370
  const controller = {
16246
16371
  update(nextConfig) {
16247
- var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2, _o2, _p2, _q2, _r2, _s2, _t2, _u2, _v2, _w2, _x2, _y2, _z2, _A2, _B2, _C2, _D2, _E2, _F2, _G2, _H2, _I2, _J2, _K2, _L2, _M2, _N2, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a;
16372
+ var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2, _o2, _p2, _q2, _r2, _s2, _t2, _u2, _v2, _w2, _x2, _y2, _z2, _A2, _B2, _C2, _D2, _E2, _F2, _G2, _H2, _I2, _J2, _K2, _L2, _M2, _N2, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab;
16248
16373
  const previousToolCallConfig = config.toolCall;
16249
16374
  const previousMessageActions = config.messageActions;
16250
16375
  const previousLayoutMessages = (_a2 = config.layout) == null ? void 0 : _a2.messages;
@@ -17002,6 +17127,9 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17002
17127
  }
17003
17128
  });
17004
17129
  }
17130
+ if (!container.querySelector(".persona-attachment-drop-overlay")) {
17131
+ container.appendChild(buildDropOverlay(attachmentsConfig.dropOverlay));
17132
+ }
17005
17133
  } else {
17006
17134
  attachmentButtonWrapper.style.display = "";
17007
17135
  const attachmentsConfig = (_Oa = config.attachments) != null ? _Oa : {};
@@ -17024,14 +17152,15 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17024
17152
  if (attachmentManager) {
17025
17153
  attachmentManager.clearAttachments();
17026
17154
  }
17155
+ (_Ra = container.querySelector(".persona-attachment-drop-overlay")) == null ? void 0 : _Ra.remove();
17027
17156
  }
17028
- const sendButtonConfig = (_Ra = config.sendButton) != null ? _Ra : {};
17029
- const useIcon = (_Sa = sendButtonConfig.useIcon) != null ? _Sa : false;
17030
- const iconText = (_Ta = sendButtonConfig.iconText) != null ? _Ta : "\u2191";
17157
+ const sendButtonConfig = (_Sa = config.sendButton) != null ? _Sa : {};
17158
+ const useIcon = (_Ta = sendButtonConfig.useIcon) != null ? _Ta : false;
17159
+ const iconText = (_Ua = sendButtonConfig.iconText) != null ? _Ua : "\u2191";
17031
17160
  const iconName = sendButtonConfig.iconName;
17032
- const tooltipText = (_Ua = sendButtonConfig.tooltipText) != null ? _Ua : "Send message";
17033
- const showTooltip = (_Va = sendButtonConfig.showTooltip) != null ? _Va : false;
17034
- const buttonSize = (_Wa = sendButtonConfig.size) != null ? _Wa : "40px";
17161
+ const tooltipText = (_Va = sendButtonConfig.tooltipText) != null ? _Va : "Send message";
17162
+ const showTooltip = (_Wa = sendButtonConfig.showTooltip) != null ? _Wa : false;
17163
+ const buttonSize = (_Xa = sendButtonConfig.size) != null ? _Xa : "40px";
17035
17164
  const backgroundColor = sendButtonConfig.backgroundColor;
17036
17165
  const textColor = sendButtonConfig.textColor;
17037
17166
  if (useIcon) {
@@ -17068,7 +17197,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17068
17197
  sendButton.classList.add("persona-bg-persona-primary");
17069
17198
  }
17070
17199
  } else {
17071
- sendButton.textContent = (_Ya = (_Xa = config.copy) == null ? void 0 : _Xa.sendButtonLabel) != null ? _Ya : "Send";
17200
+ sendButton.textContent = (_Za = (_Ya = config.copy) == null ? void 0 : _Ya.sendButtonLabel) != null ? _Za : "Send";
17072
17201
  sendButton.style.width = "";
17073
17202
  sendButton.style.height = "";
17074
17203
  sendButton.style.minWidth = "";
@@ -17128,7 +17257,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17128
17257
  } else if (tooltip) {
17129
17258
  tooltip.style.display = "none";
17130
17259
  }
17131
- const updatedContentMaxWidth = (_Za = config.layout) == null ? void 0 : _Za.contentMaxWidth;
17260
+ const updatedContentMaxWidth = (__a = config.layout) == null ? void 0 : __a.contentMaxWidth;
17132
17261
  if (updatedContentMaxWidth) {
17133
17262
  messagesWrapper.style.maxWidth = updatedContentMaxWidth;
17134
17263
  messagesWrapper.style.marginLeft = "auto";
@@ -17160,8 +17289,8 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17160
17289
  suggestions.style.marginRight = "";
17161
17290
  }
17162
17291
  }
17163
- const statusIndicatorConfig = (__a = config.statusIndicator) != null ? __a : {};
17164
- const isVisible = (_$a = statusIndicatorConfig.visible) != null ? _$a : true;
17292
+ const statusIndicatorConfig = (_$a = config.statusIndicator) != null ? _$a : {};
17293
+ const isVisible = (_ab = statusIndicatorConfig.visible) != null ? _ab : true;
17165
17294
  statusText.style.display = isVisible ? "" : "none";
17166
17295
  if (session) {
17167
17296
  const currentStatus = session.getStatus();
package/dist/widget.css CHANGED
@@ -93,6 +93,35 @@
93
93
  gap: 1.5rem;
94
94
  }
95
95
 
96
+ [data-persona-root] .persona-widget-container .persona-attachment-drop-overlay {
97
+ display: none;
98
+ position: absolute;
99
+ inset: var(--persona-drop-overlay-inset, 0);
100
+ z-index: 50;
101
+ flex-direction: column;
102
+ align-items: center;
103
+ justify-content: center;
104
+ gap: 0.5rem;
105
+ pointer-events: none;
106
+ background: var(--persona-drop-overlay-bg, rgba(59, 130, 246, 0.08));
107
+ -webkit-backdrop-filter: blur(var(--persona-drop-overlay-blur, 8px));
108
+ backdrop-filter: blur(var(--persona-drop-overlay-blur, 8px));
109
+ border: var(--persona-drop-overlay-border, 2px dashed rgba(59, 130, 246, 0.4));
110
+ border-radius: var(--persona-drop-overlay-radius, inherit);
111
+ transition: opacity 0.15s ease;
112
+ }
113
+
114
+ [data-persona-root] .persona-widget-container .persona-attachment-drop-overlay .persona-drop-overlay-label {
115
+ font-size: var(--persona-drop-overlay-label-size, 0.875rem);
116
+ color: var(--persona-drop-overlay-label-color, rgba(59, 130, 246, 0.8));
117
+ font-weight: 500;
118
+ user-select: none;
119
+ }
120
+
121
+ [data-persona-root] .persona-widget-container.persona-attachment-drop-active .persona-attachment-drop-overlay {
122
+ display: flex;
123
+ }
124
+
96
125
  /* Widget CSS Variables - scoped to widget root to avoid polluting global namespace */
97
126
  [data-persona-root] {
98
127
  --persona-radius-sm: 0.125rem;
@@ -935,6 +964,7 @@
935
964
  }
936
965
 
937
966
  .persona-widget-container {
967
+ position: relative;
938
968
  border-radius: var(--persona-panel-radius, var(--persona-radius-xl, 0.75rem));
939
969
  }
940
970