vanilla-agent 1.10.0 → 1.11.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.
package/src/defaults.ts CHANGED
@@ -66,8 +66,9 @@ export const DEFAULT_WIDGET_CONFIG: Partial<AgentWidgetConfig> = {
66
66
  backgroundColor: "transparent",
67
67
  borderColor: "transparent",
68
68
  enabled: true,
69
+ placement: "inline",
69
70
  iconName: "refresh-cw",
70
- size: "29px",
71
+ size: "32px",
71
72
  showTooltip: true,
72
73
  tooltipText: "Clear chat",
73
74
  paddingX: "0px",
@@ -134,6 +135,29 @@ export const DEFAULT_WIDGET_CONFIG: Partial<AgentWidgetConfig> = {
134
135
  paddingX: "12px",
135
136
  paddingY: "6px",
136
137
  },
138
+ layout: {
139
+ header: {
140
+ layout: "default",
141
+ showIcon: true,
142
+ showTitle: true,
143
+ showSubtitle: true,
144
+ showCloseButton: true,
145
+ showClearChat: true,
146
+ },
147
+ messages: {
148
+ layout: "bubble",
149
+ avatar: {
150
+ show: false,
151
+ position: "left",
152
+ },
153
+ timestamp: {
154
+ show: false,
155
+ position: "below",
156
+ },
157
+ groupConsecutive: false,
158
+ },
159
+ slots: {},
160
+ },
137
161
  debug: false,
138
162
  };
139
163
 
@@ -186,5 +210,29 @@ export function mergeWithDefaults(
186
210
  ...DEFAULT_WIDGET_CONFIG.suggestionChipsConfig,
187
211
  ...config.suggestionChipsConfig,
188
212
  },
213
+ layout: {
214
+ ...DEFAULT_WIDGET_CONFIG.layout,
215
+ ...config.layout,
216
+ header: {
217
+ ...DEFAULT_WIDGET_CONFIG.layout?.header,
218
+ ...config.layout?.header,
219
+ },
220
+ messages: {
221
+ ...DEFAULT_WIDGET_CONFIG.layout?.messages,
222
+ ...config.layout?.messages,
223
+ avatar: {
224
+ ...DEFAULT_WIDGET_CONFIG.layout?.messages?.avatar,
225
+ ...config.layout?.messages?.avatar,
226
+ },
227
+ timestamp: {
228
+ ...DEFAULT_WIDGET_CONFIG.layout?.messages?.timestamp,
229
+ ...config.layout?.messages?.timestamp,
230
+ },
231
+ },
232
+ slots: {
233
+ ...DEFAULT_WIDGET_CONFIG.layout?.slots,
234
+ ...config.layout?.slots,
235
+ },
236
+ },
189
237
  };
190
238
  }
package/src/index.ts CHANGED
@@ -17,7 +17,18 @@ export type {
17
17
  AgentWidgetCustomFetch,
18
18
  AgentWidgetSSEEventParser,
19
19
  AgentWidgetSSEEventResult,
20
- AgentWidgetHeadersFunction
20
+ AgentWidgetHeadersFunction,
21
+ // Layout types
22
+ AgentWidgetLayoutConfig,
23
+ AgentWidgetHeaderLayoutConfig,
24
+ AgentWidgetMessageLayoutConfig,
25
+ AgentWidgetAvatarConfig,
26
+ AgentWidgetTimestampConfig,
27
+ WidgetLayoutSlot,
28
+ SlotRenderer,
29
+ SlotRenderContext,
30
+ HeaderRenderContext,
31
+ MessageRenderContext
21
32
  } from "./types";
22
33
 
23
34
  export { initAgentWidgetFn as initAgentWidget };
@@ -72,4 +83,35 @@ export {
72
83
  // Default configuration exports
73
84
  export { DEFAULT_WIDGET_CONFIG, mergeWithDefaults } from "./defaults";
74
85
 
86
+ // Layout system exports
87
+ export {
88
+ buildHeader,
89
+ buildComposer,
90
+ attachHeaderToContainer
91
+ } from "./components/panel";
92
+ export type {
93
+ HeaderElements,
94
+ HeaderBuildContext,
95
+ ComposerElements,
96
+ ComposerBuildContext
97
+ } from "./components/panel";
98
+ export {
99
+ headerLayouts,
100
+ getHeaderLayout,
101
+ buildHeaderWithLayout,
102
+ buildDefaultHeader,
103
+ buildMinimalHeader,
104
+ buildExpandedHeader
105
+ } from "./components/header-layouts";
106
+ export type {
107
+ HeaderLayoutContext,
108
+ HeaderLayoutRenderer
109
+ } from "./components/header-layouts";
110
+ export {
111
+ createStandardBubble,
112
+ createBubbleWithLayout,
113
+ createTypingIndicator
114
+ } from "./components/message-bubble";
115
+ export type { MessageTransform } from "./components/message-bubble";
116
+
75
117
  export default initAgentWidgetFn;
@@ -92,6 +92,16 @@ export const initAgentWidget = (
92
92
  const target = ensureTarget(options.target);
93
93
  const host = document.createElement("div");
94
94
  host.className = "vanilla-agent-host";
95
+
96
+ // When launcher is disabled (inline embed mode), ensure the host fills its container
97
+ // This allows the widget to respect the parent container's height
98
+ const launcherEnabled = options.config?.launcher?.enabled ?? true;
99
+ if (!launcherEnabled) {
100
+ host.style.height = "100%";
101
+ host.style.display = "flex";
102
+ host.style.flexDirection = "column";
103
+ }
104
+
95
105
  target.appendChild(host);
96
106
 
97
107
  const useShadow = options.useShadowDom !== false;
@@ -103,12 +113,28 @@ export const initAgentWidget = (
103
113
  root = shadowRoot;
104
114
  mount = document.createElement("div");
105
115
  mount.id = "vanilla-agent-root";
116
+ // When launcher is disabled, ensure mount fills the host
117
+ if (!launcherEnabled) {
118
+ mount.style.height = "100%";
119
+ mount.style.display = "flex";
120
+ mount.style.flexDirection = "column";
121
+ mount.style.flex = "1";
122
+ mount.style.minHeight = "0";
123
+ }
106
124
  shadowRoot.appendChild(mount);
107
125
  mountStyles(shadowRoot);
108
126
  } else {
109
127
  root = host;
110
128
  mount = document.createElement("div");
111
129
  mount.id = "vanilla-agent-root";
130
+ // When launcher is disabled, ensure mount fills the host
131
+ if (!launcherEnabled) {
132
+ mount.style.height = "100%";
133
+ mount.style.display = "flex";
134
+ mount.style.flexDirection = "column";
135
+ mount.style.flex = "1";
136
+ mount.style.minHeight = "0";
137
+ }
112
138
  host.appendChild(mount);
113
139
  mountStyles(host);
114
140
  }
package/src/types.ts CHANGED
@@ -156,6 +156,24 @@ export type AgentWidgetTheme = {
156
156
  radiusLg?: string;
157
157
  launcherRadius?: string;
158
158
  buttonRadius?: string;
159
+ /**
160
+ * Border style for the chat panel container.
161
+ * @example "1px solid #e5e7eb" | "none"
162
+ * @default "1px solid var(--tvw-cw-border)"
163
+ */
164
+ panelBorder?: string;
165
+ /**
166
+ * Box shadow for the chat panel container.
167
+ * @example "0 25px 50px -12px rgba(0,0,0,0.25)" | "none"
168
+ * @default "0 25px 50px -12px rgba(0,0,0,0.25)"
169
+ */
170
+ panelShadow?: string;
171
+ /**
172
+ * Border radius for the chat panel container.
173
+ * @example "16px" | "0"
174
+ * @default "16px"
175
+ */
176
+ panelBorderRadius?: string;
159
177
  };
160
178
 
161
179
  export type AgentWidgetLauncherConfig = {
@@ -170,6 +188,35 @@ export type AgentWidgetLauncherConfig = {
170
188
  position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
171
189
  autoExpand?: boolean;
172
190
  width?: string;
191
+ /**
192
+ * When true, the widget panel will fill the full height of its container.
193
+ * Useful for sidebar layouts where the chat should take up the entire viewport height.
194
+ * The widget will use flex layout to ensure header stays at top, messages scroll in middle,
195
+ * and composer stays fixed at bottom.
196
+ *
197
+ * @default false
198
+ */
199
+ fullHeight?: boolean;
200
+ /**
201
+ * When true, the widget panel will be positioned as a sidebar flush with the viewport edges.
202
+ * The panel will have:
203
+ * - No border-radius (square corners)
204
+ * - No margins (flush with top, left/right, and bottom edges)
205
+ * - Full viewport height
206
+ * - Subtle shadow on the edge facing the content
207
+ * - No border between footer and messages
208
+ *
209
+ * Use with `position` to control which side ('bottom-left' for left sidebar, 'bottom-right' for right sidebar).
210
+ * Automatically enables fullHeight when true.
211
+ *
212
+ * @default false
213
+ */
214
+ sidebarMode?: boolean;
215
+ /**
216
+ * Width of the sidebar panel when sidebarMode is true.
217
+ * @default "420px"
218
+ */
219
+ sidebarWidth?: string;
173
220
  callToActionIconText?: string;
174
221
  callToActionIconName?: string;
175
222
  callToActionIconColor?: string;
@@ -214,6 +261,7 @@ export type AgentWidgetSendButtonConfig = {
214
261
 
215
262
  export type AgentWidgetClearChatConfig = {
216
263
  enabled?: boolean;
264
+ placement?: "inline" | "top-right";
217
265
  iconName?: string;
218
266
  iconColor?: string;
219
267
  backgroundColor?: string;
@@ -386,6 +434,174 @@ export type AgentWidgetCustomFetch = (
386
434
  */
387
435
  export type AgentWidgetHeadersFunction = () => Record<string, string> | Promise<Record<string, string>>;
388
436
 
437
+ // ============================================================================
438
+ // Layout Configuration Types
439
+ // ============================================================================
440
+
441
+ /**
442
+ * Context provided to header render functions
443
+ */
444
+ export type HeaderRenderContext = {
445
+ config: AgentWidgetConfig;
446
+ onClose?: () => void;
447
+ onClearChat?: () => void;
448
+ };
449
+
450
+ /**
451
+ * Context provided to message render functions
452
+ */
453
+ export type MessageRenderContext = {
454
+ message: AgentWidgetMessage;
455
+ config: AgentWidgetConfig;
456
+ streaming: boolean;
457
+ };
458
+
459
+ /**
460
+ * Context provided to slot render functions
461
+ */
462
+ export type SlotRenderContext = {
463
+ config: AgentWidgetConfig;
464
+ defaultContent: () => HTMLElement | null;
465
+ };
466
+
467
+ /**
468
+ * Header layout configuration
469
+ * Allows customization of the header section appearance and behavior
470
+ */
471
+ export type AgentWidgetHeaderLayoutConfig = {
472
+ /**
473
+ * Layout preset: "default" | "minimal" | "expanded"
474
+ * - default: Standard layout with icon, title, subtitle, and buttons
475
+ * - minimal: Simplified layout with just title and close button
476
+ * - expanded: Full branding area with additional content space
477
+ */
478
+ layout?: "default" | "minimal" | "expanded";
479
+ /** Show/hide the header icon */
480
+ showIcon?: boolean;
481
+ /** Show/hide the title */
482
+ showTitle?: boolean;
483
+ /** Show/hide the subtitle */
484
+ showSubtitle?: boolean;
485
+ /** Show/hide the close button */
486
+ showCloseButton?: boolean;
487
+ /** Show/hide the clear chat button */
488
+ showClearChat?: boolean;
489
+ /**
490
+ * Custom renderer for complete header override
491
+ * When provided, replaces the entire header with custom content
492
+ */
493
+ render?: (context: HeaderRenderContext) => HTMLElement;
494
+ };
495
+
496
+ /**
497
+ * Avatar configuration for message bubbles
498
+ */
499
+ export type AgentWidgetAvatarConfig = {
500
+ /** Whether to show avatars */
501
+ show?: boolean;
502
+ /** Position of avatar relative to message bubble */
503
+ position?: "left" | "right";
504
+ /** URL or emoji for user avatar */
505
+ userAvatar?: string;
506
+ /** URL or emoji for assistant avatar */
507
+ assistantAvatar?: string;
508
+ };
509
+
510
+ /**
511
+ * Timestamp configuration for message bubbles
512
+ */
513
+ export type AgentWidgetTimestampConfig = {
514
+ /** Whether to show timestamps */
515
+ show?: boolean;
516
+ /** Position of timestamp relative to message */
517
+ position?: "inline" | "below";
518
+ /** Custom formatter for timestamp display */
519
+ format?: (date: Date) => string;
520
+ };
521
+
522
+ /**
523
+ * Message layout configuration
524
+ * Allows customization of how chat messages are displayed
525
+ */
526
+ export type AgentWidgetMessageLayoutConfig = {
527
+ /**
528
+ * Layout preset: "bubble" | "flat" | "minimal"
529
+ * - bubble: Standard chat bubble appearance (default)
530
+ * - flat: Flat messages without bubble styling
531
+ * - minimal: Minimal styling with reduced padding/borders
532
+ */
533
+ layout?: "bubble" | "flat" | "minimal";
534
+ /** Avatar configuration */
535
+ avatar?: AgentWidgetAvatarConfig;
536
+ /** Timestamp configuration */
537
+ timestamp?: AgentWidgetTimestampConfig;
538
+ /** Group consecutive messages from the same role */
539
+ groupConsecutive?: boolean;
540
+ /**
541
+ * Custom renderer for user messages
542
+ * When provided, replaces the default user message rendering
543
+ */
544
+ renderUserMessage?: (context: MessageRenderContext) => HTMLElement;
545
+ /**
546
+ * Custom renderer for assistant messages
547
+ * When provided, replaces the default assistant message rendering
548
+ */
549
+ renderAssistantMessage?: (context: MessageRenderContext) => HTMLElement;
550
+ };
551
+
552
+ /**
553
+ * Available layout slots for content injection
554
+ */
555
+ export type WidgetLayoutSlot =
556
+ | "header-left"
557
+ | "header-center"
558
+ | "header-right"
559
+ | "body-top"
560
+ | "messages"
561
+ | "body-bottom"
562
+ | "footer-top"
563
+ | "composer"
564
+ | "footer-bottom";
565
+
566
+ /**
567
+ * Slot renderer function signature
568
+ * Returns HTMLElement to render in the slot, or null to use default content
569
+ */
570
+ export type SlotRenderer = (context: SlotRenderContext) => HTMLElement | null;
571
+
572
+ /**
573
+ * Main layout configuration
574
+ * Provides comprehensive control over widget layout and appearance
575
+ *
576
+ * @example
577
+ * ```typescript
578
+ * config: {
579
+ * layout: {
580
+ * header: { layout: "minimal" },
581
+ * messages: {
582
+ * avatar: { show: true, assistantAvatar: "/bot.png" },
583
+ * timestamp: { show: true, position: "below" }
584
+ * },
585
+ * slots: {
586
+ * "footer-top": () => {
587
+ * const el = document.createElement("div");
588
+ * el.textContent = "Powered by AI";
589
+ * return el;
590
+ * }
591
+ * }
592
+ * }
593
+ * }
594
+ * ```
595
+ */
596
+ export type AgentWidgetLayoutConfig = {
597
+ /** Header layout configuration */
598
+ header?: AgentWidgetHeaderLayoutConfig;
599
+ /** Message layout configuration */
600
+ messages?: AgentWidgetMessageLayoutConfig;
601
+ /** Slot renderers for custom content injection */
602
+ slots?: Partial<Record<WidgetLayoutSlot, SlotRenderer>>;
603
+ };
604
+
389
605
  export type AgentWidgetConfig = {
390
606
  apiUrl?: string;
391
607
  flowId?: string;
@@ -580,6 +796,21 @@ export type AgentWidgetConfig = {
580
796
  * ```
581
797
  */
582
798
  parseSSEEvent?: AgentWidgetSSEEventParser;
799
+ /**
800
+ * Layout configuration for customizing widget appearance and structure.
801
+ * Provides control over header, messages, and content slots.
802
+ *
803
+ * @example
804
+ * ```typescript
805
+ * config: {
806
+ * layout: {
807
+ * header: { layout: "minimal" },
808
+ * messages: { avatar: { show: true } }
809
+ * }
810
+ * }
811
+ * ```
812
+ */
813
+ layout?: AgentWidgetLayoutConfig;
583
814
  };
584
815
 
585
816
  export type AgentWidgetMessageRole = "user" | "assistant" | "system";