@runtypelabs/persona 2.0.0 → 2.1.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/dist/widget.css CHANGED
@@ -927,6 +927,7 @@
927
927
 
928
928
  .persona-widget-composer {
929
929
  border-radius: var(--persona-input-radius, var(--persona-radius-lg, 0.5rem));
930
+ box-shadow: var(--persona-composer-shadow, none);
930
931
  }
931
932
 
932
933
  .persona-form-grid {
@@ -1168,6 +1169,18 @@
1168
1169
  box-shadow: var(--persona-message-assistant-shadow, 0 1px 2px 0 rgb(0 0 0 / 0.05));
1169
1170
  }
1170
1171
 
1172
+ #persona-root .vanilla-message-user-bubble.persona-shadow-sm {
1173
+ box-shadow: var(--persona-message-user-shadow, 0 5px 15px rgba(15, 23, 42, 0.08));
1174
+ }
1175
+
1176
+ #persona-root .vanilla-tool-bubble.persona-shadow-sm {
1177
+ box-shadow: var(--persona-tool-bubble-shadow, 0 5px 15px rgba(15, 23, 42, 0.08));
1178
+ }
1179
+
1180
+ #persona-root .vanilla-reasoning-bubble.persona-shadow-sm {
1181
+ box-shadow: var(--persona-reasoning-bubble-shadow, 0 5px 15px rgba(15, 23, 42, 0.08));
1182
+ }
1183
+
1171
1184
  /* Artifact markdown (no .vanilla-message-bubble wrapper) */
1172
1185
  #persona-root .persona-markdown-bubble {
1173
1186
  color: var(--persona-text, #111827);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runtypelabs/persona",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
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",
@@ -927,6 +927,7 @@
927
927
 
928
928
  .persona-widget-composer {
929
929
  border-radius: var(--persona-input-radius, var(--persona-radius-lg, 0.5rem));
930
+ box-shadow: var(--persona-composer-shadow, none);
930
931
  }
931
932
 
932
933
  .persona-form-grid {
@@ -1168,6 +1169,18 @@
1168
1169
  box-shadow: var(--persona-message-assistant-shadow, 0 1px 2px 0 rgb(0 0 0 / 0.05));
1169
1170
  }
1170
1171
 
1172
+ #persona-root .vanilla-message-user-bubble.persona-shadow-sm {
1173
+ box-shadow: var(--persona-message-user-shadow, 0 5px 15px rgba(15, 23, 42, 0.08));
1174
+ }
1175
+
1176
+ #persona-root .vanilla-tool-bubble.persona-shadow-sm {
1177
+ box-shadow: var(--persona-tool-bubble-shadow, 0 5px 15px rgba(15, 23, 42, 0.08));
1178
+ }
1179
+
1180
+ #persona-root .vanilla-reasoning-bubble.persona-shadow-sm {
1181
+ box-shadow: var(--persona-reasoning-bubble-shadow, 0 5px 15px rgba(15, 23, 42, 0.08));
1182
+ }
1183
+
1171
1184
  /* Artifact markdown (no .vanilla-message-bubble wrapper) */
1172
1185
  #persona-root .persona-markdown-bubble {
1173
1186
  color: var(--persona-text, #111827);
@@ -206,6 +206,8 @@ export interface MessageTokens {
206
206
  background: TokenReference<'color'>;
207
207
  text: TokenReference<'color'>;
208
208
  borderRadius: TokenReference<'radius'>;
209
+ /** User bubble box-shadow (token ref or raw CSS, e.g. `none`). */
210
+ shadow?: string;
209
211
  };
210
212
  assistant: {
211
213
  background: TokenReference<'color'>;
@@ -279,6 +281,23 @@ export interface AttachmentTokens {
279
281
  };
280
282
  }
281
283
 
284
+ /** Tool-call row chrome (collapsible tool bubbles). */
285
+ export interface ToolBubbleTokens {
286
+ /** Box-shadow for tool bubbles (token ref or raw CSS, e.g. `none`). */
287
+ shadow: string;
288
+ }
289
+
290
+ /** Reasoning / “thinking” row chrome. */
291
+ export interface ReasoningBubbleTokens {
292
+ shadow: string;
293
+ }
294
+
295
+ /** Composer (message input) chrome. */
296
+ export interface ComposerChromeTokens {
297
+ /** Box-shadow on the composer form (raw CSS, e.g. `none`). */
298
+ shadow: string;
299
+ }
300
+
282
301
  export interface ComponentTokens {
283
302
  button: ButtonTokens;
284
303
  input: InputTokens;
@@ -291,6 +310,9 @@ export interface ComponentTokens {
291
310
  voice: VoiceTokens;
292
311
  approval: ApprovalTokens;
293
312
  attachment: AttachmentTokens;
313
+ toolBubble: ToolBubbleTokens;
314
+ reasoningBubble: ReasoningBubbleTokens;
315
+ composer: ComposerChromeTokens;
294
316
  }
295
317
 
296
318
  export interface PaletteExtras {
package/src/types.ts CHANGED
@@ -714,6 +714,28 @@ export type AgentWidgetTheme = {
714
714
  * @default "16px"
715
715
  */
716
716
  panelBorderRadius?: string;
717
+ /**
718
+ * Box-shadow for user message bubbles (bubble message layout).
719
+ * @example "none" | "0 1px 2px rgba(0,0,0,0.05)"
720
+ */
721
+ messageUserShadow?: string;
722
+ /**
723
+ * Box-shadow for assistant message bubbles (bubble message layout).
724
+ * Overrides the default subtle assistant shadow when set.
725
+ */
726
+ messageAssistantShadow?: string;
727
+ /**
728
+ * Box-shadow for tool-call / function-call rows.
729
+ */
730
+ toolBubbleShadow?: string;
731
+ /**
732
+ * Box-shadow for reasoning (“thinking”) rows.
733
+ */
734
+ reasoningBubbleShadow?: string;
735
+ /**
736
+ * Box-shadow on the composer (input) container.
737
+ */
738
+ composerShadow?: string;
717
739
  };
718
740
 
719
741
  export type AgentWidgetDockConfig = {
@@ -1141,6 +1163,8 @@ export type AgentWidgetApprovalConfig = {
1141
1163
  };
1142
1164
 
1143
1165
  export type AgentWidgetToolCallConfig = {
1166
+ /** Box-shadow for tool-call bubbles; overrides `theme.toolBubbleShadow` when set. */
1167
+ shadow?: string;
1144
1168
  backgroundColor?: string;
1145
1169
  borderColor?: string;
1146
1170
  borderWidth?: string;
@@ -139,6 +139,28 @@ export function migrateV1Theme(
139
139
  migrated.components.panel = {};
140
140
  }
141
141
  migrated.components.panel.borderRadius = value;
142
+ } else if (key === 'messageUserShadow') {
143
+ if (!migrated.components) migrated.components = {};
144
+ if (!migrated.components.message) migrated.components.message = {};
145
+ if (!migrated.components.message.user) migrated.components.message.user = {};
146
+ (migrated.components.message.user as { shadow?: string }).shadow = value as string;
147
+ } else if (key === 'messageAssistantShadow') {
148
+ if (!migrated.components) migrated.components = {};
149
+ if (!migrated.components.message) migrated.components.message = {};
150
+ if (!migrated.components.message.assistant) migrated.components.message.assistant = {};
151
+ (migrated.components.message.assistant as { shadow?: string }).shadow = value as string;
152
+ } else if (key === 'toolBubbleShadow') {
153
+ if (!migrated.components) migrated.components = {};
154
+ if (!migrated.components.toolBubble) migrated.components.toolBubble = {};
155
+ (migrated.components.toolBubble as { shadow?: string }).shadow = value as string;
156
+ } else if (key === 'reasoningBubbleShadow') {
157
+ if (!migrated.components) migrated.components = {};
158
+ if (!migrated.components.reasoningBubble) migrated.components.reasoningBubble = {};
159
+ (migrated.components.reasoningBubble as { shadow?: string }).shadow = value as string;
160
+ } else if (key === 'composerShadow') {
161
+ if (!migrated.components) migrated.components = {};
162
+ if (!migrated.components.composer) migrated.components.composer = {};
163
+ (migrated.components.composer as { shadow?: string }).shadow = value as string;
142
164
  }
143
165
  }
144
166
 
@@ -165,8 +187,27 @@ export function validateV1Theme(v1Theme: unknown): {
165
187
  return { valid: true, warnings: [] };
166
188
  }
167
189
 
190
+ const v1ThemeChromeKeys = new Set([
191
+ 'panelBorder',
192
+ 'panelShadow',
193
+ 'panelBorderRadius',
194
+ 'messageUserShadow',
195
+ 'messageAssistantShadow',
196
+ 'toolBubbleShadow',
197
+ 'reasoningBubbleShadow',
198
+ 'composerShadow',
199
+ ]);
200
+
168
201
  const deprecatedProperties = Object.keys(theme).filter(
169
- (key) => !(key in v1ToV2Mapping || key in v1RadiusMapping || key === 'inputFontFamily' || key === 'inputFontWeight' || key.startsWith('panel'))
202
+ (key) =>
203
+ !(
204
+ key in v1ToV2Mapping ||
205
+ key in v1RadiusMapping ||
206
+ key === 'inputFontFamily' ||
207
+ key === 'inputFontWeight' ||
208
+ key.startsWith('panel') ||
209
+ v1ThemeChromeKeys.has(key)
210
+ )
170
211
  );
171
212
 
172
213
  if (deprecatedProperties.length > 0) {
@@ -1,7 +1,7 @@
1
1
  // @vitest-environment jsdom
2
2
 
3
3
  import { afterEach, describe, expect, it } from 'vitest';
4
- import { createTheme, getActiveTheme, themeToCssVariables } from './theme';
4
+ import { applyThemeVariables, createTheme, getActiveTheme, themeToCssVariables } from './theme';
5
5
 
6
6
  describe('theme utils', () => {
7
7
  afterEach(() => {
@@ -122,4 +122,36 @@ describe('theme utils', () => {
122
122
  expect(cssVars['--persona-md-h2-weight']).toBe('600');
123
123
  expect(cssVars['--persona-md-prose-font-family']).toBe('Georgia, serif');
124
124
  });
125
+
126
+ it('maps flat AgentWidgetTheme bubble shadow keys to consumer CSS variables', () => {
127
+ const cfg = {
128
+ colorScheme: 'light' as const,
129
+ theme: {
130
+ toolBubbleShadow: 'none',
131
+ reasoningBubbleShadow: 'none',
132
+ messageUserShadow: 'none',
133
+ messageAssistantShadow: 'none',
134
+ composerShadow: 'none',
135
+ },
136
+ };
137
+
138
+ const active = getActiveTheme(cfg as any);
139
+ const cssVars = themeToCssVariables(active);
140
+
141
+ expect(cssVars['--persona-tool-bubble-shadow']).toBe('none');
142
+ expect(cssVars['--persona-reasoning-bubble-shadow']).toBe('none');
143
+ expect(cssVars['--persona-message-user-shadow']).toBe('none');
144
+ expect(cssVars['--persona-message-assistant-shadow']).toBe('none');
145
+ expect(cssVars['--persona-composer-shadow']).toBe('none');
146
+ });
147
+
148
+ it('lets config.toolCall.shadow override theme tool bubble shadow on the root element', () => {
149
+ const el = document.createElement('div');
150
+ applyThemeVariables(el, {
151
+ colorScheme: 'light',
152
+ theme: { toolBubbleShadow: '0 1px 2px rgba(255,0,0,0.5)' },
153
+ toolCall: { shadow: 'none' },
154
+ } as any);
155
+ expect(el.style.getPropertyValue('--persona-tool-bubble-shadow').trim()).toBe('none');
156
+ });
125
157
  });
@@ -220,6 +220,14 @@ export const applyThemeVariables = (
220
220
  for (const [name, value] of Object.entries(cssVars)) {
221
221
  element.style.setProperty(name, value);
222
222
  }
223
+
224
+ const toolCallShadow = (config as AgentWidgetConfig | undefined)?.toolCall?.shadow;
225
+ if (toolCallShadow !== undefined) {
226
+ element.style.setProperty(
227
+ '--persona-tool-bubble-shadow',
228
+ toolCallShadow.trim() === '' ? 'none' : toolCallShadow
229
+ );
230
+ }
223
231
  };
224
232
 
225
233
  export const createThemeObserver = (
@@ -271,6 +271,7 @@ export const DEFAULT_COMPONENTS: ComponentTokens = {
271
271
  background: 'semantic.colors.primary',
272
272
  text: 'semantic.colors.textInverse',
273
273
  borderRadius: 'palette.radius.lg',
274
+ shadow: 'palette.shadows.sm',
274
275
  },
275
276
  assistant: {
276
277
  background: 'semantic.colors.container',
@@ -280,6 +281,15 @@ export const DEFAULT_COMPONENTS: ComponentTokens = {
280
281
  shadow: 'palette.shadows.sm',
281
282
  },
282
283
  },
284
+ toolBubble: {
285
+ shadow: 'palette.shadows.sm',
286
+ },
287
+ reasoningBubble: {
288
+ shadow: 'palette.shadows.sm',
289
+ },
290
+ composer: {
291
+ shadow: 'none',
292
+ },
283
293
  markdown: {
284
294
  inlineCode: {
285
295
  background: 'semantic.colors.container',
@@ -637,6 +647,8 @@ export function themeToCssVariables(theme: PersonaTheme): Record<string, string>
637
647
  cssVars['--persona-components-message-user-background'] ?? cssVars['--persona-accent'];
638
648
  cssVars['--persona-message-user-text'] =
639
649
  cssVars['--persona-components-message-user-text'] ?? cssVars['--persona-text-inverse'];
650
+ cssVars['--persona-message-user-shadow'] =
651
+ cssVars['--persona-components-message-user-shadow'] ?? '0 5px 15px rgba(15, 23, 42, 0.08)';
640
652
  cssVars['--persona-message-assistant-bg'] =
641
653
  cssVars['--persona-components-message-assistant-background'] ?? cssVars['--persona-surface'];
642
654
  cssVars['--persona-message-assistant-text'] =
@@ -646,6 +658,13 @@ export function themeToCssVariables(theme: PersonaTheme): Record<string, string>
646
658
  cssVars['--persona-message-assistant-shadow'] =
647
659
  cssVars['--persona-components-message-assistant-shadow'] ?? '0 1px 2px 0 rgb(0 0 0 / 0.05)';
648
660
 
661
+ cssVars['--persona-tool-bubble-shadow'] =
662
+ cssVars['--persona-components-toolBubble-shadow'] ?? '0 5px 15px rgba(15, 23, 42, 0.08)';
663
+ cssVars['--persona-reasoning-bubble-shadow'] =
664
+ cssVars['--persona-components-reasoningBubble-shadow'] ?? '0 5px 15px rgba(15, 23, 42, 0.08)';
665
+ cssVars['--persona-composer-shadow'] =
666
+ cssVars['--persona-components-composer-shadow'] ?? 'none';
667
+
649
668
  cssVars['--persona-md-inline-code-bg'] =
650
669
  cssVars['--persona-components-markdown-inlineCode-background'] ?? cssVars['--persona-container'];
651
670
  cssVars['--persona-md-inline-code-color'] =