@runtypelabs/persona 4.14.0 → 4.15.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/README.md +4 -4
- package/dist/animations/glyph-cycle.d.cts +1 -1
- package/dist/animations/glyph-cycle.d.ts +1 -1
- package/dist/animations/{types-DveIaNx6.d.cts → types-BpWGm7_6.d.cts} +17 -0
- package/dist/animations/{types-DveIaNx6.d.ts → types-BpWGm7_6.d.ts} +17 -0
- package/dist/animations/wipe.d.cts +1 -1
- package/dist/animations/wipe.d.ts +1 -1
- package/dist/chunk-QJ4LV2KW.js +1 -0
- package/dist/codegen.cjs +12 -11
- package/dist/codegen.js +14 -13
- package/dist/{context-mentions-ONG7A7M6.js → context-mentions-BTSTIBFC.js} +1 -1
- package/dist/context-mentions.cjs +11 -8
- package/dist/context-mentions.d.cts +241 -16
- package/dist/context-mentions.d.ts +241 -16
- package/dist/context-mentions.js +11 -8
- package/dist/index.cjs +67 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +301 -41
- package/dist/index.d.ts +301 -41
- package/dist/index.global.js +59 -56
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +67 -66
- package/dist/index.js.map +1 -1
- package/dist/launcher.global.js +5 -2
- package/dist/launcher.global.js.map +1 -1
- package/dist/smart-dom-reader.d.cts +241 -16
- package/dist/smart-dom-reader.d.ts +241 -16
- package/dist/theme-editor-preview.cjs +66 -66
- package/dist/theme-editor-preview.d.cts +255 -17
- package/dist/theme-editor-preview.d.ts +255 -17
- package/dist/theme-editor-preview.js +56 -56
- package/dist/theme-editor.cjs +5 -5
- package/dist/theme-editor.d.cts +242 -17
- package/dist/theme-editor.d.ts +242 -17
- package/dist/theme-editor.js +7 -7
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +38 -0
- package/dist/theme-reference.d.ts +38 -0
- package/dist/theme-reference.js +1 -1
- package/dist/widget.css +1 -1
- package/package.json +1 -1
- package/src/ask-user-question-tool.ts +10 -7
- package/src/components/artifact-preview.ts +1 -1
- package/src/components/composer-parts.test.ts +103 -4
- package/src/components/composer-parts.ts +53 -15
- package/src/components/messages.ts +5 -2
- package/src/components/panel.ts +31 -5
- package/src/components/pill-composer-builder.test.ts +18 -0
- package/src/components/suggestions.test.ts +233 -0
- package/src/components/suggestions.ts +463 -81
- package/src/components/widget-view.ts +4 -0
- package/src/defaults.ts +5 -3
- package/src/generated/runtype-openapi-contract.ts +17 -0
- package/src/index-core.ts +18 -2
- package/src/launcher-global.ts +1 -1
- package/src/plugins/types.ts +71 -3
- package/src/presets.ts +3 -3
- package/src/session.ts +10 -8
- package/src/styles/widget-styles.test.ts +162 -0
- package/src/styles/widget.css +430 -0
- package/src/suggest-replies-tool.test.ts +233 -2
- package/src/suggest-replies-tool.ts +115 -39
- package/src/theme-editor/preview-utils.test.ts +34 -0
- package/src/theme-editor/preview-utils.ts +77 -2
- package/src/theme-editor/sections.test.ts +33 -0
- package/src/theme-editor/sections.ts +53 -5
- package/src/theme-reference.ts +9 -2
- package/src/types/theme.ts +32 -0
- package/src/types.ts +152 -16
- package/src/ui.detached-panel.test.ts +1 -1
- package/src/ui.suggest-replies.test.ts +1066 -1
- package/src/ui.ts +268 -20
- package/src/utils/artifact-file.test.ts +1 -1
- package/src/utils/code-generators.test.ts +40 -0
- package/src/utils/code-generators.ts +22 -0
- package/src/utils/config-merge.test.ts +24 -0
- package/src/utils/icons.test.ts +26 -0
- package/src/utils/icons.ts +8 -0
- package/src/utils/theme.test.ts +79 -0
- package/src/utils/tokens.ts +64 -0
- package/dist/chunk-MMUPR2JW.js +0 -1
package/src/index-core.ts
CHANGED
|
@@ -140,7 +140,18 @@ export type {
|
|
|
140
140
|
AskUserQuestionPrompt,
|
|
141
141
|
AskUserQuestionOption,
|
|
142
142
|
AgentWidgetAskUserQuestionFeature,
|
|
143
|
-
AgentWidgetAskUserQuestionStyles
|
|
143
|
+
AgentWidgetAskUserQuestionStyles,
|
|
144
|
+
AgentWidgetSuggestion,
|
|
145
|
+
AgentWidgetSuggestionChipsConfig,
|
|
146
|
+
AgentWidgetResolvedSuggestion,
|
|
147
|
+
AgentWidgetSuggestionBehavior,
|
|
148
|
+
AgentWidgetSuggestionVariant,
|
|
149
|
+
AgentWidgetSuggestionSurface,
|
|
150
|
+
AgentWidgetSuggestionSource,
|
|
151
|
+
AgentWidgetSuggestionSurfaceConfig,
|
|
152
|
+
AgentWidgetStarterSuggestionsConfig,
|
|
153
|
+
AgentWidgetFollowUpSuggestionsConfig,
|
|
154
|
+
AgentWidgetSuggestionsConfig
|
|
144
155
|
} from "./types";
|
|
145
156
|
|
|
146
157
|
export {
|
|
@@ -326,7 +337,12 @@ export { VERSION } from "./version";
|
|
|
326
337
|
export type { AgentWidgetInitHandle };
|
|
327
338
|
|
|
328
339
|
// Plugin system exports
|
|
329
|
-
export type {
|
|
340
|
+
export type {
|
|
341
|
+
AgentWidgetPlugin,
|
|
342
|
+
AgentWidgetTransformSuggestionsContext,
|
|
343
|
+
AgentWidgetRenderSuggestionContext,
|
|
344
|
+
AgentWidgetSuggestionSelectContext
|
|
345
|
+
} from "./plugins/types";
|
|
330
346
|
export { pluginRegistry } from "./plugins/registry";
|
|
331
347
|
|
|
332
348
|
// Stream animation plugin API: lets consumers register custom animations
|
package/src/launcher-global.ts
CHANGED
|
@@ -76,7 +76,7 @@ const mergeCriticalLauncherConfig = (
|
|
|
76
76
|
* Mirrors the full widget's DOM exactly (`runtime/init.ts` + `ui.ts`): a
|
|
77
77
|
* `[data-persona-root]` wrapper carries the theme CSS variables and the launcher
|
|
78
78
|
* button is its child. Keeping the theme vars on the wrapper (not the button)
|
|
79
|
-
* leaves the button's own inline style
|
|
79
|
+
* leaves the button's own inline style matching the full widget's, so
|
|
80
80
|
* the eventual mount-then-remove handoff is invisible.
|
|
81
81
|
*/
|
|
82
82
|
export const mount = (
|
package/src/plugins/types.ts
CHANGED
|
@@ -8,9 +8,51 @@ import {
|
|
|
8
8
|
EventStreamViewRenderContext,
|
|
9
9
|
EventStreamRowRenderContext,
|
|
10
10
|
EventStreamToolbarRenderContext,
|
|
11
|
-
EventStreamPayloadRenderContext
|
|
11
|
+
EventStreamPayloadRenderContext,
|
|
12
|
+
AgentWidgetSuggestion,
|
|
13
|
+
AgentWidgetResolvedSuggestion,
|
|
14
|
+
AgentWidgetSuggestionSource,
|
|
15
|
+
AgentWidgetSuggestionSurface,
|
|
16
|
+
AgentWidgetSuggestionVariant
|
|
12
17
|
} from "../types";
|
|
13
18
|
|
|
19
|
+
export type AgentWidgetTransformSuggestionsContext = {
|
|
20
|
+
/**
|
|
21
|
+
* Fresh copy of the suggestions entering this plugin, already normalized:
|
|
22
|
+
* shorthand strings expanded and the effective send/fill behavior resolved.
|
|
23
|
+
*/
|
|
24
|
+
suggestions: AgentWidgetResolvedSuggestion[];
|
|
25
|
+
surface: AgentWidgetSuggestionSurface;
|
|
26
|
+
source: AgentWidgetSuggestionSource;
|
|
27
|
+
config: AgentWidgetConfig;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type AgentWidgetRenderSuggestionContext = {
|
|
31
|
+
/** Fully normalized suggestion, including the effective send/fill behavior. */
|
|
32
|
+
suggestion: AgentWidgetResolvedSuggestion;
|
|
33
|
+
index: number;
|
|
34
|
+
surface: AgentWidgetSuggestionSurface;
|
|
35
|
+
source: AgentWidgetSuggestionSource;
|
|
36
|
+
variant: AgentWidgetSuggestionVariant;
|
|
37
|
+
streaming: boolean;
|
|
38
|
+
config: AgentWidgetConfig;
|
|
39
|
+
/** Build Persona's standard chip, card, or list item. */
|
|
40
|
+
defaultRenderer: () => HTMLElement;
|
|
41
|
+
/**
|
|
42
|
+
* Run the normal selection pipeline: DOM event, plugin selection hooks, then
|
|
43
|
+
* send or fill. Custom renderers should call this instead of sending directly.
|
|
44
|
+
*/
|
|
45
|
+
select: () => void;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type AgentWidgetSuggestionSelectContext = {
|
|
49
|
+
suggestion: AgentWidgetResolvedSuggestion;
|
|
50
|
+
surface: AgentWidgetSuggestionSurface;
|
|
51
|
+
source: AgentWidgetSuggestionSource;
|
|
52
|
+
variant: AgentWidgetSuggestionVariant;
|
|
53
|
+
config: AgentWidgetConfig;
|
|
54
|
+
};
|
|
55
|
+
|
|
14
56
|
/**
|
|
15
57
|
* Plugin interface for customizing widget components
|
|
16
58
|
*/
|
|
@@ -25,6 +67,34 @@ export interface AgentWidgetPlugin {
|
|
|
25
67
|
*/
|
|
26
68
|
priority?: number;
|
|
27
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Transform, filter, enrich, or reorder suggestions. Hooks receive normalized
|
|
72
|
+
* items and compose in plugin priority order; the return value may use the
|
|
73
|
+
* loose shape (string shorthand included) and is re-normalized before the next
|
|
74
|
+
* hook. A per-item `behavior` set here survives. `maxItems` caps the list
|
|
75
|
+
* after the full chain. Return an empty array to hide the surface.
|
|
76
|
+
*/
|
|
77
|
+
transformSuggestions?: (
|
|
78
|
+
context: AgentWidgetTransformSuggestionsContext
|
|
79
|
+
) => AgentWidgetSuggestion[];
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Render one starter or follow-up suggestion. Return null to use Persona's
|
|
83
|
+
* default chip/card/list renderer. Call `select()` from custom interaction
|
|
84
|
+
* controls to preserve events, selection hooks, and send/fill behavior.
|
|
85
|
+
*/
|
|
86
|
+
renderSuggestion?: (
|
|
87
|
+
context: AgentWidgetRenderSuggestionContext
|
|
88
|
+
) => HTMLElement | null;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Observe or intercept a suggestion selection. Return false to cancel the
|
|
92
|
+
* built-in send/fill action. Hooks run in plugin priority order.
|
|
93
|
+
*/
|
|
94
|
+
onSuggestionSelect?: (
|
|
95
|
+
context: AgentWidgetSuggestionSelectContext
|
|
96
|
+
) => void | boolean;
|
|
97
|
+
|
|
28
98
|
/**
|
|
29
99
|
* Custom renderer for message bubbles
|
|
30
100
|
* Return null to use default renderer
|
|
@@ -298,5 +368,3 @@ export interface AgentWidgetPlugin {
|
|
|
298
368
|
|
|
299
369
|
|
|
300
370
|
|
|
301
|
-
|
|
302
|
-
|
package/src/presets.ts
CHANGED
|
@@ -75,9 +75,9 @@ export const PRESET_SHOP: WidgetPreset = {
|
|
|
75
75
|
sendButtonLabel: "Send",
|
|
76
76
|
},
|
|
77
77
|
suggestionChips: [
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
78
|
+
"Show me what you can help with",
|
|
79
|
+
"Walk me through getting started",
|
|
80
|
+
"Answer a question about this page",
|
|
81
81
|
],
|
|
82
82
|
},
|
|
83
83
|
};
|
package/src/session.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { AgentWidgetClient, type SSEEventCallback } from "./client";
|
|
|
2
2
|
import { isWebMcpToolName } from "./webmcp-bridge";
|
|
3
3
|
import {
|
|
4
4
|
SUGGEST_REPLIES_TOOL_NAME,
|
|
5
|
+
resolveFollowUpsFeature,
|
|
5
6
|
suggestRepliesToolResult,
|
|
6
7
|
} from "./suggest-replies-tool";
|
|
7
8
|
import {
|
|
@@ -77,10 +78,11 @@ export type AgentWidgetSessionStatus =
|
|
|
77
78
|
* request. When NONE of these change, `updateConfig` can refresh the live
|
|
78
79
|
* client in place (preserving the WebMCP bridge and any in-flight stream/resume)
|
|
79
80
|
* instead of swapping in a fresh client and tearing down WebMCP state. Fields
|
|
80
|
-
* outside this list (theme, copy, layout,
|
|
81
|
-
* postprocessMessage, feature display toggles, …) are
|
|
82
|
-
* apply mid-turn: which is what a self-styling widget
|
|
83
|
-
* theme tool re-renders the widget while the agent's
|
|
81
|
+
* outside this list (theme, copy, layout, suggestions, suggestionChips,
|
|
82
|
+
* iterationDisplay, postprocessMessage, feature display toggles, …) are
|
|
83
|
+
* display-only and safe to apply mid-turn: which is what a self-styling widget
|
|
84
|
+
* needs when a `webmcp:*` theme tool re-renders the widget while the agent's
|
|
85
|
+
* turn is still streaming.
|
|
84
86
|
*
|
|
85
87
|
* Compared by identity (`!==`): primitives by value, functions/objects by
|
|
86
88
|
* reference. A consumer that rebuilds these objects on every render simply
|
|
@@ -2983,15 +2985,15 @@ export class AgentWidgetSession {
|
|
|
2983
2985
|
// indefinitely: `resolveWebMcpToolCall` translates the missing-bridge
|
|
2984
2986
|
// case into an isError result that resumes the flow cleanly.
|
|
2985
2987
|
// `suggest_replies`, by contrast, is gated on its feature flag: when
|
|
2986
|
-
// `
|
|
2987
|
-
//
|
|
2988
|
-
//
|
|
2988
|
+
// the resolved `enabled` is false the widget neither renders chips nor
|
|
2989
|
+
// resumes: the same parked-execution posture as a server-declared
|
|
2990
|
+
// ask_user_question with its sheet disabled.
|
|
2989
2991
|
const tc = event.message.toolCall;
|
|
2990
2992
|
const autoResolvable =
|
|
2991
2993
|
!!tc?.name &&
|
|
2992
2994
|
(isWebMcpToolName(tc.name) ||
|
|
2993
2995
|
(tc.name === SUGGEST_REPLIES_TOOL_NAME &&
|
|
2994
|
-
this.config.
|
|
2996
|
+
resolveFollowUpsFeature(this.config).enabled));
|
|
2995
2997
|
if (
|
|
2996
2998
|
event.message.agentMetadata?.awaitingLocalTool === true &&
|
|
2997
2999
|
autoResolvable
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
|
|
5
|
+
const widgetCss = readFileSync(
|
|
6
|
+
new URL("./widget.css", import.meta.url),
|
|
7
|
+
"utf8",
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
describe("suggestion interaction styles", () => {
|
|
11
|
+
it("keeps suggestion surfaces from collapsing inside constrained transcripts", () => {
|
|
12
|
+
const selector = ".persona-suggestions {";
|
|
13
|
+
const start = widgetCss.indexOf(selector);
|
|
14
|
+
const end = widgetCss.indexOf("\n}", start);
|
|
15
|
+
const surfaceRule = widgetCss.slice(start, end);
|
|
16
|
+
|
|
17
|
+
expect(start).toBeGreaterThan(-1);
|
|
18
|
+
expect(surfaceRule).toContain("flex-shrink: 0");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("keeps the primary emphasis a quiet accent rather than a solid fill", () => {
|
|
22
|
+
const selector = '.persona-suggestion[data-emphasis="primary"] {';
|
|
23
|
+
const start = widgetCss.indexOf(selector);
|
|
24
|
+
const rule = widgetCss.slice(start, widgetCss.indexOf("\n}", start));
|
|
25
|
+
|
|
26
|
+
expect(start).toBeGreaterThan(-1);
|
|
27
|
+
expect(rule).toContain("border-color: var(--persona-primary)");
|
|
28
|
+
// Plain declaration first so engines without color-mix stay transparent.
|
|
29
|
+
expect(rule).toContain("background: transparent");
|
|
30
|
+
expect(rule).toContain(
|
|
31
|
+
"background: color-mix(in srgb, var(--persona-primary) 6%, transparent)",
|
|
32
|
+
);
|
|
33
|
+
expect(rule).not.toContain("--persona-text-inverse");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("strengthens the primary wash on hover instead of filling it", () => {
|
|
37
|
+
const selector =
|
|
38
|
+
'.persona-suggestion[data-emphasis="primary"]:hover {';
|
|
39
|
+
const start = widgetCss.indexOf(selector);
|
|
40
|
+
const hoverRule = widgetCss.slice(start, widgetCss.indexOf("\n }", start));
|
|
41
|
+
|
|
42
|
+
expect(start).toBeGreaterThan(-1);
|
|
43
|
+
expect(hoverRule).toContain("border-color: var(--persona-primary)");
|
|
44
|
+
expect(hoverRule).toContain(
|
|
45
|
+
"color-mix(in srgb, var(--persona-primary) 12%, transparent)",
|
|
46
|
+
);
|
|
47
|
+
expect(hoverRule).not.toContain("filter: brightness");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("rests cards flat and reserves the shadow plus lift for hover", () => {
|
|
51
|
+
const restStart = widgetCss.indexOf(".persona-suggestion--card {");
|
|
52
|
+
const restRule = widgetCss.slice(
|
|
53
|
+
restStart,
|
|
54
|
+
widgetCss.indexOf("\n}", restStart),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
expect(restStart).toBeGreaterThan(-1);
|
|
58
|
+
expect(restRule).toContain(
|
|
59
|
+
"box-shadow: var(--persona-components-suggestion-card-shadow, none)",
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const hoverStart = widgetCss.indexOf(".persona-suggestion--card:hover {");
|
|
63
|
+
const hoverRule = widgetCss.slice(
|
|
64
|
+
hoverStart,
|
|
65
|
+
widgetCss.indexOf("\n }", hoverStart),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(hoverStart).toBeGreaterThan(-1);
|
|
69
|
+
expect(hoverRule).toContain("box-shadow: var(--persona-shadow-sm)");
|
|
70
|
+
expect(hoverRule).toContain("transform: translateY(-1px)");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("reveals the suggestion arrow only on hover and keyboard focus", () => {
|
|
74
|
+
// Searched past `__copy`: the bare selector also appears in the shared
|
|
75
|
+
// `flex: 0 0 auto` group above it and the coarse-pointer override below.
|
|
76
|
+
const restStart = widgetCss.indexOf(
|
|
77
|
+
".persona-suggestion__arrow {",
|
|
78
|
+
widgetCss.indexOf(".persona-suggestion__copy {"),
|
|
79
|
+
);
|
|
80
|
+
const restRule = widgetCss.slice(
|
|
81
|
+
restStart,
|
|
82
|
+
widgetCss.indexOf("\n}", restStart),
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(restStart).toBeGreaterThan(-1);
|
|
86
|
+
expect(restRule).toContain("opacity: 0;");
|
|
87
|
+
expect(restRule).toContain("transition: opacity");
|
|
88
|
+
expect(widgetCss).toContain(
|
|
89
|
+
".persona-suggestion:focus-visible .persona-suggestion__arrow",
|
|
90
|
+
);
|
|
91
|
+
expect(widgetCss).toContain(
|
|
92
|
+
".persona-suggestion:hover .persona-suggestion__arrow",
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("caps the starter card grid so wide panels get two columns", () => {
|
|
97
|
+
expect(widgetCss).toContain(
|
|
98
|
+
"grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr))",
|
|
99
|
+
);
|
|
100
|
+
const selector =
|
|
101
|
+
'.persona-suggestions[data-variant="card"][data-persona-suggestion-surface="starter"] {';
|
|
102
|
+
const start = widgetCss.indexOf(selector);
|
|
103
|
+
const rule = widgetCss.slice(start, widgetCss.indexOf("\n}", start));
|
|
104
|
+
|
|
105
|
+
expect(start).toBeGreaterThan(-1);
|
|
106
|
+
expect(rule).toContain("max-width: 600px");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("masks only the scrollable chip edges that still contain content", () => {
|
|
110
|
+
expect(widgetCss).toContain(
|
|
111
|
+
'[data-overflow="scroll"][data-scroll-right]:not(',
|
|
112
|
+
);
|
|
113
|
+
expect(widgetCss).toContain(
|
|
114
|
+
'[data-overflow="scroll"][data-scroll-left]:not(',
|
|
115
|
+
);
|
|
116
|
+
expect(widgetCss).toContain(
|
|
117
|
+
'[data-overflow="scroll"][data-scroll-left][data-scroll-right]',
|
|
118
|
+
);
|
|
119
|
+
expect(widgetCss).toContain(
|
|
120
|
+
"--persona-suggestion-scroll-fade-size: 32px",
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe("composer spacing styles", () => {
|
|
126
|
+
it("themes the composer form padding and gap with utility-matching fallbacks", () => {
|
|
127
|
+
const selector =
|
|
128
|
+
"[data-persona-root] .persona-widget-composer:not(.persona-pill-composer) {";
|
|
129
|
+
const start = widgetCss.indexOf(selector);
|
|
130
|
+
const rule = widgetCss.slice(start, widgetCss.indexOf("\n}", start));
|
|
131
|
+
|
|
132
|
+
expect(start).toBeGreaterThan(-1);
|
|
133
|
+
// Fallbacks reproduce `persona-px-4 persona-py-3` and `persona-gap-2`.
|
|
134
|
+
expect(rule).toContain(
|
|
135
|
+
"padding: var(--persona-composer-padding, 0.75rem 1rem)",
|
|
136
|
+
);
|
|
137
|
+
expect(rule).toContain("gap: var(--persona-composer-gap, 0.5rem)");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("themes the composer textarea type with text-sm fallbacks", () => {
|
|
141
|
+
const selector = "[data-persona-root] .persona-composer-textarea {";
|
|
142
|
+
const start = widgetCss.indexOf(selector);
|
|
143
|
+
const rule = widgetCss.slice(start, widgetCss.indexOf("\n}", start));
|
|
144
|
+
|
|
145
|
+
expect(start).toBeGreaterThan(-1);
|
|
146
|
+
expect(rule).toContain(
|
|
147
|
+
"font-size: var(--persona-composer-font-size, 0.875rem)",
|
|
148
|
+
);
|
|
149
|
+
expect(rule).toContain(
|
|
150
|
+
"line-height: var(--persona-composer-line-height, 1.25rem)",
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("leaves the pill composer on its own single-row geometry", () => {
|
|
155
|
+
const start = widgetCss.indexOf(".persona-pill-composer {");
|
|
156
|
+
const rule = widgetCss.slice(start, widgetCss.indexOf("\n}", start));
|
|
157
|
+
|
|
158
|
+
expect(start).toBeGreaterThan(-1);
|
|
159
|
+
expect(rule).toContain("padding: 6px 14px");
|
|
160
|
+
expect(rule).toContain("gap: 8px");
|
|
161
|
+
});
|
|
162
|
+
});
|