@runtypelabs/persona 2.3.0 → 3.0.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.
Files changed (41) hide show
  1. package/README.md +221 -4
  2. package/dist/index.cjs +42 -42
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +832 -571
  5. package/dist/index.d.ts +832 -571
  6. package/dist/index.global.js +87 -87
  7. package/dist/index.global.js.map +1 -1
  8. package/dist/index.js +42 -42
  9. package/dist/index.js.map +1 -1
  10. package/dist/widget.css +205 -15
  11. package/package.json +2 -2
  12. package/src/components/artifact-card.ts +39 -5
  13. package/src/components/artifact-pane.ts +67 -126
  14. package/src/components/composer-builder.ts +3 -23
  15. package/src/components/header-builder.ts +29 -34
  16. package/src/components/header-layouts.ts +109 -41
  17. package/src/components/launcher.ts +10 -7
  18. package/src/components/message-bubble.ts +7 -11
  19. package/src/components/panel.ts +4 -4
  20. package/src/defaults.ts +22 -93
  21. package/src/index.ts +20 -7
  22. package/src/presets.ts +66 -51
  23. package/src/runtime/host-layout.test.ts +196 -0
  24. package/src/runtime/host-layout.ts +265 -27
  25. package/src/runtime/init.test.ts +77 -7
  26. package/src/styles/widget.css +205 -15
  27. package/src/types/theme.ts +76 -0
  28. package/src/types.ts +86 -97
  29. package/src/ui.docked.test.ts +203 -7
  30. package/src/ui.ts +129 -88
  31. package/src/utils/buttons.ts +417 -0
  32. package/src/utils/code-generators.test.ts +43 -7
  33. package/src/utils/code-generators.ts +9 -25
  34. package/src/utils/deep-merge.ts +26 -0
  35. package/src/utils/dock.ts +18 -5
  36. package/src/utils/dropdown.ts +178 -0
  37. package/src/utils/sanitize.ts +1 -1
  38. package/src/utils/theme.test.ts +90 -15
  39. package/src/utils/theme.ts +20 -46
  40. package/src/utils/tokens.ts +108 -11
  41. package/src/utils/migration.ts +0 -220
@@ -2067,7 +2067,7 @@
2067
2067
  padding: var(--persona-artifact-toolbar-icon-padding, 0.25rem);
2068
2068
  border-radius: var(--persona-artifact-toolbar-icon-radius, var(--persona-radius-md, 0.375rem));
2069
2069
  border: var(--persona-artifact-toolbar-icon-border, 1px solid var(--persona-border, #e5e7eb));
2070
- background: var(--persona-surface, #ffffff);
2070
+ background: var(--persona-artifact-toolbar-icon-bg, var(--persona-surface, #ffffff));
2071
2071
  color: var(--persona-artifact-doc-toolbar-icon-color, var(--persona-text, #111827));
2072
2072
  cursor: pointer;
2073
2073
  line-height: 1;
@@ -2105,18 +2105,6 @@
2105
2105
  font-weight: 500;
2106
2106
  }
2107
2107
 
2108
- /* Copy menu dropdown theming */
2109
- #persona-root .persona-artifact-doc-copy-menu {
2110
- background: var(--persona-artifact-toolbar-copy-menu-bg, var(--persona-surface, #fff));
2111
- border: var(--persona-artifact-toolbar-copy-menu-border, 1px solid var(--persona-border, #e5e7eb));
2112
- box-shadow: var(--persona-artifact-toolbar-copy-menu-shadow, 0 4px 6px -1px rgba(0,0,0,.1));
2113
- border-radius: var(--persona-artifact-toolbar-copy-menu-radius, 0.375rem);
2114
- }
2115
-
2116
- #persona-root .persona-artifact-doc-copy-menu button:hover {
2117
- background: var(--persona-artifact-toolbar-copy-menu-item-hover-bg, var(--persona-container, #f3f4f6));
2118
- }
2119
-
2120
2108
  /* Artifact tab theming */
2121
2109
  #persona-root .persona-artifact-tab {
2122
2110
  background: var(--persona-artifact-tab-bg, transparent);
@@ -2134,6 +2122,200 @@
2134
2122
  background: var(--persona-artifact-toolbar-bg, var(--persona-surface, #fff));
2135
2123
  }
2136
2124
 
2125
+ /* Toggle group gap */
2126
+ #persona-root .persona-artifact-toggle-group {
2127
+ gap: var(--persona-artifact-toolbar-toggle-group-gap, 0.25rem);
2128
+ }
2129
+
2130
+ /* Toggle button border-radius (view/code buttons) */
2131
+ #persona-root .persona-artifact-toolbar-document .persona-artifact-view-btn,
2132
+ #persona-root .persona-artifact-toolbar-document .persona-artifact-code-btn {
2133
+ border-radius: var(--persona-artifact-toolbar-toggle-radius, var(--persona-artifact-toolbar-icon-radius, var(--persona-radius-md, 0.375rem)));
2134
+ }
2135
+
2136
+ /* Tab hover */
2137
+ #persona-root .persona-artifact-tab:hover {
2138
+ background: var(--persona-artifact-tab-hover-bg, var(--persona-container, #f3f4f6));
2139
+ }
2140
+
2141
+ /* Tab list container */
2142
+ #persona-root .persona-artifact-list {
2143
+ background: var(--persona-artifact-tab-list-bg, transparent);
2144
+ border-bottom-color: var(--persona-artifact-tab-list-border-color, var(--persona-border, #e5e7eb));
2145
+ padding: var(--persona-artifact-tab-list-padding, 0.5rem);
2146
+ }
2147
+
2148
+ /* Toolbar border override */
2149
+ #persona-root .persona-artifact-toolbar-document {
2150
+ border-bottom: var(--persona-artifact-toolbar-border, 1px solid var(--persona-border, #e5e7eb));
2151
+ }
2152
+
2153
+ /* ── Composable button utilities ── */
2154
+
2155
+ /* Icon button — base for all icon-only buttons created by createIconButton() */
2156
+ #persona-root .persona-icon-btn {
2157
+ display: inline-flex;
2158
+ align-items: center;
2159
+ justify-content: center;
2160
+ padding: var(--persona-icon-btn-padding, 0.25rem);
2161
+ border-radius: var(--persona-icon-btn-radius, var(--persona-radius-md, 0.375rem));
2162
+ border: var(--persona-icon-btn-border, 1px solid var(--persona-border, #e5e7eb));
2163
+ background: var(--persona-icon-btn-bg, var(--persona-surface, #ffffff));
2164
+ color: var(--persona-icon-btn-color, var(--persona-text, #111827));
2165
+ cursor: pointer;
2166
+ line-height: 1;
2167
+ transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
2168
+ }
2169
+
2170
+ #persona-root .persona-icon-btn:hover {
2171
+ background: var(--persona-icon-btn-hover-bg, var(--persona-container, #f3f4f6));
2172
+ color: var(--persona-icon-btn-hover-color, inherit);
2173
+ }
2174
+
2175
+ #persona-root .persona-icon-btn:focus-visible {
2176
+ outline: 2px solid var(--persona-accent, #3b82f6);
2177
+ outline-offset: 2px;
2178
+ }
2179
+
2180
+ #persona-root .persona-icon-btn[aria-pressed="true"] {
2181
+ background: var(--persona-icon-btn-active-bg, var(--persona-container, #f3f4f6));
2182
+ border-color: var(--persona-icon-btn-active-border, var(--persona-border, #e5e7eb));
2183
+ }
2184
+
2185
+ /* Label button — icon + text button created by createLabelButton() */
2186
+ #persona-root .persona-label-btn {
2187
+ display: inline-flex;
2188
+ align-items: center;
2189
+ gap: var(--persona-label-btn-gap, 0.35rem);
2190
+ padding: var(--persona-label-btn-padding, 0.25rem 0.5rem);
2191
+ border-radius: var(--persona-label-btn-radius, var(--persona-radius-md, 0.375rem));
2192
+ border: var(--persona-label-btn-border, 1px solid var(--persona-border, #e5e7eb));
2193
+ background: var(--persona-label-btn-bg, var(--persona-surface, #ffffff));
2194
+ color: var(--persona-label-btn-color, var(--persona-text, #111827));
2195
+ cursor: pointer;
2196
+ font-size: var(--persona-label-btn-font-size, 0.75rem);
2197
+ font-weight: 500;
2198
+ line-height: 1.25;
2199
+ white-space: nowrap;
2200
+ transition: background-color 0.15s ease, color 0.15s ease;
2201
+ }
2202
+
2203
+ #persona-root .persona-label-btn:hover {
2204
+ background: var(--persona-label-btn-hover-bg, var(--persona-container, #f3f4f6));
2205
+ }
2206
+
2207
+ #persona-root .persona-label-btn:focus-visible {
2208
+ outline: 2px solid var(--persona-accent, #3b82f6);
2209
+ outline-offset: 2px;
2210
+ }
2211
+
2212
+ #persona-root .persona-label-btn--sm {
2213
+ padding: var(--persona-label-btn-padding, 0.25rem 0.5rem);
2214
+ font-size: var(--persona-label-btn-font-size, 0.75rem);
2215
+ }
2216
+
2217
+ #persona-root .persona-label-btn--md {
2218
+ padding: 0.375rem 0.75rem;
2219
+ font-size: 0.8125rem;
2220
+ }
2221
+
2222
+ #persona-root .persona-label-btn--primary {
2223
+ background: var(--persona-primary, #3b82f6);
2224
+ color: var(--persona-text-inverse, #ffffff);
2225
+ border-color: transparent;
2226
+ }
2227
+
2228
+ #persona-root .persona-label-btn--primary:hover {
2229
+ opacity: 0.9;
2230
+ }
2231
+
2232
+ #persona-root .persona-label-btn--destructive {
2233
+ color: var(--persona-label-btn-destructive-color, #ef4444);
2234
+ }
2235
+
2236
+ #persona-root .persona-label-btn--ghost {
2237
+ border: none;
2238
+ background: transparent;
2239
+ }
2240
+
2241
+ #persona-root .persona-label-btn--ghost:hover {
2242
+ background: var(--persona-label-btn-hover-bg, var(--persona-container, #f3f4f6));
2243
+ }
2244
+
2245
+ /* Toggle group — mutually exclusive button set created by createToggleGroup() */
2246
+ #persona-root .persona-toggle-group {
2247
+ display: inline-flex;
2248
+ gap: var(--persona-toggle-group-gap, 0);
2249
+ }
2250
+
2251
+ #persona-root .persona-toggle-group > .persona-icon-btn {
2252
+ border-radius: 0;
2253
+ }
2254
+
2255
+ #persona-root .persona-toggle-group > .persona-icon-btn:first-child {
2256
+ border-top-left-radius: var(--persona-toggle-group-radius, var(--persona-icon-btn-radius, var(--persona-radius-md, 0.375rem)));
2257
+ border-bottom-left-radius: var(--persona-toggle-group-radius, var(--persona-icon-btn-radius, var(--persona-radius-md, 0.375rem)));
2258
+ }
2259
+
2260
+ #persona-root .persona-toggle-group > .persona-icon-btn:last-child {
2261
+ border-top-right-radius: var(--persona-toggle-group-radius, var(--persona-icon-btn-radius, var(--persona-radius-md, 0.375rem)));
2262
+ border-bottom-right-radius: var(--persona-toggle-group-radius, var(--persona-icon-btn-radius, var(--persona-radius-md, 0.375rem)));
2263
+ }
2264
+
2265
+ /* Combo button — label + chevron with dropdown */
2266
+ #persona-root .persona-combo-btn {
2267
+ font-size: var(--persona-combo-btn-font-size, 0.8125rem);
2268
+ font-weight: var(--persona-combo-btn-font-weight, 600);
2269
+ color: var(--persona-combo-btn-color, var(--persona-text, #111827));
2270
+ user-select: none;
2271
+ }
2272
+
2273
+ #persona-root .persona-combo-btn-label {
2274
+ white-space: nowrap;
2275
+ overflow: hidden;
2276
+ text-overflow: ellipsis;
2277
+ }
2278
+
2279
+ /* Dropdown menu utility */
2280
+ #persona-root .persona-dropdown-menu {
2281
+ z-index: 100;
2282
+ min-width: 160px;
2283
+ background: var(--persona-dropdown-bg, var(--persona-surface, #fff));
2284
+ border: var(--persona-dropdown-border, 1px solid var(--persona-border, #e5e7eb));
2285
+ border-radius: var(--persona-dropdown-radius, 0.625rem);
2286
+ padding: 0.25rem 0;
2287
+ box-shadow: var(--persona-dropdown-shadow, 0 4px 16px rgba(0,0,0,0.12));
2288
+ }
2289
+
2290
+ #persona-root .persona-dropdown-menu button {
2291
+ display: flex;
2292
+ align-items: center;
2293
+ gap: 0.625rem;
2294
+ width: 100%;
2295
+ padding: 0.5rem 0.875rem;
2296
+ border: none;
2297
+ background: transparent;
2298
+ color: var(--persona-dropdown-item-color, var(--persona-text, #1f2937));
2299
+ font-size: 0.8125rem;
2300
+ cursor: pointer;
2301
+ text-align: left;
2302
+ white-space: nowrap;
2303
+ }
2304
+
2305
+ #persona-root .persona-dropdown-menu button:hover {
2306
+ background: var(--persona-dropdown-item-hover-bg, var(--persona-container, #f3f4f6));
2307
+ }
2308
+
2309
+ #persona-root .persona-dropdown-menu button[data-destructive] {
2310
+ color: var(--persona-dropdown-destructive-color, #ef4444);
2311
+ }
2312
+
2313
+ #persona-root .persona-dropdown-menu hr {
2314
+ border: none;
2315
+ border-top: 1px solid var(--persona-dropdown-hr, var(--persona-border, #e5e7eb));
2316
+ margin: 0.25rem 0;
2317
+ }
2318
+
2137
2319
  /* Draggable split handle (desktop split only; hidden in drawer / narrow host / small viewport) */
2138
2320
  #persona-root .persona-artifact-split-handle {
2139
2321
  width: 6px;
@@ -2178,7 +2360,11 @@
2178
2360
  #persona-root .persona-artifact-pane {
2179
2361
  border-radius: var(--persona-artifact-pane-radius, 0);
2180
2362
  overflow: hidden;
2181
- background-color: var(--persona-artifact-pane-bg, var(--persona-surface, #ffffff));
2363
+ /* Layout paneBackground → theme components.artifact.pane.background → semantic surface */
2364
+ background-color: var(
2365
+ --persona-artifact-pane-bg,
2366
+ var(--persona-components-artifact-pane-background, var(--persona-surface, #ffffff))
2367
+ );
2182
2368
  }
2183
2369
 
2184
2370
  /* paneAppearance: 'seamless' — flush with chat, no border/shadow/gap */
@@ -2192,7 +2378,11 @@
2192
2378
  border-left-width: 0 !important;
2193
2379
  border-left-color: transparent !important;
2194
2380
  box-shadow: none !important;
2195
- background-color: var(--persona-artifact-pane-bg, var(--persona-container, #f8fafc));
2381
+ /* Same token chain; final fallback stays container for flush split chrome */
2382
+ background-color: var(
2383
+ --persona-artifact-pane-bg,
2384
+ var(--persona-components-artifact-pane-background, var(--persona-container, #f8fafc))
2385
+ );
2196
2386
  }
2197
2387
 
2198
2388
  /* layout.paneBorder / paneBorderLeft — theme overrides (after appearance defaults) */
@@ -199,6 +199,20 @@ export interface HeaderTokens extends ComponentTokenSet {
199
199
  background: TokenReference<'color'>;
200
200
  border: TokenReference<'color'>;
201
201
  borderRadius: TokenReference<'radius'>;
202
+ /** Background of the rounded avatar tile next to the title (Lucide / emoji / image). */
203
+ iconBackground: TokenReference<'color'>;
204
+ /** Foreground (glyph stroke or emoji text) on the header avatar tile. */
205
+ iconForeground: TokenReference<'color'>;
206
+ /** Header title line (next to the icon, or minimal layout title). */
207
+ titleForeground: TokenReference<'color'>;
208
+ /** Header subtitle line under the title. */
209
+ subtitleForeground: TokenReference<'color'>;
210
+ /** Default color for clear / close icon buttons when launcher overrides are unset. */
211
+ actionIconForeground: TokenReference<'color'>;
212
+ /** Box-shadow on the header (e.g., a fade shadow to replace the default border). */
213
+ shadow?: string;
214
+ /** Override the header bottom border (e.g., `none`). */
215
+ borderBottom?: string;
202
216
  }
203
217
 
204
218
  export interface MessageTokens {
@@ -317,6 +331,10 @@ export interface ArtifactToolbarTokens {
317
331
  copyMenuShadow?: string;
318
332
  copyMenuBorderRadius?: string;
319
333
  copyMenuItemHoverBackground?: string;
334
+ /** Base background of icon buttons (defaults to --persona-surface). */
335
+ iconBackground?: string;
336
+ /** Border on the toolbar (e.g., `none` to remove the bottom border). */
337
+ toolbarBorder?: string;
320
338
  }
321
339
 
322
340
  /** Artifact tab strip chrome. */
@@ -326,13 +344,62 @@ export interface ArtifactTabTokens {
326
344
  activeBorder?: string;
327
345
  borderRadius?: string;
328
346
  textColor?: string;
347
+ /** Hover background for inactive tabs. */
348
+ hoverBackground?: string;
349
+ /** Tab list container background. */
350
+ listBackground?: string;
351
+ /** Tab list container border color. */
352
+ listBorderColor?: string;
353
+ /** Tab list container padding (CSS shorthand). */
354
+ listPadding?: string;
329
355
  }
330
356
 
331
357
  /** Artifact pane chrome. */
332
358
  export interface ArtifactPaneTokens {
359
+ /**
360
+ * Background for the artifact column (toolbar + content), resolved from the theme.
361
+ * Defaults to `semantic.colors.container` so the pane matches assistant message surfaces.
362
+ * `features.artifacts.layout.paneBackground` still wins when set (layout escape hatch).
363
+ */
364
+ background?: string;
333
365
  toolbarBackground?: string;
334
366
  }
335
367
 
368
+ /** Icon button chrome (used by createIconButton). */
369
+ export interface IconButtonTokens {
370
+ background?: string;
371
+ border?: string;
372
+ color?: string;
373
+ padding?: string;
374
+ borderRadius?: string;
375
+ hoverBackground?: string;
376
+ hoverColor?: string;
377
+ /** Background when aria-pressed="true". */
378
+ activeBackground?: string;
379
+ /** Border color when aria-pressed="true". */
380
+ activeBorder?: string;
381
+ }
382
+
383
+ /** Label button chrome (used by createLabelButton). */
384
+ export interface LabelButtonTokens {
385
+ background?: string;
386
+ border?: string;
387
+ color?: string;
388
+ padding?: string;
389
+ borderRadius?: string;
390
+ hoverBackground?: string;
391
+ fontSize?: string;
392
+ gap?: string;
393
+ }
394
+
395
+ /** Toggle group chrome (used by createToggleGroup). */
396
+ export interface ToggleGroupTokens {
397
+ /** Gap between toggle buttons. Default: 0 (connected). */
398
+ gap?: string;
399
+ /** Border radius for first/last buttons. */
400
+ borderRadius?: string;
401
+ }
402
+
336
403
  export interface ComponentTokens {
337
404
  button: ButtonTokens;
338
405
  input: InputTokens;
@@ -348,6 +415,12 @@ export interface ComponentTokens {
348
415
  toolBubble: ToolBubbleTokens;
349
416
  reasoningBubble: ReasoningBubbleTokens;
350
417
  composer: ComposerChromeTokens;
418
+ /** Icon button styling tokens. */
419
+ iconButton?: IconButtonTokens;
420
+ /** Label button styling tokens. */
421
+ labelButton?: LabelButtonTokens;
422
+ /** Toggle group styling tokens. */
423
+ toggleGroup?: ToggleGroupTokens;
351
424
  /** Artifact toolbar, tab strip, and pane chrome. */
352
425
  artifact?: {
353
426
  toolbar?: ArtifactToolbarTokens;
@@ -384,6 +457,9 @@ export type PersonaTheme = PersonaThemeBase &
384
457
  PersonaThemeSemantic &
385
458
  PersonaThemeComponents;
386
459
 
460
+ /** Recursive partial for `config.theme` / `config.darkTheme` overrides. */
461
+ export type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]> } : T;
462
+
387
463
  export interface ResolvedToken {
388
464
  path: string;
389
465
  value: string;
package/src/types.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { AgentWidgetPlugin } from "./plugins/types";
2
+ import type { DeepPartial, PersonaTheme } from "./types/theme";
2
3
 
3
4
  // ============================================================================
4
5
  // Multi-Modal Content Types
@@ -469,7 +470,9 @@ export type AgentWidgetArtifactsLayoutConfig = {
469
470
  */
470
471
  unifiedSplitOuterRadius?: string;
471
472
  /**
472
- * Background color for the artifact column (CSS color). Sets `--persona-artifact-pane-bg` on the widget root.
473
+ * Strongest override: solid background for the artifact column (CSS color). Sets `--persona-artifact-pane-bg`
474
+ * on the widget root. Leave unset to use theme `components.artifact.pane.background` (defaults to semantic
475
+ * container) so light/dark stays consistent.
473
476
  */
474
477
  paneBackground?: string;
475
478
  /**
@@ -533,6 +536,20 @@ export type AgentWidgetArtifactsFeature = {
533
536
  type: 'open' | 'download';
534
537
  artifactId: string;
535
538
  }) => boolean | void;
539
+ /**
540
+ * Custom renderer for artifact reference cards shown in the message thread.
541
+ * Return an HTMLElement to replace the default card, or `null` to use the default.
542
+ */
543
+ renderCard?: (context: {
544
+ artifact: {
545
+ artifactId: string;
546
+ title: string;
547
+ artifactType: string;
548
+ status: string;
549
+ };
550
+ config: AgentWidgetConfig;
551
+ defaultRenderer: () => HTMLElement;
552
+ }) => HTMLElement | null;
536
553
  };
537
554
 
538
555
  export type AgentWidgetFeatureFlags = {
@@ -667,85 +684,6 @@ export type EventStreamPayloadRenderContext = {
667
684
  parsedPayload: unknown;
668
685
  };
669
686
 
670
- export type AgentWidgetTheme = {
671
- primary?: string;
672
- secondary?: string;
673
- surface?: string;
674
- muted?: string;
675
- accent?: string;
676
- container?: string;
677
- border?: string;
678
- divider?: string;
679
- messageBorder?: string;
680
- inputBackground?: string;
681
- callToAction?: string;
682
- callToActionBackground?: string;
683
- sendButtonBackgroundColor?: string;
684
- sendButtonTextColor?: string;
685
- sendButtonBorderColor?: string;
686
- closeButtonColor?: string;
687
- closeButtonBackgroundColor?: string;
688
- closeButtonBorderColor?: string;
689
- clearChatIconColor?: string;
690
- clearChatBackgroundColor?: string;
691
- clearChatBorderColor?: string;
692
- tooltipBackground?: string;
693
- tooltipForeground?: string;
694
- micIconColor?: string;
695
- micBackgroundColor?: string;
696
- micBorderColor?: string;
697
- recordingIconColor?: string;
698
- recordingBackgroundColor?: string;
699
- recordingBorderColor?: string;
700
- inputFontFamily?: "sans-serif" | "serif" | "mono";
701
- inputFontWeight?: string;
702
- radiusSm?: string;
703
- radiusMd?: string;
704
- radiusLg?: string;
705
- launcherRadius?: string;
706
- buttonRadius?: string;
707
- /**
708
- * Border style for the chat panel container.
709
- * @example "1px solid #e5e7eb" | "none"
710
- * @default "1px solid var(--persona-border)"
711
- */
712
- panelBorder?: string;
713
- /**
714
- * Box shadow for the chat panel container.
715
- * @example "0 25px 50px -12px rgba(0,0,0,0.25)" | "none"
716
- * @default "0 25px 50px -12px rgba(0,0,0,0.25)"
717
- */
718
- panelShadow?: string;
719
- /**
720
- * Border radius for the chat panel container.
721
- * @example "16px" | "0"
722
- * @default "16px"
723
- */
724
- panelBorderRadius?: string;
725
- /**
726
- * Box-shadow for user message bubbles (bubble message layout).
727
- * @example "none" | "0 1px 2px rgba(0,0,0,0.05)"
728
- */
729
- messageUserShadow?: string;
730
- /**
731
- * Box-shadow for assistant message bubbles (bubble message layout).
732
- * Overrides the default subtle assistant shadow when set.
733
- */
734
- messageAssistantShadow?: string;
735
- /**
736
- * Box-shadow for tool-call / function-call rows.
737
- */
738
- toolBubbleShadow?: string;
739
- /**
740
- * Box-shadow for reasoning (“thinking”) rows.
741
- */
742
- reasoningBubbleShadow?: string;
743
- /**
744
- * Box-shadow on the composer (input) container.
745
- */
746
- composerShadow?: string;
747
- };
748
-
749
687
  export type AgentWidgetDockConfig = {
750
688
  /**
751
689
  * Side of the wrapped container where the docked panel should render.
@@ -758,10 +696,22 @@ export type AgentWidgetDockConfig = {
758
696
  */
759
697
  width?: string;
760
698
  /**
761
- * Width of the collapsed launcher rail when the docked panel is closed.
762
- * @default "72px"
699
+ * When false, the dock column snaps between `0` and `width` with no CSS transition so main
700
+ * content does not reflow during the open/close animation.
701
+ * @default true
702
+ */
703
+ animate?: boolean;
704
+ /**
705
+ * How the dock panel is shown.
706
+ * - `"resize"` (default): a flex column grows/shrinks between `0` and `width` (main content reflows).
707
+ * - `"overlay"`: panel is absolutely positioned and translates in/out **over** full-width content.
708
+ * - `"push"`: a wide inner track `[content at shell width][panel]` translates horizontally so the panel
709
+ * appears to push the workspace aside **without** animating the content column width (Shopify-style).
710
+ * - `"emerge"`: like `"resize"`, the flex column animates so **page content reflows**; the chat
711
+ * panel keeps a **fixed** `dock.width` (not squeezed while the column grows), clipped by the slot so
712
+ * it appears to emerge at full width like a floating widget.
763
713
  */
764
- collapsedWidth?: string;
714
+ reveal?: "resize" | "overlay" | "push" | "emerge";
765
715
  };
766
716
 
767
717
  export type AgentWidgetLauncherConfig = {
@@ -1396,6 +1346,17 @@ export type AgentWidgetHeaderTrailingAction = {
1396
1346
  icon?: string;
1397
1347
  label?: string;
1398
1348
  ariaLabel?: string;
1349
+ /**
1350
+ * When set, clicking this action opens a dropdown menu.
1351
+ * Menu item selections fire `onAction(menuItemId)`.
1352
+ */
1353
+ menuItems?: Array<{
1354
+ id: string;
1355
+ label: string;
1356
+ icon?: string;
1357
+ destructive?: boolean;
1358
+ dividerBefore?: boolean;
1359
+ }>;
1399
1360
  };
1400
1361
 
1401
1362
  /**
@@ -1466,6 +1427,41 @@ export type AgentWidgetHeaderLayoutConfig = {
1466
1427
  * When set, the title row becomes visually interactive (cursor: pointer).
1467
1428
  */
1468
1429
  onTitleClick?: () => void;
1430
+ /** Style config for the title row hover effect (minimal layout). */
1431
+ titleRowHover?: {
1432
+ /** Hover background color. */
1433
+ background?: string;
1434
+ /** Hover border color. */
1435
+ border?: string;
1436
+ /** Border radius for the pill shape. */
1437
+ borderRadius?: string;
1438
+ /** Padding inside the pill. */
1439
+ padding?: string;
1440
+ };
1441
+ /**
1442
+ * Replaces the title with a combo button (label + chevron + dropdown menu).
1443
+ * When set, `trailingActions`, `onTitleClick`, and `titleRowHover` are ignored
1444
+ * since the combo button handles all of these internally.
1445
+ */
1446
+ titleMenu?: {
1447
+ /** Dropdown menu items. */
1448
+ menuItems: Array<{
1449
+ id: string;
1450
+ label: string;
1451
+ icon?: string;
1452
+ destructive?: boolean;
1453
+ dividerBefore?: boolean;
1454
+ }>;
1455
+ /** Called when a menu item is selected. */
1456
+ onSelect: (id: string) => void;
1457
+ /** Hover pill style. */
1458
+ hover?: {
1459
+ background?: string;
1460
+ border?: string;
1461
+ borderRadius?: string;
1462
+ padding?: string;
1463
+ };
1464
+ };
1469
1465
  };
1470
1466
 
1471
1467
  /**
@@ -2256,22 +2252,15 @@ export type AgentWidgetConfig = {
2256
2252
  */
2257
2253
  showWelcomeCard?: boolean;
2258
2254
  };
2259
- theme?: AgentWidgetTheme;
2260
2255
  /**
2261
- * Theme colors for dark mode. Applied when dark mode is detected
2262
- * (when colorScheme is 'dark' or 'auto' with dark mode active).
2263
- * If not provided, falls back to `theme` colors.
2264
- *
2265
- * @example
2266
- * ```typescript
2267
- * config: {
2268
- * theme: { primary: '#111827', surface: '#ffffff' },
2269
- * darkTheme: { primary: '#f9fafb', surface: '#1f2937' },
2270
- * colorScheme: 'auto'
2271
- * }
2272
- * ```
2256
+ * Semantic design tokens (`palette`, `semantic`, `components`).
2257
+ * Omit for library defaults.
2258
+ */
2259
+ theme?: DeepPartial<PersonaTheme>;
2260
+ /**
2261
+ * Dark-mode token overrides. Merged over `theme` when the active scheme is dark.
2273
2262
  */
2274
- darkTheme?: AgentWidgetTheme;
2263
+ darkTheme?: DeepPartial<PersonaTheme>;
2275
2264
  /**
2276
2265
  * Color scheme mode for the widget.
2277
2266
  * - 'light': Always use light theme (default)