@runtypelabs/persona 3.10.1 → 3.12.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.
@@ -124,12 +124,14 @@ var DEFAULT_WIDGET_CONFIG = {
124
124
  activePreview: false,
125
125
  grouped: false,
126
126
  previewMaxLines: 3,
127
- expandable: true
127
+ expandable: true,
128
+ loadingAnimation: "none"
128
129
  },
129
130
  reasoningDisplay: {
130
131
  activePreview: false,
131
132
  previewMaxLines: 3,
132
- expandable: true
133
+ expandable: true,
134
+ loadingAnimation: "none"
133
135
  }
134
136
  },
135
137
  suggestionChips: [
@@ -3236,6 +3238,70 @@ var describeToolTitle = (tool) => {
3236
3238
  }
3237
3239
  return "Using tool...";
3238
3240
  };
3241
+ var formatElapsedMs = (ms) => {
3242
+ const seconds = ms / 1e3;
3243
+ if (seconds < 0.1) return "<0.1s";
3244
+ if (seconds >= 10) return `${Math.round(seconds)}s`;
3245
+ return `${seconds.toFixed(1).replace(/\.0$/, "")}s`;
3246
+ };
3247
+ var computeToolElapsed = (tool) => {
3248
+ var _a, _b, _c;
3249
+ const durationMs = typeof tool.duration === "number" ? tool.duration : typeof tool.durationMs === "number" ? tool.durationMs : Math.max(
3250
+ 0,
3251
+ ((_a = tool.completedAt) != null ? _a : Date.now()) - ((_c = (_b = tool.startedAt) != null ? _b : tool.completedAt) != null ? _c : Date.now())
3252
+ );
3253
+ return formatElapsedMs(durationMs);
3254
+ };
3255
+ var computeReasoningElapsed = (reasoning) => {
3256
+ var _a, _b, _c;
3257
+ const durationMs = reasoning.durationMs !== void 0 ? reasoning.durationMs : Math.max(
3258
+ 0,
3259
+ ((_a = reasoning.completedAt) != null ? _a : Date.now()) - ((_c = (_b = reasoning.startedAt) != null ? _b : reasoning.completedAt) != null ? _c : Date.now())
3260
+ );
3261
+ return formatElapsedMs(durationMs);
3262
+ };
3263
+ var resolveToolHeaderText = (tool, template, fallback) => {
3264
+ var _a;
3265
+ if (!template) return fallback;
3266
+ const toolName = ((_a = tool.name) == null ? void 0 : _a.trim()) || "tool";
3267
+ const duration = computeToolElapsed(tool);
3268
+ return template.replace(/\{toolName\}/g, toolName).replace(/\{duration\}/g, duration);
3269
+ };
3270
+ var parseFormattedTemplate = (template, toolName) => {
3271
+ const resolved = template.replace(/\{toolName\}/g, toolName);
3272
+ const segments = [];
3273
+ const regex = /\*\*(.+?)\*\*|\*(.+?)\*|~(.+?)~/g;
3274
+ let lastIndex = 0;
3275
+ let match;
3276
+ while ((match = regex.exec(resolved)) !== null) {
3277
+ if (match.index > lastIndex) {
3278
+ pushSegments(segments, resolved.slice(lastIndex, match.index), []);
3279
+ }
3280
+ if (match[1] !== void 0) {
3281
+ pushSegments(segments, match[1], ["bold"]);
3282
+ } else if (match[2] !== void 0) {
3283
+ pushSegments(segments, match[2], ["italic"]);
3284
+ } else if (match[3] !== void 0) {
3285
+ pushSegments(segments, match[3], ["dim"]);
3286
+ }
3287
+ lastIndex = match.index + match[0].length;
3288
+ }
3289
+ if (lastIndex < resolved.length) {
3290
+ pushSegments(segments, resolved.slice(lastIndex), []);
3291
+ }
3292
+ return segments;
3293
+ };
3294
+ var pushSegments = (segments, text, styles) => {
3295
+ const parts = text.split("{duration}");
3296
+ for (let i = 0; i < parts.length; i++) {
3297
+ if (parts[i]) {
3298
+ segments.push({ text: parts[i], styles });
3299
+ }
3300
+ if (i < parts.length - 1) {
3301
+ segments.push({ text: "{duration}", styles, isDuration: true });
3302
+ }
3303
+ }
3304
+ };
3239
3305
  var createRegexJsonParserInternal = () => {
3240
3306
  let extractedText = null;
3241
3307
  let processedLength = 0;
@@ -7853,10 +7919,24 @@ var morphMessages = (container, newContent, options = {}) => {
7853
7919
  Idiomorph.morph(container, newContent.innerHTML, {
7854
7920
  morphStyle: "innerHTML",
7855
7921
  callbacks: {
7856
- beforeNodeMorphed(oldNode, _newNode) {
7922
+ beforeNodeMorphed(oldNode, newNode) {
7923
+ var _a, _b;
7857
7924
  if (!(oldNode instanceof HTMLElement)) return;
7858
7925
  if (preserveTypingAnimation) {
7859
- if (oldNode.classList.contains("persona-animate-typing") || oldNode.hasAttribute("data-preserve-animation")) {
7926
+ if (oldNode.classList.contains("persona-animate-typing")) {
7927
+ return false;
7928
+ }
7929
+ if (oldNode.hasAttribute("data-preserve-animation")) {
7930
+ if (newNode instanceof HTMLElement && !newNode.hasAttribute("data-preserve-animation")) {
7931
+ return;
7932
+ }
7933
+ if (newNode instanceof HTMLElement && newNode.hasAttribute("data-preserve-animation")) {
7934
+ const oldText = (_a = oldNode.textContent) != null ? _a : "";
7935
+ const newText = (_b = newNode.textContent) != null ? _b : "";
7936
+ if (oldText !== newText) {
7937
+ return;
7938
+ }
7939
+ }
7860
7940
  return false;
7861
7941
  }
7862
7942
  }
@@ -7867,7 +7947,7 @@ var morphMessages = (container, newContent, options = {}) => {
7867
7947
 
7868
7948
  // src/utils/message-fingerprint.ts
7869
7949
  function computeMessageFingerprint(message, configVersion) {
7870
- 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;
7950
+ 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;
7871
7951
  return [
7872
7952
  message.id,
7873
7953
  message.role,
@@ -7879,11 +7959,12 @@ function computeMessageFingerprint(message, configVersion) {
7879
7959
  (_i = (_h = message.llmContent) == null ? void 0 : _h.length) != null ? _i : 0,
7880
7960
  (_k = (_j = message.approval) == null ? void 0 : _j.status) != null ? _k : "",
7881
7961
  (_m = (_l = message.toolCall) == null ? void 0 : _l.status) != null ? _m : "",
7882
- (_p = (_o = (_n = message.toolCall) == null ? void 0 : _n.chunks) == null ? void 0 : _o.length) != null ? _p : 0,
7883
- (_t = (_s = (_r = (_q = message.toolCall) == null ? void 0 : _q.chunks) == null ? void 0 : _r[message.toolCall.chunks.length - 1]) == null ? void 0 : _s.slice(-32)) != null ? _t : "",
7884
- typeof ((_u = message.toolCall) == null ? void 0 : _u.args) === "string" ? message.toolCall.args.length : ((_v = message.toolCall) == null ? void 0 : _v.args) ? JSON.stringify(message.toolCall.args).length : 0,
7885
- (_y = (_x = (_w = message.reasoning) == null ? void 0 : _w.chunks) == null ? void 0 : _x.length) != null ? _y : 0,
7886
- (_A = (_z = message.contentParts) == null ? void 0 : _z.length) != null ? _A : 0,
7962
+ (_o = (_n = message.toolCall) == null ? void 0 : _n.name) != null ? _o : "",
7963
+ (_r = (_q = (_p = message.toolCall) == null ? void 0 : _p.chunks) == null ? void 0 : _q.length) != null ? _r : 0,
7964
+ (_v = (_u = (_t = (_s = message.toolCall) == null ? void 0 : _s.chunks) == null ? void 0 : _t[message.toolCall.chunks.length - 1]) == null ? void 0 : _u.slice(-32)) != null ? _v : "",
7965
+ typeof ((_w = message.toolCall) == null ? void 0 : _w.args) === "string" ? message.toolCall.args.length : ((_x = message.toolCall) == null ? void 0 : _x.args) ? JSON.stringify(message.toolCall.args).length : 0,
7966
+ (_A = (_z = (_y = message.reasoning) == null ? void 0 : _y.chunks) == null ? void 0 : _z.length) != null ? _A : 0,
7967
+ (_C = (_B = message.contentParts) == null ? void 0 : _B.length) != null ? _C : 0,
7887
7968
  configVersion
7888
7969
  ].join("\0");
7889
7970
  }
@@ -10005,7 +10086,7 @@ var updateReasoningBubbleUI = (messageId, bubble) => {
10005
10086
  }
10006
10087
  };
10007
10088
  var createReasoningBubble = (message, config) => {
10008
- var _a, _b, _c, _d, _e, _f, _g;
10089
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
10009
10090
  const reasoning = message.reasoning;
10010
10091
  const bubble = createElement(
10011
10092
  "div",
@@ -10048,13 +10129,23 @@ var createReasoningBubble = (message, config) => {
10048
10129
  const headerContent = createElement("div", "persona-flex persona-flex-col persona-text-left");
10049
10130
  const title = createElement("span", "persona-text-xs persona-text-persona-primary");
10050
10131
  const defaultSummary = "Thinking...";
10051
- const customSummary = (_e = (_d = config == null ? void 0 : config.reasoning) == null ? void 0 : _d.renderCollapsedSummary) == null ? void 0 : _e.call(_d, {
10132
+ const reasoningConfig = (_d = config == null ? void 0 : config.reasoning) != null ? _d : {};
10133
+ const startedAt = String((_e = reasoning.startedAt) != null ? _e : Date.now());
10134
+ const createElapsedSpan = () => {
10135
+ const span = createElement("span", "");
10136
+ span.setAttribute("data-tool-elapsed", startedAt);
10137
+ span.textContent = computeReasoningElapsed(reasoning);
10138
+ return span;
10139
+ };
10140
+ const customSummary = (_f = reasoningConfig.renderCollapsedSummary) == null ? void 0 : _f.call(reasoningConfig, {
10052
10141
  message,
10053
10142
  reasoning,
10054
10143
  defaultSummary,
10055
10144
  previewText,
10056
10145
  isActive,
10057
- config: config != null ? config : {}
10146
+ config: config != null ? config : {},
10147
+ elapsed: computeReasoningElapsed(reasoning),
10148
+ createElapsedElement: createElapsedSpan
10058
10149
  });
10059
10150
  if (typeof customSummary === "string" && customSummary.trim()) {
10060
10151
  title.textContent = customSummary;
@@ -10068,10 +10159,101 @@ var createReasoningBubble = (message, config) => {
10068
10159
  const status = createElement("span", "persona-text-xs persona-text-persona-primary");
10069
10160
  status.textContent = describeReasonStatus(reasoning);
10070
10161
  headerContent.appendChild(status);
10071
- if (reasoning.status === "complete") {
10072
- title.style.display = "none";
10073
- } else {
10162
+ const loadingAnimation = (_g = reasoningDisplayConfig.loadingAnimation) != null ? _g : "none";
10163
+ const activeTemplate = reasoningConfig.activeTextTemplate;
10164
+ const completeTemplate = reasoningConfig.completeTextTemplate;
10165
+ const currentTemplate = isActive ? activeTemplate : completeTemplate;
10166
+ const skipCustomElement = customSummary instanceof HTMLElement;
10167
+ const appendCharSpans = (container, text2, startIndex) => {
10168
+ let idx = startIndex;
10169
+ for (const char of text2) {
10170
+ const span = createElement("span", "persona-tool-char");
10171
+ span.style.setProperty("--char-index", String(idx));
10172
+ span.textContent = char === " " ? "\xA0" : char;
10173
+ container.appendChild(span);
10174
+ idx++;
10175
+ }
10176
+ return idx;
10177
+ };
10178
+ const renderFormattedTitle = (template, animated) => {
10179
+ title.textContent = "";
10180
+ const segments = parseFormattedTemplate(template, "");
10181
+ let charIndex = 0;
10182
+ for (const seg of segments) {
10183
+ const parent = seg.styles.length > 0 ? (() => {
10184
+ const w = createElement("span", seg.styles.map((s) => `persona-tool-text-${s}`).join(" "));
10185
+ title.appendChild(w);
10186
+ return w;
10187
+ })() : title;
10188
+ if (seg.isDuration && isActive) {
10189
+ parent.appendChild(createElapsedSpan());
10190
+ } else {
10191
+ const text2 = seg.isDuration ? computeReasoningElapsed(reasoning) : seg.text;
10192
+ if (animated) {
10193
+ charIndex = appendCharSpans(parent, text2, charIndex);
10194
+ } else {
10195
+ parent.appendChild(document.createTextNode(text2));
10196
+ }
10197
+ }
10198
+ }
10199
+ };
10200
+ if (!skipCustomElement && currentTemplate) {
10201
+ status.style.display = "none";
10202
+ title.style.display = "";
10203
+ if (isActive && loadingAnimation !== "none") {
10204
+ const animDuration = (_h = reasoningConfig.loadingAnimationDuration) != null ? _h : 2e3;
10205
+ title.setAttribute("data-preserve-animation", "true");
10206
+ if (loadingAnimation === "pulse") {
10207
+ title.classList.add("persona-tool-loading-pulse");
10208
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10209
+ renderFormattedTitle(currentTemplate, false);
10210
+ } else {
10211
+ title.classList.add(`persona-tool-loading-${loadingAnimation}`);
10212
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10213
+ if (loadingAnimation === "shimmer-color") {
10214
+ if (reasoningConfig.loadingAnimationColor) {
10215
+ title.style.setProperty("--persona-tool-anim-color", reasoningConfig.loadingAnimationColor);
10216
+ }
10217
+ if (reasoningConfig.loadingAnimationSecondaryColor) {
10218
+ title.style.setProperty("--persona-tool-anim-secondary-color", reasoningConfig.loadingAnimationSecondaryColor);
10219
+ }
10220
+ }
10221
+ renderFormattedTitle(currentTemplate, true);
10222
+ }
10223
+ } else {
10224
+ renderFormattedTitle(currentTemplate, false);
10225
+ }
10226
+ } else if (!skipCustomElement && isActive && loadingAnimation !== "none") {
10074
10227
  title.style.display = "";
10228
+ const animDuration = (_i = reasoningConfig.loadingAnimationDuration) != null ? _i : 2e3;
10229
+ title.setAttribute("data-preserve-animation", "true");
10230
+ if (loadingAnimation === "pulse") {
10231
+ title.classList.add("persona-tool-loading-pulse");
10232
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10233
+ } else {
10234
+ title.classList.add(`persona-tool-loading-${loadingAnimation}`);
10235
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10236
+ if (loadingAnimation === "shimmer-color") {
10237
+ if (reasoningConfig.loadingAnimationColor) {
10238
+ title.style.setProperty("--persona-tool-anim-color", reasoningConfig.loadingAnimationColor);
10239
+ }
10240
+ if (reasoningConfig.loadingAnimationSecondaryColor) {
10241
+ title.style.setProperty("--persona-tool-anim-secondary-color", reasoningConfig.loadingAnimationSecondaryColor);
10242
+ }
10243
+ }
10244
+ const text2 = title.textContent || defaultSummary;
10245
+ title.textContent = "";
10246
+ appendCharSpans(title, text2, 0);
10247
+ }
10248
+ if (reasoning.status === "complete") {
10249
+ title.style.display = "none";
10250
+ }
10251
+ } else if (!skipCustomElement) {
10252
+ if (reasoning.status === "complete") {
10253
+ title.style.display = "none";
10254
+ } else {
10255
+ title.style.display = "";
10256
+ }
10075
10257
  }
10076
10258
  let toggleIcon = null;
10077
10259
  if (expandable) {
@@ -10097,7 +10279,7 @@ var createReasoningBubble = (message, config) => {
10097
10279
  collapsedPreview.style.display = "none";
10098
10280
  collapsedPreview.style.whiteSpace = "pre-wrap";
10099
10281
  if (!expanded && isActive && reasoningDisplayConfig.activePreview && previewText) {
10100
- const renderedPreview = (_g = (_f = config == null ? void 0 : config.reasoning) == null ? void 0 : _f.renderCollapsedPreview) == null ? void 0 : _g.call(_f, {
10282
+ const renderedPreview = (_k = (_j = config == null ? void 0 : config.reasoning) == null ? void 0 : _j.renderCollapsedPreview) == null ? void 0 : _k.call(_j, {
10101
10283
  message,
10102
10284
  reasoning,
10103
10285
  defaultPreview: previewText,
@@ -10173,7 +10355,7 @@ var getToolPreviewText = (message, maxLines) => {
10173
10355
  return argsText.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).slice(0, maxLines).join("\n");
10174
10356
  };
10175
10357
  var getToolSummaryText = (message, config) => {
10176
- var _a, _b, _c, _d;
10358
+ var _a, _b, _c, _d, _e;
10177
10359
  const tool = message.toolCall;
10178
10360
  const toolDisplayConfig = (_a = config == null ? void 0 : config.features) == null ? void 0 : _a.toolCallDisplay;
10179
10361
  const collapsedMode = (_b = toolDisplayConfig == null ? void 0 : toolDisplayConfig.collapsedMode) != null ? _b : "tool-call";
@@ -10183,12 +10365,18 @@ var getToolSummaryText = (message, config) => {
10183
10365
  return { summary: defaultSummary, previewText, isActive: false };
10184
10366
  }
10185
10367
  const isActive = tool.status !== "complete";
10368
+ const toolCallConfig = (_d = config == null ? void 0 : config.toolCall) != null ? _d : {};
10186
10369
  let summary = defaultSummary;
10187
10370
  if (collapsedMode === "tool-name") {
10188
- summary = ((_d = tool.name) == null ? void 0 : _d.trim()) || defaultSummary;
10371
+ summary = ((_e = tool.name) == null ? void 0 : _e.trim()) || defaultSummary;
10189
10372
  } else if (collapsedMode === "tool-preview" && previewText) {
10190
10373
  summary = previewText;
10191
10374
  }
10375
+ if (isActive && toolCallConfig.activeTextTemplate) {
10376
+ summary = resolveToolHeaderText(tool, toolCallConfig.activeTextTemplate, summary);
10377
+ } else if (!isActive && toolCallConfig.completeTextTemplate) {
10378
+ summary = resolveToolHeaderText(tool, toolCallConfig.completeTextTemplate, summary);
10379
+ }
10192
10380
  return { summary, previewText, isActive };
10193
10381
  };
10194
10382
  var updateToolBubbleUI = (messageId, bubble, config) => {
@@ -10218,7 +10406,7 @@ var updateToolBubbleUI = (messageId, bubble, config) => {
10218
10406
  }
10219
10407
  };
10220
10408
  var createToolBubble = (message, config) => {
10221
- var _a, _b, _c, _d, _e, _f;
10409
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
10222
10410
  const tool = message.toolCall;
10223
10411
  const toolCallConfig = (_a = config == null ? void 0 : config.toolCall) != null ? _a : {};
10224
10412
  const bubble = createElement(
@@ -10286,14 +10474,23 @@ var createToolBubble = (message, config) => {
10286
10474
  if (toolCallConfig.headerTextColor) {
10287
10475
  title.style.color = toolCallConfig.headerTextColor;
10288
10476
  }
10289
- const customSummary = (_e = toolCallConfig.renderCollapsedSummary) == null ? void 0 : _e.call(toolCallConfig, {
10477
+ const startedAt = String((_d = tool.startedAt) != null ? _d : Date.now());
10478
+ const createElapsedSpan = () => {
10479
+ const span = createElement("span", "");
10480
+ span.setAttribute("data-tool-elapsed", startedAt);
10481
+ span.textContent = computeToolElapsed(tool);
10482
+ return span;
10483
+ };
10484
+ const customSummary = (_f = toolCallConfig.renderCollapsedSummary) == null ? void 0 : _f.call(toolCallConfig, {
10290
10485
  message,
10291
10486
  toolCall: tool,
10292
10487
  defaultSummary: summary,
10293
10488
  previewText,
10294
- collapsedMode: (_d = toolDisplayConfig.collapsedMode) != null ? _d : "tool-call",
10489
+ collapsedMode: (_e = toolDisplayConfig.collapsedMode) != null ? _e : "tool-call",
10295
10490
  isActive,
10296
- config: config != null ? config : {}
10491
+ config: config != null ? config : {},
10492
+ elapsed: computeToolElapsed(tool),
10493
+ createElapsedElement: createElapsedSpan
10297
10494
  });
10298
10495
  if (typeof customSummary === "string" && customSummary.trim()) {
10299
10496
  title.textContent = customSummary;
@@ -10304,6 +10501,79 @@ var createToolBubble = (message, config) => {
10304
10501
  title.textContent = summary;
10305
10502
  headerContent.appendChild(title);
10306
10503
  }
10504
+ const loadingAnimation = (_g = toolDisplayConfig.loadingAnimation) != null ? _g : "none";
10505
+ const activeTemplate = toolCallConfig.activeTextTemplate;
10506
+ const completeTemplate = toolCallConfig.completeTextTemplate;
10507
+ const currentTemplate = isActive ? activeTemplate : completeTemplate;
10508
+ const skipCustomElement = customSummary instanceof HTMLElement;
10509
+ const appendCharSpans = (container, text, startIndex) => {
10510
+ let idx = startIndex;
10511
+ for (const char of text) {
10512
+ const span = createElement("span", "persona-tool-char");
10513
+ span.style.setProperty("--char-index", String(idx));
10514
+ span.textContent = char === " " ? "\xA0" : char;
10515
+ container.appendChild(span);
10516
+ idx++;
10517
+ }
10518
+ return idx;
10519
+ };
10520
+ const renderFormattedTitle = (template, animated) => {
10521
+ var _a2;
10522
+ title.textContent = "";
10523
+ const toolName = ((_a2 = tool.name) == null ? void 0 : _a2.trim()) || "tool";
10524
+ const segments = parseFormattedTemplate(template, toolName);
10525
+ let charIndex = 0;
10526
+ for (const seg of segments) {
10527
+ const parent = seg.styles.length > 0 ? (() => {
10528
+ const w = createElement("span", seg.styles.map((s) => `persona-tool-text-${s}`).join(" "));
10529
+ title.appendChild(w);
10530
+ return w;
10531
+ })() : title;
10532
+ if (seg.isDuration && isActive) {
10533
+ parent.appendChild(createElapsedSpan());
10534
+ } else {
10535
+ const text = seg.isDuration ? computeToolElapsed(tool) : seg.text;
10536
+ if (animated) {
10537
+ charIndex = appendCharSpans(parent, text, charIndex);
10538
+ } else {
10539
+ parent.appendChild(document.createTextNode(text));
10540
+ }
10541
+ }
10542
+ }
10543
+ };
10544
+ if (!skipCustomElement) {
10545
+ if (isActive && loadingAnimation !== "none") {
10546
+ const animDuration = (_h = toolCallConfig.loadingAnimationDuration) != null ? _h : 2e3;
10547
+ title.setAttribute("data-preserve-animation", "true");
10548
+ if (loadingAnimation === "pulse") {
10549
+ title.classList.add("persona-tool-loading-pulse");
10550
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10551
+ if (currentTemplate) {
10552
+ renderFormattedTitle(currentTemplate, false);
10553
+ }
10554
+ } else {
10555
+ title.classList.add(`persona-tool-loading-${loadingAnimation}`);
10556
+ title.style.setProperty("--persona-tool-anim-duration", `${animDuration}ms`);
10557
+ if (loadingAnimation === "shimmer-color") {
10558
+ if (toolCallConfig.loadingAnimationColor) {
10559
+ title.style.setProperty("--persona-tool-anim-color", toolCallConfig.loadingAnimationColor);
10560
+ }
10561
+ if (toolCallConfig.loadingAnimationSecondaryColor) {
10562
+ title.style.setProperty("--persona-tool-anim-secondary-color", toolCallConfig.loadingAnimationSecondaryColor);
10563
+ }
10564
+ }
10565
+ if (currentTemplate) {
10566
+ renderFormattedTitle(currentTemplate, true);
10567
+ } else {
10568
+ const text = title.textContent || summary;
10569
+ title.textContent = "";
10570
+ appendCharSpans(title, text, 0);
10571
+ }
10572
+ }
10573
+ } else if (currentTemplate) {
10574
+ renderFormattedTitle(currentTemplate, false);
10575
+ }
10576
+ }
10307
10577
  let toggleIcon = null;
10308
10578
  if (expandable) {
10309
10579
  toggleIcon = createElement("div", "persona-flex persona-items-center");
@@ -10328,7 +10598,7 @@ var createToolBubble = (message, config) => {
10328
10598
  collapsedPreview.style.display = "none";
10329
10599
  collapsedPreview.style.whiteSpace = "pre-wrap";
10330
10600
  if (!expanded && isActive && toolDisplayConfig.activePreview && previewText) {
10331
- const renderedPreview = (_f = toolCallConfig.renderCollapsedPreview) == null ? void 0 : _f.call(toolCallConfig, {
10601
+ const renderedPreview = (_i = toolCallConfig.renderCollapsedPreview) == null ? void 0 : _i.call(toolCallConfig, {
10332
10602
  message,
10333
10603
  toolCall: tool,
10334
10604
  defaultPreview: previewText,
@@ -14721,8 +14991,9 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14721
14991
  let scrollRAF = null;
14722
14992
  let isAutoScrolling = false;
14723
14993
  let hasPendingAutoScroll = false;
14724
- const USER_SCROLL_THRESHOLD = 1;
14725
- const BOTTOM_THRESHOLD = 8;
14994
+ const USER_SCROLL_THRESHOLD = 4;
14995
+ const BOTTOM_THRESHOLD = 24;
14996
+ const AUTO_SCROLL_SNAP_THRESHOLD = 80;
14726
14997
  const messageState = /* @__PURE__ */ new Map();
14727
14998
  const voiceState = {
14728
14999
  active: false,
@@ -14863,6 +15134,14 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14863
15134
  lastScrollTop = element.scrollTop;
14864
15135
  return;
14865
15136
  }
15137
+ if (Math.abs(distance) >= AUTO_SCROLL_SNAP_THRESHOLD) {
15138
+ cancelSmoothScroll();
15139
+ isAutoScrolling = true;
15140
+ element.scrollTop = target;
15141
+ lastScrollTop = element.scrollTop;
15142
+ isAutoScrolling = false;
15143
+ return;
15144
+ }
14866
15145
  cancelSmoothScroll();
14867
15146
  const startTime = performance.now();
14868
15147
  isAutoScrolling = true;
@@ -15471,9 +15750,28 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15471
15750
  }
15472
15751
  };
15473
15752
  }
15753
+ let toolElapsedTimerId = null;
15754
+ const ensureToolElapsedTimer = () => {
15755
+ if (toolElapsedTimerId != null) return;
15756
+ toolElapsedTimerId = setInterval(() => {
15757
+ const spans = messagesWrapper.querySelectorAll("[data-tool-elapsed]");
15758
+ if (spans.length === 0) {
15759
+ clearInterval(toolElapsedTimerId);
15760
+ toolElapsedTimerId = null;
15761
+ return;
15762
+ }
15763
+ const now = Date.now();
15764
+ spans.forEach((span) => {
15765
+ const startedAt = Number(span.getAttribute("data-tool-elapsed"));
15766
+ if (!startedAt) return;
15767
+ span.textContent = formatElapsedMs(now - startedAt);
15768
+ });
15769
+ }, 100);
15770
+ };
15474
15771
  session = new AgentWidgetSession(config, {
15475
15772
  onMessagesChanged(messages) {
15476
15773
  renderMessagesWithPlugins(messagesWrapper, messages, postprocess);
15774
+ ensureToolElapsedTimer();
15477
15775
  if (session) {
15478
15776
  const hasUserMessage = messages.some((msg) => msg.role === "user");
15479
15777
  if (hasUserMessage) {
@@ -17636,6 +17934,10 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17636
17934
  return session.submitNPSFeedback(rating, comment);
17637
17935
  },
17638
17936
  destroy() {
17937
+ if (toolElapsedTimerId != null) {
17938
+ clearInterval(toolElapsedTimerId);
17939
+ toolElapsedTimerId = null;
17940
+ }
17639
17941
  destroyCallbacks.forEach((cb) => cb());
17640
17942
  wrapper.remove();
17641
17943
  launcherButtonInstance == null ? void 0 : launcherButtonInstance.destroy();
@@ -1 +1 @@
1
- "use strict";var t=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var m=(o,e)=>{for(var a in e)t(o,a,{get:e[a],enumerable:!0})},u=(o,e,a,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of c(e))!d.call(o,r)&&r!==a&&t(o,r,{get:()=>e[r],enumerable:!(s=l(e,r))||s.enumerable});return o};var g=o=>u(t({},"__esModule",{value:!0}),o);var h={};m(h,{THEME_EXAMPLES:()=>p,THEME_TOKEN_DOCS:()=>i,getThemeReference:()=>b});module.exports=g(h);var n={colors:{primary:{50:"#ffffff",100:"#f5f5f5",200:"#d4d4d4",300:"#a3a3a3",400:"#737373",500:"#171717",600:"#0f0f0f",700:"#0a0a0a",800:"#050505",900:"#030303",950:"#000000"},secondary:{50:"#f5f3ff",100:"#ede9fe",200:"#ddd6fe",300:"#c4b5fd",400:"#a78bfa",500:"#8b5cf6",600:"#7c3aed",700:"#6d28d9",800:"#5b21b6",900:"#4c1d95",950:"#2e1065"},accent:{50:"#ecfeff",100:"#cffafe",200:"#a5f3fc",300:"#67e8f9",400:"#22d3ee",500:"#06b6d4",600:"#0891b2",700:"#0e7490",800:"#155e75",900:"#164e63",950:"#083344"},gray:{50:"#f9fafb",100:"#f3f4f6",200:"#e5e7eb",300:"#d1d5db",400:"#9ca3af",500:"#6b7280",600:"#4b5563",700:"#374151",800:"#1f2937",900:"#111827",950:"#030712"},success:{50:"#f0fdf4",100:"#dcfce7",200:"#bbf7d0",300:"#86efac",400:"#4ade80",500:"#22c55e",600:"#16a34a",700:"#15803d",800:"#166534",900:"#14532d"},warning:{50:"#fefce8",100:"#fef9c3",200:"#fef08a",300:"#fde047",400:"#facc15",500:"#eab308",600:"#ca8a04",700:"#a16207",800:"#854d0e",900:"#713f12"},error:{50:"#fef2f2",100:"#fee2e2",200:"#fecaca",300:"#fca5a5",400:"#f87171",500:"#ef4444",600:"#dc2626",700:"#b91c1c",800:"#991b1b",900:"#7f1d1d"},info:{50:"#eff6ff",100:"#dbeafe",200:"#bfdbfe",300:"#93c5fd",400:"#60a5fa",500:"#3b82f6",600:"#2563eb",700:"#1d4ed8",800:"#1e40af",900:"#1e3a8a",950:"#172554"}},spacing:{0:"0px",1:"0.25rem",2:"0.5rem",3:"0.75rem",4:"1rem",5:"1.25rem",6:"1.5rem",8:"2rem",10:"2.5rem",12:"3rem",16:"4rem",20:"5rem",24:"6rem",32:"8rem",40:"10rem",48:"12rem",56:"14rem",64:"16rem"},typography:{fontFamily:{sans:'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',serif:'Georgia, Cambria, "Times New Roman", Times, serif',mono:"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace"},fontSize:{xs:"0.75rem",sm:"0.875rem",base:"1rem",lg:"1.125rem",xl:"1.25rem","2xl":"1.5rem","3xl":"1.875rem","4xl":"2.25rem"},fontWeight:{normal:"400",medium:"500",semibold:"600",bold:"700"},lineHeight:{tight:"1.25",normal:"1.5",relaxed:"1.625"}},shadows:{none:"none",sm:"0 1px 2px 0 rgb(0 0 0 / 0.05)",md:"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",lg:"0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",xl:"0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)","2xl":"0 25px 50px -12px rgb(0 0 0 / 0.25)"},borders:{none:"none",sm:"1px solid",md:"2px solid",lg:"4px solid"},radius:{none:"0px",sm:"0.125rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem",full:"9999px"}};var i={overview:"Persona uses a three-layer design token system: palette \u2192 semantic \u2192 components. Most themes only need palette.colors overrides \u2014 semantic and component layers auto-derive from palette values. Config also accepts non-theme appearance options (launcher, sendButton, toolCall, etc.).",layers:{palette:{description:"Primitive design tokens. Override specific shades to change the entire widget feel.",colors:{description:"7 color scales, each with shades 50 (lightest) to 950 (darkest). Override only the shades you need.",scales:{gray:"Neutrals \u2014 backgrounds, text, borders. Key shades: 50 (lightest bg), 100 (secondary bg), 200 (borders), 500 (muted text), 900 (primary text).",primary:"Brand color \u2014 buttons, links, interactive elements. Key shades: 500 (default), 600 (hover).",accent:"Secondary highlight. Key shades: 500 (default), 600 (hover).",secondary:"Tertiary color scale.",success:"Positive feedback (default: green).",warning:"Caution feedback (default: yellow).",error:"Error/danger feedback (default: red)."}},radius:{description:"Border radius scale. Add custom keys like launcher, button.",defaults:{none:"0px",sm:"0.125rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem",full:"9999px"}},typography:{fontFamily:"Three stacks: sans (system-ui), serif (Georgia), mono (ui-monospace). Override individual stack values.",fontSize:"Scale: xs (0.75rem), sm (0.875rem), base (1rem), lg (1.125rem), xl (1.25rem), 2xl (1.5rem), 3xl (1.875rem), 4xl (2.25rem).",fontWeight:"normal (400), medium (500), semibold (600), bold (700).",lineHeight:"tight (1.25), normal (1.5), relaxed (1.625)."},shadows:"Scale: none, sm, md, lg, xl, 2xl. Values are CSS box-shadow strings.",borders:"Scale: none, sm (1px solid), md (2px solid), lg (4px solid).",spacing:"Scale: 0 (0px), 1 (0.25rem), 2 (0.5rem), 3 (0.75rem), 4 (1rem), 5 (1.25rem), 6 (1.5rem), 8 (2rem), 10 (2.5rem), 12 (3rem), 16-64."},semantic:{description:'Design intent tokens. Auto-derived from palette by default. Override to redirect token resolution. Values are token reference strings like "palette.colors.primary.500".',colors:{primary:"palette.colors.primary.500 \u2014 Primary brand color.",secondary:"palette.colors.gray.500 \u2014 Secondary color.",accent:"palette.colors.primary.600 \u2014 Accent/interactive color.",surface:"palette.colors.gray.50 \u2014 Panel/card backgrounds.",background:"palette.colors.gray.50 \u2014 Page background.",container:"palette.colors.gray.100 \u2014 Container backgrounds.",text:"palette.colors.gray.900 \u2014 Primary text.",textMuted:"palette.colors.gray.500 \u2014 Muted/secondary text.",textInverse:"palette.colors.gray.50 \u2014 Text on dark backgrounds.",border:"palette.colors.gray.200 \u2014 Default border color.",divider:"palette.colors.gray.200 \u2014 Divider lines.",interactive:{default:"palette.colors.primary.500",hover:"palette.colors.primary.600",focus:"palette.colors.primary.700",active:"palette.colors.primary.800",disabled:"palette.colors.gray.300"},feedback:{success:"palette.colors.success.500",warning:"palette.colors.warning.500",error:"palette.colors.error.500",info:"palette.colors.primary.500"}},spacing:"xs (0.25rem), sm (0.5rem), md (1rem), lg (1.5rem), xl (2rem), 2xl (2.5rem).",typography:"fontFamily, fontSize, fontWeight, lineHeight \u2014 reference palette typography tokens."},components:{description:"UI element tokens. Rarely needed for basic theming. Override for fine-grained control. All values are token references or raw CSS strings.",button:{description:"Three variants: primary, secondary, ghost.",properties:"background, foreground, borderRadius, padding."},input:{description:"Message input field.",properties:"background, placeholder, borderRadius, padding, focus.border, focus.ring."},launcher:{description:"Floating launcher button.",properties:"size (60px), iconSize (28px), borderRadius, shadow."},panel:{description:"Chat panel container.",properties:"width, maxWidth (440px), height (600px), maxHeight, borderRadius, shadow."},header:{description:"Chat panel header.",properties:"background, border, borderRadius, padding, iconBackground, iconForeground, titleForeground, subtitleForeground, actionIconForeground, shadow, borderBottom."},message:{description:"Chat message bubbles.",user:"background, text, borderRadius, shadow.",assistant:"background, text, borderRadius, border (optional), shadow (optional)."},markdown:{description:"Markdown rendering in messages and artifact pane.",properties:"inlineCode (background, foreground), link.foreground, prose.fontFamily, heading.h1/h2 (fontSize, fontWeight)."},voice:"recording (indicator, background, border), processing (icon, background), speaking (icon).",approval:"requested (background, border, text), approve (background, foreground), deny (background, foreground).",attachment:"image (background, border).",scrollToBottom:"Floating scroll-to-bottom affordance shared by transcript and event stream: background, foreground, border, size, borderRadius, shadow, padding, gap, fontSize, iconSize.",toolBubble:"shadow \u2014 tool call row box-shadow.",reasoningBubble:"shadow \u2014 reasoning/thinking row box-shadow.",composer:"shadow \u2014 message input form box-shadow.",artifact:"toolbar (icon styling, copy menu), tab (background, active states), pane (background, toolbarBackground)."}},colorScheme:'"dark" merges darkTheme overrides on top of theme. "auto" detects system preference or <html class="dark">. "light" is default. colorScheme does NOT auto-invert colors \u2014 provide dark palette and semantic overrides yourself.',plugins:{description:"Plugins transform theme tokens before resolution. Use with createTheme().",available:{brandPlugin:'Auto-generates full color scales from a single brand hex: brandPlugin({ colors: { primary: "#7c3aed" } }).',accessibilityPlugin:"Enhanced focus indicators and disabled states.",highContrastPlugin:"Increased contrast for visual accessibility.",reducedMotionPlugin:"Disables all animations (sets transitions to 0ms).",animationsPlugin:"Adds transition and easing tokens."},usage:'createTheme(themeOverrides, { plugins: [brandPlugin({ colors: { primary: "#7c3aed" } })] })'},widgetConfig:{description:'Non-theme config options on the widget config object that affect appearance. These are siblings of "theme" in the config, not nested inside it.',launcher:{description:"Floating launcher button and panel positioning.",properties:{enabled:"Show/hide the launcher button.",title:"Header title text.",subtitle:"Header subtitle text.",position:'"bottom-right" | "bottom-left" | "top-right" | "top-left".',width:"Chat panel width (CSS value).",fullHeight:"Fill full height of container.",mountMode:'"floating" | "docked".',agentIconText:"Emoji/text for agent icon.",border:"Border style for launcher button.",shadow:"Box shadow for launcher button.",collapsedMaxWidth:"Max-width for launcher pill when panel closed."}},sendButton:{description:"Send button appearance.",properties:"backgroundColor, textColor, borderWidth, borderColor, paddingX, paddingY, iconText, iconName, size."},closeButton:{description:"Close button (on launcher config).",properties:"closeButtonSize, closeButtonColor, closeButtonBackgroundColor, closeButtonBorderWidth, closeButtonBorderColor, closeButtonBorderRadius."},clearChat:{description:"Clear chat button (on launcher.clearChat config).",properties:"enabled, iconColor, backgroundColor, borderWidth, borderColor, borderRadius, size."},scrollToBottom:{description:"Shared transcript + event-stream jump-to-latest affordance.",properties:'features.scrollToBottom.enabled, features.scrollToBottom.iconName, features.scrollToBottom.label (empty string renders icon-only). Defaults: enabled=true, iconName="arrow-down", label="".'},toolCall:{description:"Tool call display styling and collapsed/grouped rendering hooks.",properties:"shadow, backgroundColor, borderColor, borderWidth, borderRadius, headerBackgroundColor, headerTextColor, headerPaddingX, headerPaddingY, contentBackgroundColor, contentTextColor, contentPaddingX, contentPaddingY, codeBlockBackgroundColor, codeBlockBorderColor, codeBlockTextColor, toggleTextColor, labelTextColor, renderCollapsedSummary, renderCollapsedPreview, renderGroupedSummary."},reasoning:{description:"Reasoning/thinking row rendering hooks.",properties:"renderCollapsedSummary, renderCollapsedPreview."},approval:{description:"Tool approval bubble styling and behavior. Set to false to disable.",properties:"backgroundColor, borderColor, titleColor, descriptionColor, approveButtonColor, approveButtonTextColor, denyButtonColor, denyButtonTextColor, parameterBackgroundColor, parameterTextColor, title, approveLabel, denyLabel."},copy:{description:"Widget text content.",properties:"showWelcomeCard (boolean), welcomeTitle, welcomeSubtitle, inputPlaceholder, sendButtonLabel."},voiceRecognition:{description:"Voice input configuration.",properties:"enabled, pauseDuration, iconColor, backgroundColor."},textToSpeech:{description:"Text-to-speech for assistant messages.",properties:'enabled, provider ("browser" | "runtype"), browserFallback, voice, rate, pitch.'},suggestionChips:"string[] \u2014 Suggested prompts shown to the user.",messageActions:{description:"Message action buttons (copy, upvote, downvote).",properties:'enabled, showCopy, showUpvote, showDownvote, visibility ("hover" | "always"), align ("left" | "center" | "right"), layout ("pill-inside" | "row-inside").'},attachments:{description:"File attachment configuration.",properties:"enabled, allowedTypes (string[]), maxFileSize (bytes), maxFiles, buttonIconName, buttonTooltipText."},markdown:{description:"Markdown rendering configuration.",properties:"options (gfm, breaks, headerIds, headerPrefix, pedantic, mangle, silent), disableDefaultStyles."},layout:{description:"Layout configuration.",showHeader:"boolean \u2014 show/hide the header section entirely.",showFooter:"boolean \u2014 show/hide the footer/composer section entirely.",contentMaxWidth:'CSS width value for centering content (e.g. "720px", "90ch").',header:'"default" | "minimal". Options: showIcon, showTitle, showSubtitle, showCloseButton, showClearChat.',messages:'"bubble" | "flat" | "minimal". Options: groupConsecutive, avatar (show, position, userAvatar, assistantAvatar), timestamp (show, position).'},statusIndicator:{description:"Status text shown below the composer.",properties:{visible:"Show/hide the status indicator.",align:'"left" | "center" | "right" \u2014 text alignment (default: "right").',idleText:'Text shown when idle (default: "Online").',idleLink:"URL to open when idle text is clicked (wraps text in a link).",connectingText:'Text shown while connecting (default: "Connecting\u2026").',connectedText:'Text shown while streaming (default: "Streaming\u2026").',errorText:'Text shown on error (default: "Offline").'}},features:{description:"Feature flags.",properties:"showReasoning (AI thinking steps), showToolCalls (tool invocations), toolCallDisplay (collapsedMode, activePreview, activeMinHeight, previewMaxLines, grouped), reasoningDisplay (activePreview, activeMinHeight, previewMaxLines), artifacts (sidebar config)."}}},p={darkIndigo:{description:"Dark mode with indigo accent \u2014 override grays for dark backgrounds and semantic tokens for inverted text/surface",theme:{palette:{colors:{primary:{500:"#6366f1",600:"#4f46e5"},gray:{50:"#f1f5f9",100:"#1e293b",200:"#334155",500:"#94a3b8",900:"#0f172a",950:"#020617"}}},semantic:{colors:{surface:"palette.colors.gray.900",background:"palette.colors.gray.900",container:"palette.colors.gray.100",text:"palette.colors.gray.50",textMuted:"palette.colors.gray.500",textInverse:"palette.colors.gray.900",border:"palette.colors.gray.200"}}}},warmVintage:{description:"Warm sepia tones with serif font and subtle radius",theme:{palette:{colors:{primary:{500:"#b45309",600:"#92400e"},gray:{50:"#fef3c7",100:"#fef9c3",200:"#d6d3d1",500:"#78716c",900:"#44403c"}},radius:{sm:"0.125rem",md:"0.25rem",lg:"0.375rem"},typography:{fontFamily:{sans:'Georgia, Cambria, "Times New Roman", Times, serif'}}}}},neonCyberpunk:{description:"Neon on dark with monospace font \u2014 full semantic override for dark background",theme:{palette:{colors:{primary:{500:"#f0abfc",600:"#e879f9"},accent:{500:"#22d3ee",600:"#06b6d4"},gray:{50:"#f0abfc",100:"#1e0a3c",200:"#3b0764",500:"#c084fc",900:"#0c0a1a",950:"#050412"}},radius:{sm:"0",md:"0.25rem",lg:"0.375rem"},typography:{fontFamily:{sans:"ui-monospace, SFMono-Regular, Menlo, monospace"}}},semantic:{colors:{surface:"palette.colors.gray.900",background:"palette.colors.gray.950",container:"palette.colors.gray.100",text:"palette.colors.gray.50",textMuted:"palette.colors.gray.500",border:"palette.colors.gray.200"}}}},cleanRounded:{description:"Clean light theme with large radius and panel styling",theme:{palette:{radius:{sm:"6px",md:"8px",lg:"12px",launcher:"50px",button:"8px"}},components:{panel:{borderRadius:"16px",shadow:"palette.shadows.2xl"}}}}};function b(){return{tokenDocs:i,defaultColorPalette:n.colors,defaultRadius:n.radius,examples:p,sdkPresets:["shop","minimal","fullscreen"]}}0&&(module.exports={THEME_EXAMPLES,THEME_TOKEN_DOCS,getThemeReference});
1
+ "use strict";var t=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var m=(o,e)=>{for(var a in e)t(o,a,{get:e[a],enumerable:!0})},u=(o,e,a,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of c(e))!d.call(o,r)&&r!==a&&t(o,r,{get:()=>e[r],enumerable:!(s=l(e,r))||s.enumerable});return o};var g=o=>u(t({},"__esModule",{value:!0}),o);var h={};m(h,{THEME_EXAMPLES:()=>p,THEME_TOKEN_DOCS:()=>i,getThemeReference:()=>b});module.exports=g(h);var n={colors:{primary:{50:"#ffffff",100:"#f5f5f5",200:"#d4d4d4",300:"#a3a3a3",400:"#737373",500:"#171717",600:"#0f0f0f",700:"#0a0a0a",800:"#050505",900:"#030303",950:"#000000"},secondary:{50:"#f5f3ff",100:"#ede9fe",200:"#ddd6fe",300:"#c4b5fd",400:"#a78bfa",500:"#8b5cf6",600:"#7c3aed",700:"#6d28d9",800:"#5b21b6",900:"#4c1d95",950:"#2e1065"},accent:{50:"#ecfeff",100:"#cffafe",200:"#a5f3fc",300:"#67e8f9",400:"#22d3ee",500:"#06b6d4",600:"#0891b2",700:"#0e7490",800:"#155e75",900:"#164e63",950:"#083344"},gray:{50:"#f9fafb",100:"#f3f4f6",200:"#e5e7eb",300:"#d1d5db",400:"#9ca3af",500:"#6b7280",600:"#4b5563",700:"#374151",800:"#1f2937",900:"#111827",950:"#030712"},success:{50:"#f0fdf4",100:"#dcfce7",200:"#bbf7d0",300:"#86efac",400:"#4ade80",500:"#22c55e",600:"#16a34a",700:"#15803d",800:"#166534",900:"#14532d"},warning:{50:"#fefce8",100:"#fef9c3",200:"#fef08a",300:"#fde047",400:"#facc15",500:"#eab308",600:"#ca8a04",700:"#a16207",800:"#854d0e",900:"#713f12"},error:{50:"#fef2f2",100:"#fee2e2",200:"#fecaca",300:"#fca5a5",400:"#f87171",500:"#ef4444",600:"#dc2626",700:"#b91c1c",800:"#991b1b",900:"#7f1d1d"},info:{50:"#eff6ff",100:"#dbeafe",200:"#bfdbfe",300:"#93c5fd",400:"#60a5fa",500:"#3b82f6",600:"#2563eb",700:"#1d4ed8",800:"#1e40af",900:"#1e3a8a",950:"#172554"}},spacing:{0:"0px",1:"0.25rem",2:"0.5rem",3:"0.75rem",4:"1rem",5:"1.25rem",6:"1.5rem",8:"2rem",10:"2.5rem",12:"3rem",16:"4rem",20:"5rem",24:"6rem",32:"8rem",40:"10rem",48:"12rem",56:"14rem",64:"16rem"},typography:{fontFamily:{sans:'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',serif:'Georgia, Cambria, "Times New Roman", Times, serif',mono:"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace"},fontSize:{xs:"0.75rem",sm:"0.875rem",base:"1rem",lg:"1.125rem",xl:"1.25rem","2xl":"1.5rem","3xl":"1.875rem","4xl":"2.25rem"},fontWeight:{normal:"400",medium:"500",semibold:"600",bold:"700"},lineHeight:{tight:"1.25",normal:"1.5",relaxed:"1.625"}},shadows:{none:"none",sm:"0 1px 2px 0 rgb(0 0 0 / 0.05)",md:"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",lg:"0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",xl:"0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)","2xl":"0 25px 50px -12px rgb(0 0 0 / 0.25)"},borders:{none:"none",sm:"1px solid",md:"2px solid",lg:"4px solid"},radius:{none:"0px",sm:"0.125rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem",full:"9999px"}};var i={overview:"Persona uses a three-layer design token system: palette \u2192 semantic \u2192 components. Most themes only need palette.colors overrides \u2014 semantic and component layers auto-derive from palette values. Config also accepts non-theme appearance options (launcher, sendButton, toolCall, etc.).",layers:{palette:{description:"Primitive design tokens. Override specific shades to change the entire widget feel.",colors:{description:"7 color scales, each with shades 50 (lightest) to 950 (darkest). Override only the shades you need.",scales:{gray:"Neutrals \u2014 backgrounds, text, borders. Key shades: 50 (lightest bg), 100 (secondary bg), 200 (borders), 500 (muted text), 900 (primary text).",primary:"Brand color \u2014 buttons, links, interactive elements. Key shades: 500 (default), 600 (hover).",accent:"Secondary highlight. Key shades: 500 (default), 600 (hover).",secondary:"Tertiary color scale.",success:"Positive feedback (default: green).",warning:"Caution feedback (default: yellow).",error:"Error/danger feedback (default: red)."}},radius:{description:"Border radius scale. Add custom keys like launcher, button.",defaults:{none:"0px",sm:"0.125rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem",full:"9999px"}},typography:{fontFamily:"Three stacks: sans (system-ui), serif (Georgia), mono (ui-monospace). Override individual stack values.",fontSize:"Scale: xs (0.75rem), sm (0.875rem), base (1rem), lg (1.125rem), xl (1.25rem), 2xl (1.5rem), 3xl (1.875rem), 4xl (2.25rem).",fontWeight:"normal (400), medium (500), semibold (600), bold (700).",lineHeight:"tight (1.25), normal (1.5), relaxed (1.625)."},shadows:"Scale: none, sm, md, lg, xl, 2xl. Values are CSS box-shadow strings.",borders:"Scale: none, sm (1px solid), md (2px solid), lg (4px solid).",spacing:"Scale: 0 (0px), 1 (0.25rem), 2 (0.5rem), 3 (0.75rem), 4 (1rem), 5 (1.25rem), 6 (1.5rem), 8 (2rem), 10 (2.5rem), 12 (3rem), 16-64."},semantic:{description:'Design intent tokens. Auto-derived from palette by default. Override to redirect token resolution. Values are token reference strings like "palette.colors.primary.500".',colors:{primary:"palette.colors.primary.500 \u2014 Primary brand color.",secondary:"palette.colors.gray.500 \u2014 Secondary color.",accent:"palette.colors.primary.600 \u2014 Accent/interactive color.",surface:"palette.colors.gray.50 \u2014 Panel/card backgrounds.",background:"palette.colors.gray.50 \u2014 Page background.",container:"palette.colors.gray.100 \u2014 Container backgrounds.",text:"palette.colors.gray.900 \u2014 Primary text.",textMuted:"palette.colors.gray.500 \u2014 Muted/secondary text.",textInverse:"palette.colors.gray.50 \u2014 Text on dark backgrounds.",border:"palette.colors.gray.200 \u2014 Default border color.",divider:"palette.colors.gray.200 \u2014 Divider lines.",interactive:{default:"palette.colors.primary.500",hover:"palette.colors.primary.600",focus:"palette.colors.primary.700",active:"palette.colors.primary.800",disabled:"palette.colors.gray.300"},feedback:{success:"palette.colors.success.500",warning:"palette.colors.warning.500",error:"palette.colors.error.500",info:"palette.colors.primary.500"}},spacing:"xs (0.25rem), sm (0.5rem), md (1rem), lg (1.5rem), xl (2rem), 2xl (2.5rem).",typography:"fontFamily, fontSize, fontWeight, lineHeight \u2014 reference palette typography tokens."},components:{description:"UI element tokens. Rarely needed for basic theming. Override for fine-grained control. All values are token references or raw CSS strings.",button:{description:"Three variants: primary, secondary, ghost.",properties:"background, foreground, borderRadius, padding."},input:{description:"Message input field.",properties:"background, placeholder, borderRadius, padding, focus.border, focus.ring."},launcher:{description:"Floating launcher button.",properties:"size (60px), iconSize (28px), borderRadius, shadow."},panel:{description:"Chat panel container.",properties:"width, maxWidth (440px), height (600px), maxHeight, borderRadius, shadow."},header:{description:"Chat panel header.",properties:"background, border, borderRadius, padding, iconBackground, iconForeground, titleForeground, subtitleForeground, actionIconForeground, shadow, borderBottom."},message:{description:"Chat message bubbles.",user:"background, text, borderRadius, shadow.",assistant:"background, text, borderRadius, border (optional), shadow (optional)."},markdown:{description:"Markdown rendering in messages and artifact pane.",properties:"inlineCode (background, foreground), link.foreground, prose.fontFamily, heading.h1/h2 (fontSize, fontWeight)."},voice:"recording (indicator, background, border), processing (icon, background), speaking (icon).",approval:"requested (background, border, text), approve (background, foreground), deny (background, foreground).",attachment:"image (background, border).",scrollToBottom:"Floating scroll-to-bottom affordance shared by transcript and event stream: background, foreground, border, size, borderRadius, shadow, padding, gap, fontSize, iconSize.",toolBubble:"shadow \u2014 tool call row box-shadow.",reasoningBubble:"shadow \u2014 reasoning/thinking row box-shadow.",composer:"shadow \u2014 message input form box-shadow.",artifact:"toolbar (icon styling, copy menu), tab (background, active states), pane (background, toolbarBackground)."}},colorScheme:'"dark" merges darkTheme overrides on top of theme. "auto" detects system preference or <html class="dark">. "light" is default. colorScheme does NOT auto-invert colors \u2014 provide dark palette and semantic overrides yourself.',plugins:{description:"Plugins transform theme tokens before resolution. Use with createTheme().",available:{brandPlugin:'Auto-generates full color scales from a single brand hex: brandPlugin({ colors: { primary: "#7c3aed" } }).',accessibilityPlugin:"Enhanced focus indicators and disabled states.",highContrastPlugin:"Increased contrast for visual accessibility.",reducedMotionPlugin:"Disables all animations (sets transitions to 0ms).",animationsPlugin:"Adds transition and easing tokens."},usage:'createTheme(themeOverrides, { plugins: [brandPlugin({ colors: { primary: "#7c3aed" } })] })'},widgetConfig:{description:'Non-theme config options on the widget config object that affect appearance. These are siblings of "theme" in the config, not nested inside it.',launcher:{description:"Floating launcher button and panel positioning.",properties:{enabled:"Show/hide the launcher button.",title:"Header title text.",subtitle:"Header subtitle text.",position:'"bottom-right" | "bottom-left" | "top-right" | "top-left".',width:"Chat panel width (CSS value).",fullHeight:"Fill full height of container.",mountMode:'"floating" | "docked".',agentIconText:"Emoji/text for agent icon.",border:"Border style for launcher button.",shadow:"Box shadow for launcher button.",collapsedMaxWidth:"Max-width for launcher pill when panel closed."}},sendButton:{description:"Send button appearance.",properties:"backgroundColor, textColor, borderWidth, borderColor, paddingX, paddingY, iconText, iconName, size."},closeButton:{description:"Close button (on launcher config).",properties:"closeButtonSize, closeButtonColor, closeButtonBackgroundColor, closeButtonBorderWidth, closeButtonBorderColor, closeButtonBorderRadius."},clearChat:{description:"Clear chat button (on launcher.clearChat config).",properties:"enabled, iconColor, backgroundColor, borderWidth, borderColor, borderRadius, size."},scrollToBottom:{description:"Shared transcript + event-stream jump-to-latest affordance.",properties:'features.scrollToBottom.enabled, features.scrollToBottom.iconName, features.scrollToBottom.label (empty string renders icon-only). Defaults: enabled=true, iconName="arrow-down", label="".'},toolCall:{description:"Tool call display styling, text templates, loading animations, and rendering hooks. Text templates support placeholders ({toolName}, {duration}) and inline formatting (~dim~, *italic*, **bold**). renderCollapsedSummary receives elapsed (static string) and createElapsedElement() (live-updating span) in its context.",properties:"shadow, backgroundColor, borderColor, borderWidth, borderRadius, headerBackgroundColor, headerTextColor, headerPaddingX, headerPaddingY, contentBackgroundColor, contentTextColor, contentPaddingX, contentPaddingY, codeBlockBackgroundColor, codeBlockBorderColor, codeBlockTextColor, toggleTextColor, labelTextColor, activeTextTemplate, completeTextTemplate, loadingAnimationColor, loadingAnimationSecondaryColor, loadingAnimationDuration, renderCollapsedSummary, renderCollapsedPreview, renderGroupedSummary."},reasoning:{description:"Reasoning/thinking row rendering hooks, text templates, and loading animations. Text templates support {duration} placeholder and inline formatting (~dim~, *italic*, **bold**). renderCollapsedSummary receives elapsed (static string) and createElapsedElement() (live-updating span) in its context.",properties:"renderCollapsedSummary, renderCollapsedPreview, activeTextTemplate, completeTextTemplate, loadingAnimationColor, loadingAnimationSecondaryColor, loadingAnimationDuration."},approval:{description:"Tool approval bubble styling and behavior. Set to false to disable.",properties:"backgroundColor, borderColor, titleColor, descriptionColor, approveButtonColor, approveButtonTextColor, denyButtonColor, denyButtonTextColor, parameterBackgroundColor, parameterTextColor, title, approveLabel, denyLabel."},copy:{description:"Widget text content.",properties:"showWelcomeCard (boolean), welcomeTitle, welcomeSubtitle, inputPlaceholder, sendButtonLabel."},voiceRecognition:{description:"Voice input configuration.",properties:"enabled, pauseDuration, iconColor, backgroundColor."},textToSpeech:{description:"Text-to-speech for assistant messages.",properties:'enabled, provider ("browser" | "runtype"), browserFallback, voice, rate, pitch.'},suggestionChips:"string[] \u2014 Suggested prompts shown to the user.",messageActions:{description:"Message action buttons (copy, upvote, downvote).",properties:'enabled, showCopy, showUpvote, showDownvote, visibility ("hover" | "always"), align ("left" | "center" | "right"), layout ("pill-inside" | "row-inside").'},attachments:{description:"File attachment configuration.",properties:"enabled, allowedTypes (string[]), maxFileSize (bytes), maxFiles, buttonIconName, buttonTooltipText."},markdown:{description:"Markdown rendering configuration.",properties:"options (gfm, breaks, headerIds, headerPrefix, pedantic, mangle, silent), disableDefaultStyles."},layout:{description:"Layout configuration.",showHeader:"boolean \u2014 show/hide the header section entirely.",showFooter:"boolean \u2014 show/hide the footer/composer section entirely.",contentMaxWidth:'CSS width value for centering content (e.g. "720px", "90ch").',header:'"default" | "minimal". Options: showIcon, showTitle, showSubtitle, showCloseButton, showClearChat.',messages:'"bubble" | "flat" | "minimal". Options: groupConsecutive, avatar (show, position, userAvatar, assistantAvatar), timestamp (show, position).'},statusIndicator:{description:"Status text shown below the composer.",properties:{visible:"Show/hide the status indicator.",align:'"left" | "center" | "right" \u2014 text alignment (default: "right").',idleText:'Text shown when idle (default: "Online").',idleLink:"URL to open when idle text is clicked (wraps text in a link).",connectingText:'Text shown while connecting (default: "Connecting\u2026").',connectedText:'Text shown while streaming (default: "Streaming\u2026").',errorText:'Text shown on error (default: "Offline").'}},features:{description:"Feature flags.",properties:"showReasoning (AI thinking steps), showToolCalls (tool invocations), toolCallDisplay (collapsedMode, activePreview, activeMinHeight, previewMaxLines, grouped, expandable, loadingAnimation), reasoningDisplay (activePreview, activeMinHeight, previewMaxLines, expandable, loadingAnimation), artifacts (sidebar config)."}}},p={darkIndigo:{description:"Dark mode with indigo accent \u2014 override grays for dark backgrounds and semantic tokens for inverted text/surface",theme:{palette:{colors:{primary:{500:"#6366f1",600:"#4f46e5"},gray:{50:"#f1f5f9",100:"#1e293b",200:"#334155",500:"#94a3b8",900:"#0f172a",950:"#020617"}}},semantic:{colors:{surface:"palette.colors.gray.900",background:"palette.colors.gray.900",container:"palette.colors.gray.100",text:"palette.colors.gray.50",textMuted:"palette.colors.gray.500",textInverse:"palette.colors.gray.900",border:"palette.colors.gray.200"}}}},warmVintage:{description:"Warm sepia tones with serif font and subtle radius",theme:{palette:{colors:{primary:{500:"#b45309",600:"#92400e"},gray:{50:"#fef3c7",100:"#fef9c3",200:"#d6d3d1",500:"#78716c",900:"#44403c"}},radius:{sm:"0.125rem",md:"0.25rem",lg:"0.375rem"},typography:{fontFamily:{sans:'Georgia, Cambria, "Times New Roman", Times, serif'}}}}},neonCyberpunk:{description:"Neon on dark with monospace font \u2014 full semantic override for dark background",theme:{palette:{colors:{primary:{500:"#f0abfc",600:"#e879f9"},accent:{500:"#22d3ee",600:"#06b6d4"},gray:{50:"#f0abfc",100:"#1e0a3c",200:"#3b0764",500:"#c084fc",900:"#0c0a1a",950:"#050412"}},radius:{sm:"0",md:"0.25rem",lg:"0.375rem"},typography:{fontFamily:{sans:"ui-monospace, SFMono-Regular, Menlo, monospace"}}},semantic:{colors:{surface:"palette.colors.gray.900",background:"palette.colors.gray.950",container:"palette.colors.gray.100",text:"palette.colors.gray.50",textMuted:"palette.colors.gray.500",border:"palette.colors.gray.200"}}}},cleanRounded:{description:"Clean light theme with large radius and panel styling",theme:{palette:{radius:{sm:"6px",md:"8px",lg:"12px",launcher:"50px",button:"8px"}},components:{panel:{borderRadius:"16px",shadow:"palette.shadows.2xl"}}}}};function b(){return{tokenDocs:i,defaultColorPalette:n.colors,defaultRadius:n.radius,examples:p,sdkPresets:["shop","minimal","fullscreen"]}}0&&(module.exports={THEME_EXAMPLES,THEME_TOKEN_DOCS,getThemeReference});