@runtypelabs/persona 4.13.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 +339 -22
- package/dist/context-mentions.d.ts +339 -22
- package/dist/context-mentions.js +11 -8
- package/dist/index.cjs +68 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +483 -48
- package/dist/index.d.ts +483 -48
- package/dist/index.global.js +61 -58
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +70 -69
- 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 +339 -22
- package/dist/smart-dom-reader.d.ts +339 -22
- package/dist/theme-editor-preview.cjs +67 -67
- package/dist/theme-editor-preview.d.cts +355 -23
- package/dist/theme-editor-preview.d.ts +355 -23
- package/dist/theme-editor-preview.js +75 -75
- package/dist/theme-editor.cjs +10 -10
- package/dist/theme-editor.d.cts +376 -24
- package/dist/theme-editor.d.ts +376 -24
- package/dist/theme-editor.js +10 -10
- 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/artifacts-session.test.ts +106 -0
- package/src/ask-user-question-tool.ts +10 -7
- package/src/client.test.ts +2 -2
- package/src/client.ts +4 -1
- package/src/components/artifact-card.ts +13 -2
- package/src/components/artifact-inline.ts +11 -2
- package/src/components/artifact-preview.ts +1 -1
- package/src/components/composer-builder.test.ts +2 -0
- package/src/components/composer-builder.ts +1 -1
- package/src/components/composer-parts.test.ts +105 -4
- package/src/components/composer-parts.ts +54 -16
- package/src/components/message-bubble.test.ts +7 -1
- package/src/components/message-bubble.ts +11 -8
- 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 +52 -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 +55 -12
- package/src/styles/widget-styles.test.ts +162 -0
- package/src/styles/widget.css +440 -1
- package/src/suggest-replies-tool.test.ts +233 -2
- package/src/suggest-replies-tool.ts +115 -39
- package/src/theme-editor/index.ts +5 -0
- package/src/theme-editor/presets.test.ts +43 -0
- package/src/theme-editor/presets.ts +101 -87
- 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 +72 -7
- package/src/theme-editor/sections.ts +113 -13
- package/src/theme-editor/state-preferences.test.ts +15 -0
- package/src/theme-editor/state.ts +46 -0
- package/src/theme-editor/types.ts +15 -1
- package/src/theme-editor/webmcp/tools.test.ts +13 -0
- package/src/theme-editor/webmcp/tools.ts +5 -0
- package/src/theme-reference.ts +9 -2
- package/src/types/theme.ts +32 -0
- package/src/types.ts +291 -25
- package/src/ui.artifact-pane-gating.test.ts +5 -5
- package/src/ui.config-preferences.test.ts +166 -0
- package/src/ui.detached-panel.test.ts +1 -1
- package/src/ui.suggest-replies.test.ts +1066 -1
- package/src/ui.ts +311 -45
- package/src/ui.typing-indicator.test.ts +135 -0
- package/src/utils/artifact-display.test.ts +180 -16
- package/src/utils/artifact-display.ts +155 -14
- 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 +84 -0
- package/src/utils/config-merge.ts +6 -1
- package/src/utils/feature-preferences.test.ts +326 -0
- package/src/utils/feature-preferences.ts +498 -0
- package/src/utils/icons.test.ts +26 -0
- package/src/utils/icons.ts +8 -0
- package/src/utils/theme.test.ts +171 -0
- package/src/utils/tokens.ts +71 -7
- package/dist/chunk-MMUPR2JW.js +0 -1
|
@@ -79,6 +79,24 @@ describe("buildPillComposer (single-row pill composer)", () => {
|
|
|
79
79
|
expect(formChildren[2]).toBe(elements.rightActions);
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
+
it("keeps its 100px max-height cap, even under a themed line height", () => {
|
|
83
|
+
const elements = buildPillComposer({ config: { apiUrl: "/api" } });
|
|
84
|
+
expect(elements.textarea.style.maxHeight).toBe("100px");
|
|
85
|
+
|
|
86
|
+
// A themed line height must not re-derive the cap: the pill's explicit
|
|
87
|
+
// post-construction override wins over the 3-line default.
|
|
88
|
+
elements.textarea.style.lineHeight = "24px";
|
|
89
|
+
document.body.appendChild(elements.textarea);
|
|
90
|
+
Object.defineProperty(elements.textarea, "scrollHeight", {
|
|
91
|
+
configurable: true,
|
|
92
|
+
value: 10000,
|
|
93
|
+
});
|
|
94
|
+
elements.textarea.dispatchEvent(new Event("input"));
|
|
95
|
+
expect(elements.textarea.style.maxHeight).toBe("100px");
|
|
96
|
+
expect(elements.textarea.style.height).toBe("100px");
|
|
97
|
+
document.body.removeChild(elements.textarea);
|
|
98
|
+
});
|
|
99
|
+
|
|
82
100
|
it("returns null for optional controls when disabled (matching ComposerElements contract)", () => {
|
|
83
101
|
const elements = buildPillComposer({ config: { apiUrl: "/api" } });
|
|
84
102
|
expect(elements.attachmentButton).toBeNull();
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
|
|
5
|
+
import { createSuggestions } from "./suggestions";
|
|
6
|
+
import type { AgentWidgetSession } from "../session";
|
|
7
|
+
|
|
8
|
+
const makeSession = (): AgentWidgetSession =>
|
|
9
|
+
({
|
|
10
|
+
isStreaming: () => false,
|
|
11
|
+
getMessages: () => [],
|
|
12
|
+
sendMessage: () => {},
|
|
13
|
+
}) as unknown as AgentWidgetSession;
|
|
14
|
+
|
|
15
|
+
const setup = () => {
|
|
16
|
+
const container = document.createElement("div");
|
|
17
|
+
document.body.appendChild(container);
|
|
18
|
+
const textarea = document.createElement("textarea");
|
|
19
|
+
document.body.appendChild(textarea);
|
|
20
|
+
return {
|
|
21
|
+
container,
|
|
22
|
+
textarea,
|
|
23
|
+
manager: createSuggestions(container),
|
|
24
|
+
session: makeSession(),
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const withAnimate = (): ReturnType<typeof vi.fn> => {
|
|
29
|
+
const animate = vi.fn(() => ({}));
|
|
30
|
+
Object.defineProperty(Element.prototype, "animate", {
|
|
31
|
+
value: animate,
|
|
32
|
+
configurable: true,
|
|
33
|
+
writable: true,
|
|
34
|
+
});
|
|
35
|
+
return animate;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
Reflect.deleteProperty(Element.prototype, "animate");
|
|
40
|
+
vi.unstubAllGlobals();
|
|
41
|
+
document.body.replaceChildren();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("suggestion entrance animation", () => {
|
|
45
|
+
it("animates each item once for a newly shown set", () => {
|
|
46
|
+
const animate = withAnimate();
|
|
47
|
+
const { manager, session, textarea } = setup();
|
|
48
|
+
|
|
49
|
+
manager.render(["One", "Two"], session, textarea, [], undefined, {
|
|
50
|
+
variant: "card",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(animate).toHaveBeenCalledTimes(2);
|
|
54
|
+
const [, secondOptions] = animate.mock.calls[1] as [
|
|
55
|
+
unknown,
|
|
56
|
+
{ delay: number; duration: number; fill: string },
|
|
57
|
+
];
|
|
58
|
+
expect(secondOptions.delay).toBe(60);
|
|
59
|
+
expect(secondOptions.duration).toBe(250);
|
|
60
|
+
expect(secondOptions.fill).toBe("backwards");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("does not re-animate when render repeats the same items", () => {
|
|
64
|
+
const animate = withAnimate();
|
|
65
|
+
const { manager, session, textarea } = setup();
|
|
66
|
+
const items = ["One", "Two"];
|
|
67
|
+
|
|
68
|
+
manager.render(items, session, textarea, [], undefined, {
|
|
69
|
+
variant: "card",
|
|
70
|
+
});
|
|
71
|
+
manager.render(items, session, textarea, [], undefined, {
|
|
72
|
+
variant: "card",
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
expect(animate).toHaveBeenCalledTimes(2);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("animates again once the item set changes", () => {
|
|
79
|
+
const animate = withAnimate();
|
|
80
|
+
const { manager, session, textarea } = setup();
|
|
81
|
+
|
|
82
|
+
manager.render(["One"], session, textarea, [], undefined, {
|
|
83
|
+
variant: "card",
|
|
84
|
+
});
|
|
85
|
+
manager.render(["Two"], session, textarea, [], undefined, {
|
|
86
|
+
variant: "card",
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(animate).toHaveBeenCalledTimes(2);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("skips the animation under prefers-reduced-motion", () => {
|
|
93
|
+
const animate = withAnimate();
|
|
94
|
+
vi.stubGlobal(
|
|
95
|
+
"matchMedia",
|
|
96
|
+
vi.fn(() => ({ matches: true }))
|
|
97
|
+
);
|
|
98
|
+
const { manager, session, textarea } = setup();
|
|
99
|
+
|
|
100
|
+
manager.render(["One", "Two"], session, textarea, [], undefined, {
|
|
101
|
+
variant: "card",
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(animate).not.toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("still renders when the platform has no Web Animations API", () => {
|
|
108
|
+
const { container, manager, session, textarea } = setup();
|
|
109
|
+
|
|
110
|
+
expect(typeof Element.prototype.animate).toBe("undefined");
|
|
111
|
+
expect(() =>
|
|
112
|
+
manager.render(["One", "Two"], session, textarea, [], undefined, {
|
|
113
|
+
variant: "card",
|
|
114
|
+
})
|
|
115
|
+
).not.toThrow();
|
|
116
|
+
expect(container.querySelectorAll(".persona-suggestion")).toHaveLength(2);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe("per-item icon color", () => {
|
|
121
|
+
const iconOf = (container: HTMLElement): SVGElement =>
|
|
122
|
+
container.querySelector(".persona-suggestion__icon") as SVGElement;
|
|
123
|
+
|
|
124
|
+
it("tints only the icon element", () => {
|
|
125
|
+
const { manager, session, textarea, container } = setup();
|
|
126
|
+
|
|
127
|
+
manager.render(
|
|
128
|
+
[{ label: "Compare plans", icon: "dollar-sign", iconColor: "#16a34a" }],
|
|
129
|
+
session,
|
|
130
|
+
textarea,
|
|
131
|
+
[],
|
|
132
|
+
undefined,
|
|
133
|
+
{ variant: "card" }
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const button = container.querySelector("button") as HTMLButtonElement;
|
|
137
|
+
expect(iconOf(container).style.color).toBe("rgb(22, 163, 74)");
|
|
138
|
+
expect(button.style.color).toBe("");
|
|
139
|
+
expect(button.style.borderColor).toBe("");
|
|
140
|
+
expect(button.style.background).toBe("");
|
|
141
|
+
expect(
|
|
142
|
+
(container.querySelector(".persona-suggestion__label") as HTMLElement)
|
|
143
|
+
.style.color
|
|
144
|
+
).toBe("");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("wins over the emphasis-primary icon tint without recoloring the button", () => {
|
|
148
|
+
const { manager, session, textarea, container } = setup();
|
|
149
|
+
|
|
150
|
+
manager.render(
|
|
151
|
+
[
|
|
152
|
+
{
|
|
153
|
+
label: "Compare plans",
|
|
154
|
+
icon: "dollar-sign",
|
|
155
|
+
iconColor: "#16a34a",
|
|
156
|
+
emphasis: "primary",
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
session,
|
|
160
|
+
textarea,
|
|
161
|
+
[],
|
|
162
|
+
undefined,
|
|
163
|
+
{ variant: "card" }
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const button = container.querySelector("button") as HTMLButtonElement;
|
|
167
|
+
expect(button.dataset.emphasis).toBe("primary");
|
|
168
|
+
expect(iconOf(container).style.color).toBe("rgb(22, 163, 74)");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("leaves the icon in currentColor when iconColor is absent", () => {
|
|
172
|
+
const { manager, session, textarea, container } = setup();
|
|
173
|
+
|
|
174
|
+
manager.render(
|
|
175
|
+
[{ label: "Compare plans", icon: "dollar-sign" }],
|
|
176
|
+
session,
|
|
177
|
+
textarea,
|
|
178
|
+
[],
|
|
179
|
+
undefined,
|
|
180
|
+
{ variant: "card" }
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const icon = iconOf(container);
|
|
184
|
+
expect(icon.style.color).toBe("");
|
|
185
|
+
expect(icon.getAttribute("stroke")).toBe("currentColor");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("leaves string shorthand items unaffected", () => {
|
|
189
|
+
const { manager, session, textarea, container } = setup();
|
|
190
|
+
|
|
191
|
+
manager.render(["Compare plans"], session, textarea, [], undefined, {
|
|
192
|
+
variant: "card",
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
expect(container.querySelector(".persona-suggestion__icon")).toBeNull();
|
|
196
|
+
const button = container.querySelector("button") as HTMLButtonElement;
|
|
197
|
+
expect(button.style.color).toBe("");
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe("legacy suggestionChipsConfig scoping", () => {
|
|
202
|
+
const chipsConfig = {
|
|
203
|
+
fontFamily: "sans-serif" as const,
|
|
204
|
+
fontWeight: "500",
|
|
205
|
+
paddingX: "12px",
|
|
206
|
+
paddingY: "6px",
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
it("applies inline chip styles to the chip variant", () => {
|
|
210
|
+
const { manager, session, textarea, container } = setup();
|
|
211
|
+
|
|
212
|
+
manager.render(["One"], session, textarea, [], chipsConfig, {
|
|
213
|
+
variant: "chip",
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const button = container.querySelector("button") as HTMLButtonElement;
|
|
217
|
+
expect(button.style.paddingLeft).toBe("12px");
|
|
218
|
+
expect(button.style.paddingTop).toBe("6px");
|
|
219
|
+
expect(button.style.fontWeight).toBe("500");
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("does not let chip config override card and list padding tokens", () => {
|
|
223
|
+
const { manager, session, textarea, container } = setup();
|
|
224
|
+
|
|
225
|
+
for (const variant of ["card", "list"] as const) {
|
|
226
|
+
manager.render(["One"], session, textarea, [], chipsConfig, { variant });
|
|
227
|
+
const button = container.querySelector("button") as HTMLButtonElement;
|
|
228
|
+
expect(button.style.paddingLeft).toBe("");
|
|
229
|
+
expect(button.style.paddingTop).toBe("");
|
|
230
|
+
expect(button.style.fontFamily).toBe("");
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
});
|