@runtypelabs/persona 3.1.1 → 3.2.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.
package/dist/widget.css CHANGED
@@ -349,6 +349,11 @@
349
349
  word-break: break-all;
350
350
  }
351
351
 
352
+ .persona-break-words {
353
+ overflow-wrap: break-word;
354
+ word-break: break-word;
355
+ }
356
+
352
357
  .persona-px-4 {
353
358
  padding-left: 1rem;
354
359
  padding-right: 1rem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runtypelabs/persona",
3
- "version": "3.1.1",
3
+ "version": "3.2.1",
4
4
  "description": "Themeable, pluggable streaming agent widget for websites, in plain JS with support for voice input and reasoning / tool output.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -70,7 +70,7 @@
70
70
  "access": "public"
71
71
  },
72
72
  "scripts": {
73
- "build": "rimraf dist && npm run build:styles && npm run build:client && npm run build:installer",
73
+ "build": "rimraf dist && pnpm run build:styles && pnpm run build:client && pnpm run build:installer",
74
74
  "build:styles": "node -e \"const fs=require('fs');fs.mkdirSync('dist',{recursive:true});fs.copyFileSync('src/styles/widget.css','dist/widget.css');\"",
75
75
  "build:client": "tsup src/index.ts --format esm,cjs,iife --global-name AgentWidget --minify --sourcemap --splitting false --dts --loader \".css=text\"",
76
76
  "build:installer": "tsup src/install.ts --format iife --global-name SiteAgentInstaller --out-dir dist --minify --sourcemap --no-splitting",
@@ -0,0 +1,58 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { describe, expect, it } from "vitest";
4
+ import { createLauncherButton } from "./launcher";
5
+ import { DEFAULT_WIDGET_CONFIG } from "../defaults";
6
+
7
+ describe("createLauncherButton", () => {
8
+ it("applies collapsedMaxWidth when set", () => {
9
+ const { element, update } = createLauncherButton(undefined, () => {});
10
+ update({
11
+ ...DEFAULT_WIDGET_CONFIG,
12
+ launcher: {
13
+ ...DEFAULT_WIDGET_CONFIG.launcher,
14
+ collapsedMaxWidth: "min(380px, calc(100vw - 48px))",
15
+ },
16
+ });
17
+ expect(element.style.maxWidth).toBe("min(380px, calc(100vw - 48px))");
18
+ element.remove();
19
+ });
20
+
21
+ it("sets title tooltip on launcher title and subtitle for truncated text", () => {
22
+ const { element, update } = createLauncherButton(undefined, () => {});
23
+ update({
24
+ ...DEFAULT_WIDGET_CONFIG,
25
+ launcher: {
26
+ ...DEFAULT_WIDGET_CONFIG.launcher,
27
+ title: "Hello",
28
+ subtitle: "Long subtitle for tooltip",
29
+ },
30
+ });
31
+ const titleEl = element.querySelector("[data-role='launcher-title']");
32
+ const subtitleEl = element.querySelector("[data-role='launcher-subtitle']");
33
+ expect(titleEl?.getAttribute("title")).toBe("Hello");
34
+ expect(subtitleEl?.getAttribute("title")).toBe("Long subtitle for tooltip");
35
+ element.remove();
36
+ });
37
+
38
+ it("clears maxWidth when collapsedMaxWidth is unset", () => {
39
+ const { element, update } = createLauncherButton(undefined, () => {});
40
+ update({
41
+ ...DEFAULT_WIDGET_CONFIG,
42
+ launcher: {
43
+ ...DEFAULT_WIDGET_CONFIG.launcher,
44
+ collapsedMaxWidth: "320px",
45
+ },
46
+ });
47
+ expect(element.style.maxWidth).toBe("320px");
48
+ update({
49
+ ...DEFAULT_WIDGET_CONFIG,
50
+ launcher: {
51
+ ...DEFAULT_WIDGET_CONFIG.launcher,
52
+ collapsedMaxWidth: undefined,
53
+ },
54
+ });
55
+ expect(element.style.maxWidth).toBe("");
56
+ element.remove();
57
+ });
58
+ });
@@ -19,9 +19,9 @@ export const createLauncherButton = (
19
19
  button.innerHTML = `
20
20
  <span class="persona-inline-flex persona-items-center persona-justify-center persona-rounded-full persona-bg-persona-primary persona-text-white" data-role="launcher-icon">💬</span>
21
21
  <img data-role="launcher-image" class="persona-rounded-full persona-object-cover" alt="" style="display:none" />
22
- <span class="persona-flex persona-flex-col persona-items-start persona-text-left">
23
- <span class="persona-text-sm persona-font-semibold persona-text-persona-primary" data-role="launcher-title"></span>
24
- <span class="persona-text-xs persona-text-persona-muted" data-role="launcher-subtitle"></span>
22
+ <span class="persona-flex persona-min-w-0 persona-flex-1 persona-flex-col persona-items-start persona-text-left">
23
+ <span class="persona-block persona-w-full persona-truncate persona-text-sm persona-font-semibold persona-text-persona-primary" data-role="launcher-title"></span>
24
+ <span class="persona-block persona-w-full persona-truncate persona-text-xs persona-text-persona-muted" data-role="launcher-subtitle"></span>
25
25
  </span>
26
26
  <span class="persona-ml-2 persona-grid persona-place-items-center persona-rounded-full persona-bg-persona-primary persona-text-persona-call-to-action" data-role="launcher-call-to-action-icon">↗</span>
27
27
  `;
@@ -33,12 +33,16 @@ export const createLauncherButton = (
33
33
 
34
34
  const titleEl = button.querySelector("[data-role='launcher-title']");
35
35
  if (titleEl) {
36
- titleEl.textContent = launcher.title ?? "Chat Assistant";
36
+ const t = launcher.title ?? "Chat Assistant";
37
+ titleEl.textContent = t;
38
+ titleEl.setAttribute("title", t);
37
39
  }
38
40
 
39
41
  const subtitleEl = button.querySelector("[data-role='launcher-subtitle']");
40
42
  if (subtitleEl) {
41
- subtitleEl.textContent = launcher.subtitle ?? "Get answers fast";
43
+ const s = launcher.subtitle ?? "Get answers fast";
44
+ subtitleEl.textContent = s;
45
+ subtitleEl.setAttribute("title", s);
42
46
  }
43
47
 
44
48
  // Hide/show text container
@@ -186,7 +190,7 @@ export const createLauncherButton = (
186
190
  } else {
187
191
  button.style.width = "";
188
192
  button.style.minWidth = "";
189
- button.style.maxWidth = "";
193
+ button.style.maxWidth = launcher.collapsedMaxWidth ?? "";
190
194
  button.style.justifyContent = "";
191
195
  button.style.padding = "";
192
196
  button.style.overflow = "";
@@ -349,6 +349,11 @@
349
349
  word-break: break-all;
350
350
  }
351
351
 
352
+ .persona-break-words {
353
+ overflow-wrap: break-word;
354
+ word-break: break-word;
355
+ }
356
+
352
357
  .persona-px-4 {
353
358
  padding-left: 1rem;
354
359
  padding-right: 1rem;
package/src/types.ts CHANGED
@@ -827,6 +827,13 @@ export type AgentWidgetLauncherConfig = {
827
827
  * @default "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)"
828
828
  */
829
829
  shadow?: string;
830
+ /**
831
+ * CSS `max-width` for the floating launcher button when the panel is closed.
832
+ * Title and subtitle each truncate with an ellipsis when space is tight; full strings are available via the native `title` tooltip. Does not affect the open chat panel (`width` / `launcherWidth`).
833
+ *
834
+ * @example "min(380px, calc(100vw - 48px))"
835
+ */
836
+ collapsedMaxWidth?: string;
830
837
  };
831
838
 
832
839
  export type AgentWidgetSendButtonConfig = {