@runtypelabs/persona 2.0.0 → 2.2.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/LICENSE +21 -0
- package/dist/index.cjs +40 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -1
- package/dist/index.d.ts +142 -1
- package/dist/index.global.js +79 -79
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +40 -40
- package/dist/index.js.map +1 -1
- package/dist/widget.css +53 -10
- package/package.json +2 -1
- package/src/client.ts +0 -1
- package/src/components/artifact-pane.ts +2 -0
- package/src/components/composer-builder.ts +1 -0
- package/src/components/header-builder.ts +1 -0
- package/src/components/header-layouts.ts +41 -1
- package/src/components/message-bubble.ts +2 -0
- package/src/components/panel.ts +2 -0
- package/src/index.ts +14 -1
- package/src/presets.ts +127 -0
- package/src/styles/widget.css +53 -10
- package/src/types/theme.ts +63 -0
- package/src/types.ts +38 -0
- package/src/ui.ts +14 -1
- package/src/utils/migration.ts +42 -1
- package/src/utils/theme.test.ts +33 -1
- package/src/utils/theme.ts +8 -0
- package/src/utils/tokens.ts +73 -0
package/src/ui.ts
CHANGED
|
@@ -1142,6 +1142,9 @@ export const createAgentExperience = (
|
|
|
1142
1142
|
event.stopPropagation();
|
|
1143
1143
|
const artifactId = dlBtn.getAttribute('data-download-artifact');
|
|
1144
1144
|
if (!artifactId) return;
|
|
1145
|
+
// Let integrator intercept
|
|
1146
|
+
const dlPrevented = config.features?.artifacts?.onArtifactAction?.({ type: 'download', artifactId });
|
|
1147
|
+
if (dlPrevented === true) return;
|
|
1145
1148
|
// Try session state first, fall back to content stored in the card's rawContent props
|
|
1146
1149
|
const artifact = session.getArtifactById(artifactId);
|
|
1147
1150
|
let markdown = artifact?.markdown;
|
|
@@ -1180,6 +1183,9 @@ export const createAgentExperience = (
|
|
|
1180
1183
|
if (!card) return;
|
|
1181
1184
|
const artifactId = card.getAttribute('data-open-artifact');
|
|
1182
1185
|
if (!artifactId) return;
|
|
1186
|
+
// Let integrator intercept
|
|
1187
|
+
const openPrevented = config.features?.artifacts?.onArtifactAction?.({ type: 'open', artifactId });
|
|
1188
|
+
if (openPrevented === true) return;
|
|
1183
1189
|
event.preventDefault();
|
|
1184
1190
|
event.stopPropagation();
|
|
1185
1191
|
session.selectArtifact(artifactId);
|
|
@@ -3560,6 +3566,8 @@ export const createAgentExperience = (
|
|
|
3560
3566
|
const previousMessageActions = config.messageActions;
|
|
3561
3567
|
const previousLayoutMessages = config.layout?.messages;
|
|
3562
3568
|
const previousColorScheme = config.colorScheme;
|
|
3569
|
+
const previousLoadingIndicator = config.loadingIndicator;
|
|
3570
|
+
const previousIterationDisplay = config.iterationDisplay;
|
|
3563
3571
|
config = { ...config, ...nextConfig };
|
|
3564
3572
|
// applyFullHeightStyles resets mount.style.cssText, so call it before applyThemeVariables
|
|
3565
3573
|
applyFullHeightStyles();
|
|
@@ -3790,7 +3798,12 @@ export const createAgentExperience = (
|
|
|
3790
3798
|
const toolCallConfigChanged = JSON.stringify(nextConfig.toolCall) !== JSON.stringify(previousToolCallConfig);
|
|
3791
3799
|
const messageActionsChanged = JSON.stringify(config.messageActions) !== JSON.stringify(previousMessageActions);
|
|
3792
3800
|
const layoutMessagesChanged = JSON.stringify(config.layout?.messages) !== JSON.stringify(previousLayoutMessages);
|
|
3793
|
-
const
|
|
3801
|
+
const loadingIndicatorChanged = config.loadingIndicator?.render !== previousLoadingIndicator?.render
|
|
3802
|
+
|| config.loadingIndicator?.renderIdle !== previousLoadingIndicator?.renderIdle
|
|
3803
|
+
|| config.loadingIndicator?.showBubble !== previousLoadingIndicator?.showBubble;
|
|
3804
|
+
const iterationDisplayChanged = config.iterationDisplay !== previousIterationDisplay;
|
|
3805
|
+
const messagesConfigChanged = toolCallConfigChanged || messageActionsChanged || layoutMessagesChanged
|
|
3806
|
+
|| loadingIndicatorChanged || iterationDisplayChanged;
|
|
3794
3807
|
if (messagesConfigChanged && session) {
|
|
3795
3808
|
configVersion++;
|
|
3796
3809
|
renderMessagesWithPlugins(messagesWrapper, session.getMessages(), postprocess);
|
package/src/utils/migration.ts
CHANGED
|
@@ -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) =>
|
|
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) {
|
package/src/utils/theme.test.ts
CHANGED
|
@@ -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
|
});
|
package/src/utils/theme.ts
CHANGED
|
@@ -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 = (
|
package/src/utils/tokens.ts
CHANGED
|
@@ -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'] =
|
|
@@ -670,6 +689,42 @@ export function themeToCssVariables(theme: PersonaTheme): Record<string, string>
|
|
|
670
689
|
cssVars['--persona-md-prose-font-family'] = mdProseFont;
|
|
671
690
|
}
|
|
672
691
|
|
|
692
|
+
// Artifact tokens
|
|
693
|
+
const components = theme.components;
|
|
694
|
+
const artifact = components?.artifact;
|
|
695
|
+
if (artifact?.toolbar) {
|
|
696
|
+
const t = artifact.toolbar;
|
|
697
|
+
if (t.iconHoverColor) cssVars['--persona-artifact-toolbar-icon-hover-color'] = t.iconHoverColor;
|
|
698
|
+
if (t.iconHoverBackground) cssVars['--persona-artifact-toolbar-icon-hover-bg'] = t.iconHoverBackground;
|
|
699
|
+
if (t.iconPadding) cssVars['--persona-artifact-toolbar-icon-padding'] = t.iconPadding;
|
|
700
|
+
if (t.iconBorderRadius) cssVars['--persona-artifact-toolbar-icon-radius'] = t.iconBorderRadius;
|
|
701
|
+
if (t.iconBorder) cssVars['--persona-artifact-toolbar-icon-border'] = t.iconBorder;
|
|
702
|
+
if (t.toggleGroupGap) cssVars['--persona-artifact-toolbar-toggle-group-gap'] = t.toggleGroupGap;
|
|
703
|
+
if (t.toggleBorderRadius) cssVars['--persona-artifact-toolbar-toggle-radius'] = t.toggleBorderRadius;
|
|
704
|
+
if (t.copyBackground) cssVars['--persona-artifact-toolbar-copy-bg'] = t.copyBackground;
|
|
705
|
+
if (t.copyBorder) cssVars['--persona-artifact-toolbar-copy-border'] = t.copyBorder;
|
|
706
|
+
if (t.copyColor) cssVars['--persona-artifact-toolbar-copy-color'] = t.copyColor;
|
|
707
|
+
if (t.copyBorderRadius) cssVars['--persona-artifact-toolbar-copy-radius'] = t.copyBorderRadius;
|
|
708
|
+
if (t.copyPadding) cssVars['--persona-artifact-toolbar-copy-padding'] = t.copyPadding;
|
|
709
|
+
if (t.copyMenuBackground) cssVars['--persona-artifact-toolbar-copy-menu-bg'] = t.copyMenuBackground;
|
|
710
|
+
if (t.copyMenuBorder) cssVars['--persona-artifact-toolbar-copy-menu-border'] = t.copyMenuBorder;
|
|
711
|
+
if (t.copyMenuShadow) cssVars['--persona-artifact-toolbar-copy-menu-shadow'] = t.copyMenuShadow;
|
|
712
|
+
if (t.copyMenuBorderRadius) cssVars['--persona-artifact-toolbar-copy-menu-radius'] = t.copyMenuBorderRadius;
|
|
713
|
+
if (t.copyMenuItemHoverBackground) cssVars['--persona-artifact-toolbar-copy-menu-item-hover-bg'] = t.copyMenuItemHoverBackground;
|
|
714
|
+
}
|
|
715
|
+
if (artifact?.tab) {
|
|
716
|
+
const t = artifact.tab;
|
|
717
|
+
if (t.background) cssVars['--persona-artifact-tab-bg'] = t.background;
|
|
718
|
+
if (t.activeBackground) cssVars['--persona-artifact-tab-active-bg'] = t.activeBackground;
|
|
719
|
+
if (t.activeBorder) cssVars['--persona-artifact-tab-active-border'] = t.activeBorder;
|
|
720
|
+
if (t.borderRadius) cssVars['--persona-artifact-tab-radius'] = t.borderRadius;
|
|
721
|
+
if (t.textColor) cssVars['--persona-artifact-tab-color'] = t.textColor;
|
|
722
|
+
}
|
|
723
|
+
if (artifact?.pane) {
|
|
724
|
+
const t = artifact.pane;
|
|
725
|
+
if (t.toolbarBackground) cssVars['--persona-artifact-toolbar-bg'] = t.toolbarBackground;
|
|
726
|
+
}
|
|
727
|
+
|
|
673
728
|
return cssVars;
|
|
674
729
|
}
|
|
675
730
|
|
|
@@ -680,3 +735,21 @@ export function applyThemeVariables(element: HTMLElement, theme: PersonaTheme):
|
|
|
680
735
|
element.style.setProperty(name, value);
|
|
681
736
|
}
|
|
682
737
|
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Stable `data-persona-theme-zone` values applied to key widget regions.
|
|
741
|
+
* Visual editors should use `[data-persona-theme-zone="header"]` selectors
|
|
742
|
+
* rather than internal class names.
|
|
743
|
+
*/
|
|
744
|
+
export const THEME_ZONES = {
|
|
745
|
+
header: 'Widget header bar',
|
|
746
|
+
messages: 'Message list area',
|
|
747
|
+
'user-message': 'User message bubble',
|
|
748
|
+
'assistant-message': 'Assistant message bubble',
|
|
749
|
+
composer: 'Footer / composer area',
|
|
750
|
+
container: 'Main widget container',
|
|
751
|
+
'artifact-pane': 'Artifact sidebar',
|
|
752
|
+
'artifact-toolbar': 'Artifact toolbar',
|
|
753
|
+
} as const;
|
|
754
|
+
|
|
755
|
+
export type ThemeZone = keyof typeof THEME_ZONES;
|