@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/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);
|
|
@@ -2051,9 +2064,9 @@
|
|
|
2051
2064
|
display: inline-flex;
|
|
2052
2065
|
align-items: center;
|
|
2053
2066
|
justify-content: center;
|
|
2054
|
-
padding: 0.25rem;
|
|
2055
|
-
border-radius: var(--persona-radius-md, 0.375rem);
|
|
2056
|
-
border: 1px solid var(--persona-border, #e5e7eb);
|
|
2067
|
+
padding: var(--persona-artifact-toolbar-icon-padding, 0.25rem);
|
|
2068
|
+
border-radius: var(--persona-artifact-toolbar-icon-radius, var(--persona-radius-md, 0.375rem));
|
|
2069
|
+
border: var(--persona-artifact-toolbar-icon-border, 1px solid var(--persona-border, #e5e7eb));
|
|
2057
2070
|
background: var(--persona-surface, #ffffff);
|
|
2058
2071
|
color: var(--persona-artifact-doc-toolbar-icon-color, var(--persona-text, #111827));
|
|
2059
2072
|
cursor: pointer;
|
|
@@ -2061,7 +2074,8 @@
|
|
|
2061
2074
|
}
|
|
2062
2075
|
|
|
2063
2076
|
#persona-root .persona-artifact-toolbar-document .persona-artifact-doc-icon-btn:hover {
|
|
2064
|
-
|
|
2077
|
+
color: var(--persona-artifact-toolbar-icon-hover-color, inherit);
|
|
2078
|
+
background: var(--persona-artifact-toolbar-icon-hover-bg, var(--persona-container, #f3f4f6));
|
|
2065
2079
|
}
|
|
2066
2080
|
|
|
2067
2081
|
#persona-root .persona-artifact-toolbar-document .persona-artifact-doc-icon-btn[aria-pressed="true"] {
|
|
@@ -2073,24 +2087,53 @@
|
|
|
2073
2087
|
display: inline-flex;
|
|
2074
2088
|
align-items: center;
|
|
2075
2089
|
gap: 0.35rem;
|
|
2076
|
-
padding: 0.25rem 0.5rem;
|
|
2077
|
-
border-radius: var(--persona-radius-md, 0.375rem);
|
|
2078
|
-
border: 1px solid var(--persona-border, #e5e7eb);
|
|
2079
|
-
background: var(--persona-surface, #ffffff);
|
|
2080
|
-
color: var(--persona-artifact-doc-toolbar-icon-color, var(--persona-text, #111827));
|
|
2090
|
+
padding: var(--persona-artifact-toolbar-copy-padding, 0.25rem 0.5rem);
|
|
2091
|
+
border-radius: var(--persona-artifact-toolbar-copy-radius, var(--persona-radius-md, 0.375rem));
|
|
2092
|
+
border: var(--persona-artifact-toolbar-copy-border, 1px solid var(--persona-border, #e5e7eb));
|
|
2093
|
+
background: var(--persona-artifact-toolbar-copy-bg, var(--persona-surface, #ffffff));
|
|
2094
|
+
color: var(--persona-artifact-toolbar-copy-color, var(--persona-artifact-doc-toolbar-icon-color, var(--persona-text, #111827)));
|
|
2081
2095
|
cursor: pointer;
|
|
2082
2096
|
font-size: 0.75rem;
|
|
2083
2097
|
line-height: 1.25;
|
|
2084
2098
|
}
|
|
2085
2099
|
|
|
2086
2100
|
#persona-root .persona-artifact-toolbar-document .persona-artifact-doc-copy-btn:hover {
|
|
2087
|
-
background: var(--persona-container, #f3f4f6);
|
|
2101
|
+
background: var(--persona-artifact-toolbar-icon-hover-bg, var(--persona-container, #f3f4f6));
|
|
2088
2102
|
}
|
|
2089
2103
|
|
|
2090
2104
|
#persona-root .persona-artifact-toolbar-document .persona-artifact-doc-copy-label {
|
|
2091
2105
|
font-weight: 500;
|
|
2092
2106
|
}
|
|
2093
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
|
+
/* Artifact tab theming */
|
|
2121
|
+
#persona-root .persona-artifact-tab {
|
|
2122
|
+
background: var(--persona-artifact-tab-bg, transparent);
|
|
2123
|
+
border-radius: var(--persona-artifact-tab-radius, 0.5rem);
|
|
2124
|
+
color: var(--persona-artifact-tab-color, inherit);
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
#persona-root .persona-artifact-tab.persona-bg-persona-container {
|
|
2128
|
+
background: var(--persona-artifact-tab-active-bg, var(--persona-container, #f3f4f6));
|
|
2129
|
+
border-color: var(--persona-artifact-tab-active-border, var(--persona-border, #e5e7eb));
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
/* Artifact toolbar background theming */
|
|
2133
|
+
#persona-root .persona-artifact-toolbar {
|
|
2134
|
+
background: var(--persona-artifact-toolbar-bg, var(--persona-surface, #fff));
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2094
2137
|
/* Draggable split handle (desktop split only; hidden in drawer / narrow host / small viewport) */
|
|
2095
2138
|
#persona-root .persona-artifact-split-handle {
|
|
2096
2139
|
width: 6px;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runtypelabs/persona",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.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",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"engines": {
|
|
48
48
|
"node": ">=18.17.0"
|
|
49
49
|
},
|
|
50
|
+
"author": "Runtype",
|
|
50
51
|
"license": "MIT",
|
|
51
52
|
"keywords": [
|
|
52
53
|
"ai",
|
package/src/client.ts
CHANGED
|
@@ -45,7 +45,6 @@ const DEFAULT_CLIENT_API_BASE = "https://api.runtype.com";
|
|
|
45
45
|
* Check if a message has valid (non-empty) content for sending to the API.
|
|
46
46
|
* Filters out messages with empty content that would cause validation errors.
|
|
47
47
|
*
|
|
48
|
-
* @see https://github.com/anthropics/claude-code/issues/XXX - Empty assistant messages from failed requests
|
|
49
48
|
*/
|
|
50
49
|
const hasValidContent = (message: AgentWidgetMessage): boolean => {
|
|
51
50
|
// Check contentParts (multi-modal content)
|
|
@@ -127,6 +127,7 @@ export function createArtifactPane(
|
|
|
127
127
|
"aside",
|
|
128
128
|
"persona-artifact-pane persona-flex persona-flex-col persona-min-h-0 persona-min-w-0 persona-bg-persona-surface persona-text-persona-primary persona-border-l persona-border-persona-border"
|
|
129
129
|
);
|
|
130
|
+
shell.setAttribute("data-persona-theme-zone", "artifact-pane");
|
|
130
131
|
if (documentChrome) {
|
|
131
132
|
shell.classList.add("persona-artifact-pane-document");
|
|
132
133
|
}
|
|
@@ -135,6 +136,7 @@ export function createArtifactPane(
|
|
|
135
136
|
"div",
|
|
136
137
|
"persona-artifact-toolbar persona-flex persona-items-center persona-justify-between persona-gap-2 persona-px-2 persona-py-2 persona-border-b persona-border-persona-border persona-shrink-0"
|
|
137
138
|
);
|
|
139
|
+
toolbar.setAttribute("data-persona-theme-zone", "artifact-toolbar");
|
|
138
140
|
if (documentChrome) {
|
|
139
141
|
toolbar.classList.add("persona-artifact-toolbar-document");
|
|
140
142
|
}
|
|
@@ -68,6 +68,7 @@ export const buildComposer = (context: ComposerBuildContext): ComposerElements =
|
|
|
68
68
|
"div",
|
|
69
69
|
"persona-widget-footer persona-border-t-persona-divider persona-bg-persona-surface persona-px-6 persona-py-4"
|
|
70
70
|
);
|
|
71
|
+
footer.setAttribute("data-persona-theme-zone", "composer");
|
|
71
72
|
|
|
72
73
|
const suggestions = createElement(
|
|
73
74
|
"div",
|
|
@@ -31,6 +31,7 @@ export const buildHeader = (context: HeaderBuildContext): HeaderElements => {
|
|
|
31
31
|
"div",
|
|
32
32
|
"persona-widget-header persona-flex persona-items-center persona-gap-3 persona-px-6 persona-py-5"
|
|
33
33
|
);
|
|
34
|
+
header.setAttribute("data-persona-theme-zone", "header");
|
|
34
35
|
header.style.backgroundColor = 'var(--persona-header-bg, var(--persona-surface, #ffffff))';
|
|
35
36
|
header.style.borderBottomWidth = '1px';
|
|
36
37
|
header.style.borderBottomStyle = 'solid';
|
|
@@ -24,12 +24,32 @@ export type HeaderLayoutRenderer = (context: HeaderLayoutContext) => HeaderEleme
|
|
|
24
24
|
* Full header with icon, title, subtitle, clear chat, and close button
|
|
25
25
|
*/
|
|
26
26
|
export const buildDefaultHeader: HeaderLayoutRenderer = (context) => {
|
|
27
|
-
|
|
27
|
+
const elements = buildHeader({
|
|
28
28
|
config: context.config,
|
|
29
29
|
showClose: context.showClose,
|
|
30
30
|
onClose: context.onClose,
|
|
31
31
|
onClearChat: context.onClearChat
|
|
32
32
|
});
|
|
33
|
+
|
|
34
|
+
// Make the title/subtitle area clickable when onTitleClick is provided
|
|
35
|
+
const onTitleClick = context.layoutHeaderConfig?.onTitleClick;
|
|
36
|
+
if (onTitleClick) {
|
|
37
|
+
const headerCopy = elements.headerTitle.parentElement;
|
|
38
|
+
if (headerCopy) {
|
|
39
|
+
headerCopy.style.cursor = "pointer";
|
|
40
|
+
headerCopy.setAttribute("role", "button");
|
|
41
|
+
headerCopy.setAttribute("tabindex", "0");
|
|
42
|
+
headerCopy.addEventListener("click", () => onTitleClick());
|
|
43
|
+
headerCopy.addEventListener("keydown", (e) => {
|
|
44
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
onTitleClick();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return elements;
|
|
33
53
|
};
|
|
34
54
|
|
|
35
55
|
/**
|
|
@@ -68,6 +88,7 @@ export const buildMinimalHeader: HeaderLayoutRenderer = (context) => {
|
|
|
68
88
|
"div",
|
|
69
89
|
"persona-flex persona-items-center persona-justify-between persona-bg-persona-surface persona-px-6 persona-py-4 persona-border-b-persona-divider"
|
|
70
90
|
);
|
|
91
|
+
header.setAttribute("data-persona-theme-zone", "header");
|
|
71
92
|
|
|
72
93
|
const titleRow = createElement(
|
|
73
94
|
"div",
|
|
@@ -85,6 +106,25 @@ export const buildMinimalHeader: HeaderLayoutRenderer = (context) => {
|
|
|
85
106
|
layoutHeaderConfig?.onAction ?? onHeaderAction
|
|
86
107
|
);
|
|
87
108
|
|
|
109
|
+
// Make title row clickable when onTitleClick is provided
|
|
110
|
+
if (layoutHeaderConfig?.onTitleClick) {
|
|
111
|
+
titleRow.style.cursor = "pointer";
|
|
112
|
+
titleRow.setAttribute("role", "button");
|
|
113
|
+
titleRow.setAttribute("tabindex", "0");
|
|
114
|
+
const handleTitleClick = layoutHeaderConfig.onTitleClick;
|
|
115
|
+
titleRow.addEventListener("click", (e) => {
|
|
116
|
+
// Skip if the click was on a trailing action button
|
|
117
|
+
if ((e.target as HTMLElement).closest("button")) return;
|
|
118
|
+
handleTitleClick();
|
|
119
|
+
});
|
|
120
|
+
titleRow.addEventListener("keydown", (e) => {
|
|
121
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
handleTitleClick();
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
88
128
|
header.appendChild(titleRow);
|
|
89
129
|
|
|
90
130
|
// Close button
|
|
@@ -470,6 +470,8 @@ export const createStandardBubble = (
|
|
|
470
470
|
bubble.id = `bubble-${message.id}`;
|
|
471
471
|
bubble.setAttribute("data-message-id", message.id);
|
|
472
472
|
|
|
473
|
+
bubble.setAttribute("data-persona-theme-zone", message.role === "user" ? "user-message" : "assistant-message");
|
|
474
|
+
|
|
473
475
|
// Apply component-level color overrides via CSS variables
|
|
474
476
|
if (message.role === "user") {
|
|
475
477
|
bubble.style.backgroundColor = 'var(--persona-message-user-bg, var(--persona-accent))';
|
package/src/components/panel.ts
CHANGED
|
@@ -116,6 +116,7 @@ export const buildPanel = (config?: AgentWidgetConfig, showClose = true): PanelE
|
|
|
116
116
|
"div",
|
|
117
117
|
"persona-widget-container persona-flex persona-h-full persona-w-full persona-flex-1 persona-min-h-0 persona-flex-col persona-bg-persona-surface persona-text-persona-primary persona-rounded-2xl persona-overflow-hidden persona-border persona-border-persona-border"
|
|
118
118
|
);
|
|
119
|
+
container.setAttribute("data-persona-theme-zone", "container");
|
|
119
120
|
|
|
120
121
|
// Build header using layout config if available, otherwise use standard builder
|
|
121
122
|
const headerLayoutConfig = config?.layout?.header;
|
|
@@ -130,6 +131,7 @@ export const buildPanel = (config?: AgentWidgetConfig, showClose = true): PanelE
|
|
|
130
131
|
"persona-widget-body persona-flex persona-flex-1 persona-min-h-0 persona-flex-col persona-gap-6 persona-overflow-y-auto persona-bg-persona-container persona-px-6 persona-py-6"
|
|
131
132
|
);
|
|
132
133
|
body.id = "persona-scroll-container";
|
|
134
|
+
body.setAttribute("data-persona-theme-zone", "messages");
|
|
133
135
|
|
|
134
136
|
const introCard = createElement(
|
|
135
137
|
"div",
|
package/src/index.ts
CHANGED
|
@@ -189,8 +189,10 @@ export {
|
|
|
189
189
|
DEFAULT_PALETTE,
|
|
190
190
|
DEFAULT_SEMANTIC,
|
|
191
191
|
DEFAULT_COMPONENTS,
|
|
192
|
-
validateTheme
|
|
192
|
+
validateTheme,
|
|
193
|
+
THEME_ZONES
|
|
193
194
|
} from "./utils/tokens";
|
|
195
|
+
export type { ThemeZone } from "./utils/tokens";
|
|
194
196
|
export {
|
|
195
197
|
accessibilityPlugin,
|
|
196
198
|
animationsPlugin,
|
|
@@ -219,6 +221,9 @@ export type {
|
|
|
219
221
|
SemanticSpacing,
|
|
220
222
|
SemanticTypography,
|
|
221
223
|
ComponentTokens,
|
|
224
|
+
ArtifactToolbarTokens,
|
|
225
|
+
ArtifactTabTokens,
|
|
226
|
+
ArtifactPaneTokens,
|
|
222
227
|
ThemeValidationResult,
|
|
223
228
|
ThemeValidationError
|
|
224
229
|
} from "./types/theme";
|
|
@@ -245,6 +250,14 @@ export {
|
|
|
245
250
|
DEFAULT_DARK_THEME,
|
|
246
251
|
mergeWithDefaults
|
|
247
252
|
} from "./defaults";
|
|
253
|
+
export {
|
|
254
|
+
PRESETS,
|
|
255
|
+
getPreset,
|
|
256
|
+
PRESET_SHOP,
|
|
257
|
+
PRESET_MINIMAL,
|
|
258
|
+
PRESET_FULLSCREEN
|
|
259
|
+
} from "./presets";
|
|
260
|
+
export type { WidgetPreset } from "./presets";
|
|
248
261
|
|
|
249
262
|
// Layout system exports
|
|
250
263
|
export {
|
package/src/presets.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { AgentWidgetConfig } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A named preset containing partial widget configuration.
|
|
5
|
+
* Apply with: `createAgentExperience(el, { ...PRESET_SHOP.config, apiUrl: '...' })`
|
|
6
|
+
* or via IIFE: `{ ...AgentWidget.PRESETS.shop.config, apiUrl: '...' }`
|
|
7
|
+
*/
|
|
8
|
+
export interface WidgetPreset {
|
|
9
|
+
id: string;
|
|
10
|
+
label: string;
|
|
11
|
+
config: Partial<AgentWidgetConfig>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Shopping / e-commerce preset.
|
|
16
|
+
* Dark header, rounded launchers, shopping-oriented copy.
|
|
17
|
+
*/
|
|
18
|
+
export const PRESET_SHOP: WidgetPreset = {
|
|
19
|
+
id: 'shop',
|
|
20
|
+
label: 'Shopping Assistant',
|
|
21
|
+
config: {
|
|
22
|
+
theme: {
|
|
23
|
+
primary: '#111827',
|
|
24
|
+
accent: '#1d4ed8',
|
|
25
|
+
surface: '#ffffff',
|
|
26
|
+
muted: '#6b7280',
|
|
27
|
+
container: '#f8fafc',
|
|
28
|
+
border: '#f1f5f9',
|
|
29
|
+
divider: '#f1f5f9',
|
|
30
|
+
messageBorder: '#f1f5f9',
|
|
31
|
+
inputBackground: '#ffffff',
|
|
32
|
+
callToAction: '#000000',
|
|
33
|
+
callToActionBackground: '#ffffff',
|
|
34
|
+
sendButtonBackgroundColor: '#111827',
|
|
35
|
+
sendButtonTextColor: '#ffffff',
|
|
36
|
+
radiusSm: '0.75rem',
|
|
37
|
+
radiusMd: '1rem',
|
|
38
|
+
radiusLg: '1.5rem',
|
|
39
|
+
launcherRadius: '9999px',
|
|
40
|
+
buttonRadius: '9999px',
|
|
41
|
+
},
|
|
42
|
+
launcher: {
|
|
43
|
+
title: 'Shopping Assistant',
|
|
44
|
+
subtitle: 'Here to help you find what you need',
|
|
45
|
+
agentIconText: '🛍️',
|
|
46
|
+
position: 'bottom-right',
|
|
47
|
+
width: 'min(400px, calc(100vw - 24px))',
|
|
48
|
+
},
|
|
49
|
+
copy: {
|
|
50
|
+
welcomeTitle: 'Welcome to our shop!',
|
|
51
|
+
welcomeSubtitle: 'I can help you find products and answer questions',
|
|
52
|
+
inputPlaceholder: 'Ask me anything...',
|
|
53
|
+
sendButtonLabel: 'Send',
|
|
54
|
+
},
|
|
55
|
+
suggestionChips: [
|
|
56
|
+
'What can you help me with?',
|
|
57
|
+
'Tell me about your features',
|
|
58
|
+
'How does this work?',
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Minimal preset.
|
|
65
|
+
* Stripped-down header, no launcher button, suitable for inline embeds.
|
|
66
|
+
*/
|
|
67
|
+
export const PRESET_MINIMAL: WidgetPreset = {
|
|
68
|
+
id: 'minimal',
|
|
69
|
+
label: 'Minimal',
|
|
70
|
+
config: {
|
|
71
|
+
launcher: {
|
|
72
|
+
enabled: false,
|
|
73
|
+
fullHeight: true,
|
|
74
|
+
},
|
|
75
|
+
layout: {
|
|
76
|
+
header: {
|
|
77
|
+
layout: 'minimal',
|
|
78
|
+
showCloseButton: false,
|
|
79
|
+
},
|
|
80
|
+
messages: {
|
|
81
|
+
layout: 'minimal',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
theme: {
|
|
85
|
+
panelBorderRadius: '0',
|
|
86
|
+
panelShadow: 'none',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Fullscreen assistant preset.
|
|
93
|
+
* No launcher, content-max-width constrained, minimal header.
|
|
94
|
+
*/
|
|
95
|
+
export const PRESET_FULLSCREEN: WidgetPreset = {
|
|
96
|
+
id: 'fullscreen',
|
|
97
|
+
label: 'Fullscreen Assistant',
|
|
98
|
+
config: {
|
|
99
|
+
launcher: {
|
|
100
|
+
enabled: false,
|
|
101
|
+
fullHeight: true,
|
|
102
|
+
},
|
|
103
|
+
layout: {
|
|
104
|
+
header: {
|
|
105
|
+
layout: 'minimal',
|
|
106
|
+
showCloseButton: false,
|
|
107
|
+
},
|
|
108
|
+
contentMaxWidth: '72ch',
|
|
109
|
+
},
|
|
110
|
+
theme: {
|
|
111
|
+
panelBorderRadius: '0',
|
|
112
|
+
panelShadow: 'none',
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/** All named presets keyed by ID. */
|
|
118
|
+
export const PRESETS: Record<string, WidgetPreset> = {
|
|
119
|
+
shop: PRESET_SHOP,
|
|
120
|
+
minimal: PRESET_MINIMAL,
|
|
121
|
+
fullscreen: PRESET_FULLSCREEN,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/** Look up a preset by ID. */
|
|
125
|
+
export function getPreset(id: string): WidgetPreset | undefined {
|
|
126
|
+
return PRESETS[id];
|
|
127
|
+
}
|
package/src/styles/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);
|
|
@@ -2051,9 +2064,9 @@
|
|
|
2051
2064
|
display: inline-flex;
|
|
2052
2065
|
align-items: center;
|
|
2053
2066
|
justify-content: center;
|
|
2054
|
-
padding: 0.25rem;
|
|
2055
|
-
border-radius: var(--persona-radius-md, 0.375rem);
|
|
2056
|
-
border: 1px solid var(--persona-border, #e5e7eb);
|
|
2067
|
+
padding: var(--persona-artifact-toolbar-icon-padding, 0.25rem);
|
|
2068
|
+
border-radius: var(--persona-artifact-toolbar-icon-radius, var(--persona-radius-md, 0.375rem));
|
|
2069
|
+
border: var(--persona-artifact-toolbar-icon-border, 1px solid var(--persona-border, #e5e7eb));
|
|
2057
2070
|
background: var(--persona-surface, #ffffff);
|
|
2058
2071
|
color: var(--persona-artifact-doc-toolbar-icon-color, var(--persona-text, #111827));
|
|
2059
2072
|
cursor: pointer;
|
|
@@ -2061,7 +2074,8 @@
|
|
|
2061
2074
|
}
|
|
2062
2075
|
|
|
2063
2076
|
#persona-root .persona-artifact-toolbar-document .persona-artifact-doc-icon-btn:hover {
|
|
2064
|
-
|
|
2077
|
+
color: var(--persona-artifact-toolbar-icon-hover-color, inherit);
|
|
2078
|
+
background: var(--persona-artifact-toolbar-icon-hover-bg, var(--persona-container, #f3f4f6));
|
|
2065
2079
|
}
|
|
2066
2080
|
|
|
2067
2081
|
#persona-root .persona-artifact-toolbar-document .persona-artifact-doc-icon-btn[aria-pressed="true"] {
|
|
@@ -2073,24 +2087,53 @@
|
|
|
2073
2087
|
display: inline-flex;
|
|
2074
2088
|
align-items: center;
|
|
2075
2089
|
gap: 0.35rem;
|
|
2076
|
-
padding: 0.25rem 0.5rem;
|
|
2077
|
-
border-radius: var(--persona-radius-md, 0.375rem);
|
|
2078
|
-
border: 1px solid var(--persona-border, #e5e7eb);
|
|
2079
|
-
background: var(--persona-surface, #ffffff);
|
|
2080
|
-
color: var(--persona-artifact-doc-toolbar-icon-color, var(--persona-text, #111827));
|
|
2090
|
+
padding: var(--persona-artifact-toolbar-copy-padding, 0.25rem 0.5rem);
|
|
2091
|
+
border-radius: var(--persona-artifact-toolbar-copy-radius, var(--persona-radius-md, 0.375rem));
|
|
2092
|
+
border: var(--persona-artifact-toolbar-copy-border, 1px solid var(--persona-border, #e5e7eb));
|
|
2093
|
+
background: var(--persona-artifact-toolbar-copy-bg, var(--persona-surface, #ffffff));
|
|
2094
|
+
color: var(--persona-artifact-toolbar-copy-color, var(--persona-artifact-doc-toolbar-icon-color, var(--persona-text, #111827)));
|
|
2081
2095
|
cursor: pointer;
|
|
2082
2096
|
font-size: 0.75rem;
|
|
2083
2097
|
line-height: 1.25;
|
|
2084
2098
|
}
|
|
2085
2099
|
|
|
2086
2100
|
#persona-root .persona-artifact-toolbar-document .persona-artifact-doc-copy-btn:hover {
|
|
2087
|
-
background: var(--persona-container, #f3f4f6);
|
|
2101
|
+
background: var(--persona-artifact-toolbar-icon-hover-bg, var(--persona-container, #f3f4f6));
|
|
2088
2102
|
}
|
|
2089
2103
|
|
|
2090
2104
|
#persona-root .persona-artifact-toolbar-document .persona-artifact-doc-copy-label {
|
|
2091
2105
|
font-weight: 500;
|
|
2092
2106
|
}
|
|
2093
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
|
+
/* Artifact tab theming */
|
|
2121
|
+
#persona-root .persona-artifact-tab {
|
|
2122
|
+
background: var(--persona-artifact-tab-bg, transparent);
|
|
2123
|
+
border-radius: var(--persona-artifact-tab-radius, 0.5rem);
|
|
2124
|
+
color: var(--persona-artifact-tab-color, inherit);
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
#persona-root .persona-artifact-tab.persona-bg-persona-container {
|
|
2128
|
+
background: var(--persona-artifact-tab-active-bg, var(--persona-container, #f3f4f6));
|
|
2129
|
+
border-color: var(--persona-artifact-tab-active-border, var(--persona-border, #e5e7eb));
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
/* Artifact toolbar background theming */
|
|
2133
|
+
#persona-root .persona-artifact-toolbar {
|
|
2134
|
+
background: var(--persona-artifact-toolbar-bg, var(--persona-surface, #fff));
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2094
2137
|
/* Draggable split handle (desktop split only; hidden in drawer / narrow host / small viewport) */
|
|
2095
2138
|
#persona-root .persona-artifact-split-handle {
|
|
2096
2139
|
width: 6px;
|
package/src/types/theme.ts
CHANGED
|
@@ -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,58 @@ 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
|
+
|
|
301
|
+
/** Artifact toolbar chrome. */
|
|
302
|
+
export interface ArtifactToolbarTokens {
|
|
303
|
+
iconHoverColor?: string;
|
|
304
|
+
iconHoverBackground?: string;
|
|
305
|
+
iconPadding?: string;
|
|
306
|
+
iconBorderRadius?: string;
|
|
307
|
+
iconBorder?: string;
|
|
308
|
+
toggleGroupGap?: string;
|
|
309
|
+
toggleBorderRadius?: string;
|
|
310
|
+
copyBackground?: string;
|
|
311
|
+
copyBorder?: string;
|
|
312
|
+
copyColor?: string;
|
|
313
|
+
copyBorderRadius?: string;
|
|
314
|
+
copyPadding?: string;
|
|
315
|
+
copyMenuBackground?: string;
|
|
316
|
+
copyMenuBorder?: string;
|
|
317
|
+
copyMenuShadow?: string;
|
|
318
|
+
copyMenuBorderRadius?: string;
|
|
319
|
+
copyMenuItemHoverBackground?: string;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Artifact tab strip chrome. */
|
|
323
|
+
export interface ArtifactTabTokens {
|
|
324
|
+
background?: string;
|
|
325
|
+
activeBackground?: string;
|
|
326
|
+
activeBorder?: string;
|
|
327
|
+
borderRadius?: string;
|
|
328
|
+
textColor?: string;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** Artifact pane chrome. */
|
|
332
|
+
export interface ArtifactPaneTokens {
|
|
333
|
+
toolbarBackground?: string;
|
|
334
|
+
}
|
|
335
|
+
|
|
282
336
|
export interface ComponentTokens {
|
|
283
337
|
button: ButtonTokens;
|
|
284
338
|
input: InputTokens;
|
|
@@ -291,6 +345,15 @@ export interface ComponentTokens {
|
|
|
291
345
|
voice: VoiceTokens;
|
|
292
346
|
approval: ApprovalTokens;
|
|
293
347
|
attachment: AttachmentTokens;
|
|
348
|
+
toolBubble: ToolBubbleTokens;
|
|
349
|
+
reasoningBubble: ReasoningBubbleTokens;
|
|
350
|
+
composer: ComposerChromeTokens;
|
|
351
|
+
/** Artifact toolbar, tab strip, and pane chrome. */
|
|
352
|
+
artifact?: {
|
|
353
|
+
toolbar?: ArtifactToolbarTokens;
|
|
354
|
+
tab?: ArtifactTabTokens;
|
|
355
|
+
pane?: ArtifactPaneTokens;
|
|
356
|
+
};
|
|
294
357
|
}
|
|
295
358
|
|
|
296
359
|
export interface PaletteExtras {
|
package/src/types.ts
CHANGED
|
@@ -525,6 +525,14 @@ export type AgentWidgetArtifactsFeature = {
|
|
|
525
525
|
allowedTypes?: PersonaArtifactKind[];
|
|
526
526
|
/** Split / drawer dimensions and launcher widen behavior */
|
|
527
527
|
layout?: AgentWidgetArtifactsLayoutConfig;
|
|
528
|
+
/**
|
|
529
|
+
* Called when an artifact card action is triggered (open, download).
|
|
530
|
+
* Return `true` to prevent the default behavior.
|
|
531
|
+
*/
|
|
532
|
+
onArtifactAction?: (action: {
|
|
533
|
+
type: 'open' | 'download';
|
|
534
|
+
artifactId: string;
|
|
535
|
+
}) => boolean | void;
|
|
528
536
|
};
|
|
529
537
|
|
|
530
538
|
export type AgentWidgetFeatureFlags = {
|
|
@@ -714,6 +722,28 @@ export type AgentWidgetTheme = {
|
|
|
714
722
|
* @default "16px"
|
|
715
723
|
*/
|
|
716
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;
|
|
717
747
|
};
|
|
718
748
|
|
|
719
749
|
export type AgentWidgetDockConfig = {
|
|
@@ -1141,6 +1171,8 @@ export type AgentWidgetApprovalConfig = {
|
|
|
1141
1171
|
};
|
|
1142
1172
|
|
|
1143
1173
|
export type AgentWidgetToolCallConfig = {
|
|
1174
|
+
/** Box-shadow for tool-call bubbles; overrides `theme.toolBubbleShadow` when set. */
|
|
1175
|
+
shadow?: string;
|
|
1144
1176
|
backgroundColor?: string;
|
|
1145
1177
|
borderColor?: string;
|
|
1146
1178
|
borderWidth?: string;
|
|
@@ -1428,6 +1460,12 @@ export type AgentWidgetHeaderLayoutConfig = {
|
|
|
1428
1460
|
trailingActions?: AgentWidgetHeaderTrailingAction[];
|
|
1429
1461
|
/** Called when a `trailingActions` button is clicked. */
|
|
1430
1462
|
onAction?: (actionId: string) => void;
|
|
1463
|
+
/**
|
|
1464
|
+
* Called when the header title row is clicked.
|
|
1465
|
+
* Useful for dropdown menus or navigation triggered from the header.
|
|
1466
|
+
* When set, the title row becomes visually interactive (cursor: pointer).
|
|
1467
|
+
*/
|
|
1468
|
+
onTitleClick?: () => void;
|
|
1431
1469
|
};
|
|
1432
1470
|
|
|
1433
1471
|
/**
|