vanilla-agent 1.14.0 → 1.16.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanilla-agent",
3
- "version": "1.14.0",
3
+ "version": "1.16.0",
4
4
  "description": "Themeable, plugable 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",
@@ -46,7 +46,7 @@ export const buildComposer = (context: ComposerBuildContext): ComposerElements =
46
46
 
47
47
  const footer = createElement(
48
48
  "div",
49
- "tvw-border-t-cw-divider tvw-bg-cw-surface tvw-px-6 tvw-py-4"
49
+ "tvw-widget-footer tvw-border-t-cw-divider tvw-bg-cw-surface tvw-px-6 tvw-py-4"
50
50
  );
51
51
 
52
52
  const suggestions = createElement(
@@ -67,7 +67,7 @@ export const buildComposer = (context: ComposerBuildContext): ComposerElements =
67
67
 
68
68
  const composerForm = createElement(
69
69
  "form",
70
- `tvw-flex tvw-items-end ${gapClass} tvw-rounded-2xl tvw-border tvw-border-gray-200 tvw-bg-cw-input-background tvw-px-4 tvw-py-3`
70
+ `tvw-widget-composer tvw-flex tvw-items-end ${gapClass} tvw-rounded-2xl tvw-border tvw-border-gray-200 tvw-bg-cw-input-background tvw-px-4 tvw-py-3`
71
71
  ) as HTMLFormElement;
72
72
  // Prevent form from getting focus styles
73
73
  composerForm.style.outline = "none";
@@ -364,3 +364,4 @@ export const buildComposer = (context: ComposerBuildContext): ComposerElements =
364
364
  };
365
365
  };
366
366
 
367
+
@@ -29,7 +29,7 @@ export const buildHeader = (context: HeaderBuildContext): HeaderElements => {
29
29
 
30
30
  const header = createElement(
31
31
  "div",
32
- "tvw-flex tvw-items-center tvw-gap-3 tvw-bg-cw-surface tvw-px-6 tvw-py-5 tvw-border-b-cw-divider"
32
+ "tvw-widget-header tvw-flex tvw-items-center tvw-gap-3 tvw-bg-cw-surface tvw-px-6 tvw-py-5 tvw-border-b-cw-divider"
33
33
  );
34
34
 
35
35
  const launcher = config?.launcher ?? {};
@@ -452,3 +452,4 @@ export const attachHeaderToContainer = (
452
452
  }
453
453
  };
454
454
 
455
+
@@ -36,12 +36,12 @@ export const createWrapper = (config?: AgentWidgetConfig): PanelWrapper => {
36
36
 
37
37
  const wrapper = createElement(
38
38
  "div",
39
- `tvw-fixed ${position} tvw-z-50 tvw-transition`
39
+ `tvw-widget-wrapper tvw-fixed ${position} tvw-z-50 tvw-transition`
40
40
  );
41
41
 
42
42
  const panel = createElement(
43
43
  "div",
44
- "tvw-relative tvw-min-h-[320px]"
44
+ "tvw-widget-panel tvw-relative tvw-min-h-[320px]"
45
45
  );
46
46
  const launcherWidth = config?.launcher?.width ?? config?.launcherWidth;
47
47
  const width = launcherWidth ?? "min(400px, calc(100vw - 24px))";
@@ -83,7 +83,7 @@ export const buildPanel = (config?: AgentWidgetConfig, showClose = true): PanelE
83
83
  // the body (chat messages area) to scroll while header/footer stay fixed
84
84
  const container = createElement(
85
85
  "div",
86
- "tvw-flex tvw-h-full tvw-w-full tvw-flex-1 tvw-min-h-0 tvw-flex-col tvw-bg-cw-surface tvw-text-cw-primary tvw-rounded-2xl tvw-overflow-hidden tvw-shadow-2xl tvw-border tvw-border-cw-border"
86
+ "tvw-widget-container tvw-flex tvw-h-full tvw-w-full tvw-flex-1 tvw-min-h-0 tvw-flex-col tvw-bg-cw-surface tvw-text-cw-primary tvw-rounded-2xl tvw-overflow-hidden tvw-border tvw-border-cw-border"
87
87
  );
88
88
 
89
89
  // Build header using layout config if available, otherwise use standard builder
@@ -95,7 +95,7 @@ export const buildPanel = (config?: AgentWidgetConfig, showClose = true): PanelE
95
95
  // Build body with intro card and messages wrapper
96
96
  const body = createElement(
97
97
  "div",
98
- "tvw-flex tvw-flex-1 tvw-min-h-0 tvw-flex-col tvw-gap-6 tvw-overflow-y-auto tvw-bg-cw-container tvw-px-6 tvw-py-6"
98
+ "tvw-widget-body tvw-flex tvw-flex-1 tvw-min-h-0 tvw-flex-col tvw-gap-6 tvw-overflow-y-auto tvw-bg-cw-container tvw-px-6 tvw-py-6"
99
99
  );
100
100
  body.id = "vanilla-agent-scroll-container";
101
101
 
package/src/ui.ts CHANGED
@@ -19,6 +19,7 @@ import { createElement } from "./utils/dom";
19
19
  import { statusCopy } from "./utils/constants";
20
20
  import { createLauncherButton } from "./components/launcher";
21
21
  import { createWrapper, buildPanel, buildHeader, buildComposer, attachHeaderToContainer } from "./components/panel";
22
+ import { positionMap } from "./utils/positioning";
22
23
  import type { HeaderElements, ComposerElements } from "./components/panel";
23
24
  import { MessageTransform } from "./components/message-bubble";
24
25
  import { createStandardBubble, createTypingIndicator } from "./components/message-bubble";
@@ -418,12 +419,36 @@ export const createAgentExperience = (
418
419
  const panelShadow = theme.panelShadow ?? defaultPanelShadow;
419
420
  const panelBorderRadius = theme.panelBorderRadius ?? defaultPanelBorderRadius;
420
421
 
421
- // Apply panel styling to container (works in all modes)
422
+ // Reset all inline styles first to handle mode toggling
423
+ // This ensures styles don't persist when switching between modes
424
+ mount.style.cssText = '';
425
+ wrapper.style.cssText = '';
426
+ panel.style.cssText = '';
427
+ container.style.cssText = '';
428
+ body.style.cssText = '';
429
+ footer.style.cssText = '';
430
+
431
+ // Re-apply panel width/maxWidth from initial setup
432
+ const launcherWidth = config?.launcher?.width ?? config?.launcherWidth;
433
+ const width = launcherWidth ?? "min(400px, calc(100vw - 24px))";
434
+ if (!sidebarMode) {
435
+ panel.style.width = width;
436
+ panel.style.maxWidth = width;
437
+ }
438
+
439
+ // Apply panel styling
440
+ // Box-shadow is applied to panel (parent) instead of container to avoid
441
+ // rendering artifacts when container has overflow:hidden + border-radius
442
+ // Panel also gets border-radius to make the shadow follow the rounded corners
443
+ panel.style.boxShadow = panelShadow;
444
+ panel.style.borderRadius = panelBorderRadius;
422
445
  container.style.border = panelBorder;
423
- container.style.boxShadow = panelShadow;
424
446
  container.style.borderRadius = panelBorderRadius;
425
447
 
426
448
  if (fullHeight) {
449
+ // Check if this is inline embed mode (launcher disabled) vs launcher mode
450
+ const isInlineEmbed = config.launcher?.enabled === false;
451
+
427
452
  // Mount container
428
453
  mount.style.display = 'flex';
429
454
  mount.style.flexDirection = 'column';
@@ -431,13 +456,17 @@ export const createAgentExperience = (
431
456
  mount.style.minHeight = '0';
432
457
 
433
458
  // Wrapper
459
+ // - Inline embed: needs overflow:hidden to contain the flex layout
460
+ // - Launcher mode: no overflow:hidden to allow panel's box-shadow to render fully
434
461
  wrapper.style.display = 'flex';
435
462
  wrapper.style.flexDirection = 'column';
436
463
  wrapper.style.flex = '1 1 0%';
437
464
  wrapper.style.minHeight = '0';
438
465
  wrapper.style.maxHeight = '100%';
439
466
  wrapper.style.height = '100%';
440
- wrapper.style.overflow = 'hidden';
467
+ if (isInlineEmbed) {
468
+ wrapper.style.overflow = 'hidden';
469
+ }
441
470
 
442
471
  // Panel
443
472
  panel.style.display = 'flex';
@@ -465,16 +494,23 @@ export const createAgentExperience = (
465
494
  footer.style.flexShrink = '0';
466
495
  }
467
496
 
497
+ // Handle positioning classes based on mode
498
+ // First remove all position classes to reset state
499
+ wrapper.classList.remove(
500
+ 'tvw-bottom-6', 'tvw-right-6', 'tvw-left-6', 'tvw-top-6',
501
+ 'tvw-bottom-4', 'tvw-right-4', 'tvw-left-4', 'tvw-top-4'
502
+ );
503
+
504
+ if (!sidebarMode) {
505
+ // Restore positioning classes when not in sidebar mode
506
+ const positionClasses = positionMap[position as keyof typeof positionMap] ?? positionMap['bottom-right'];
507
+ positionClasses.split(' ').forEach(cls => wrapper.classList.add(cls));
508
+ }
509
+
468
510
  // Apply sidebar-specific styles
469
511
  if (sidebarMode) {
470
512
  const sidebarWidth = config.launcher?.sidebarWidth ?? '420px';
471
513
 
472
- // Remove Tailwind positioning classes that add spacing (tvw-bottom-6, tvw-right-6, etc.)
473
- wrapper.classList.remove(
474
- 'tvw-bottom-6', 'tvw-right-6', 'tvw-left-6', 'tvw-top-6',
475
- 'tvw-bottom-4', 'tvw-right-4', 'tvw-left-4', 'tvw-top-4'
476
- );
477
-
478
514
  // Wrapper - fixed position, flush with edges
479
515
  wrapper.style.cssText = `
480
516
  position: fixed !important;
@@ -491,6 +527,8 @@ export const createAgentExperience = (
491
527
  `;
492
528
 
493
529
  // Panel - fill wrapper (override inline width/max-width from panel.ts)
530
+ // Box-shadow is on panel to avoid rendering artifacts with container's overflow:hidden
531
+ // Border-radius on panel ensures shadow follows rounded corners
494
532
  panel.style.cssText = `
495
533
  position: relative !important;
496
534
  display: flex !important;
@@ -502,12 +540,15 @@ export const createAgentExperience = (
502
540
  min-height: 0 !important;
503
541
  margin: 0 !important;
504
542
  padding: 0 !important;
543
+ box-shadow: ${panelShadow} !important;
544
+ border-radius: ${panelBorderRadius} !important;
505
545
  `;
506
546
  // Force override any inline width/maxWidth that may be set elsewhere
507
547
  panel.style.setProperty('width', '100%', 'important');
508
548
  panel.style.setProperty('max-width', '100%', 'important');
509
549
 
510
550
  // Container - apply configurable styles with sidebar layout
551
+ // Note: box-shadow is on panel, not container
511
552
  container.style.cssText = `
512
553
  display: flex !important;
513
554
  flex-direction: column !important;
@@ -519,7 +560,6 @@ export const createAgentExperience = (
519
560
  overflow: hidden !important;
520
561
  border-radius: ${panelBorderRadius} !important;
521
562
  border: ${panelBorder} !important;
522
- box-shadow: ${panelShadow} !important;
523
563
  `;
524
564
 
525
565
  // Remove footer border in sidebar mode
@@ -529,6 +569,13 @@ export const createAgentExperience = (
529
569
  padding: 8px 16px 12px 16px !important;
530
570
  `;
531
571
  }
572
+
573
+ // Apply max-height constraints to wrapper to prevent expanding past viewport top
574
+ // Use both -moz-available (Firefox) and stretch (standard) for cross-browser support
575
+ // Append to cssText to allow multiple fallback values for the same property
576
+ const maxHeightStyles = 'max-height: -moz-available !important; max-height: stretch !important;';
577
+ const paddingStyles = sidebarMode ? '' : 'padding-top: 1.25em !important;';
578
+ wrapper.style.cssText += maxHeightStyles + paddingStyles;
532
579
  };
533
580
  applyFullHeightStyles();
534
581