@runtypelabs/persona 3.17.0 → 3.18.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 +142 -0
- package/dist/animations/glyph-cycle.d.cts +1 -1
- package/dist/animations/glyph-cycle.d.ts +1 -1
- package/dist/animations/{types-HPZY7oAI.d.cts → types-cwY5HaFD.d.cts} +25 -0
- package/dist/animations/{types-HPZY7oAI.d.ts → types-cwY5HaFD.d.ts} +25 -0
- package/dist/animations/wipe.d.cts +1 -1
- package/dist/animations/wipe.d.ts +1 -1
- package/dist/index.cjs +47 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +300 -1
- package/dist/index.d.ts +300 -1
- package/dist/index.global.js +75 -75
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +47 -47
- package/dist/index.js.map +1 -1
- package/dist/theme-editor.cjs +1432 -159
- package/dist/theme-editor.d.cts +218 -0
- package/dist/theme-editor.d.ts +218 -0
- package/dist/theme-editor.js +1432 -159
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +14 -0
- package/dist/theme-reference.d.ts +14 -0
- package/dist/widget.css +432 -0
- package/package.json +1 -1
- package/src/client.test.ts +134 -0
- package/src/client.ts +71 -0
- package/src/components/ask-user-question-bubble.test.ts +583 -0
- package/src/components/ask-user-question-bubble.ts +924 -0
- package/src/components/messages.ts +33 -1
- package/src/components/panel.ts +41 -4
- package/src/defaults.ts +21 -0
- package/src/index.ts +16 -1
- package/src/plugins/types.ts +57 -0
- package/src/session.test.ts +183 -0
- package/src/session.ts +242 -3
- package/src/styles/widget.css +432 -0
- package/src/types/theme.ts +15 -0
- package/src/types.ts +150 -0
- package/src/ui.ask-user-question-plugin.test.ts +649 -0
- package/src/ui.ts +631 -5
- package/src/utils/storage.ts +10 -2
- package/src/utils/theme.test.ts +36 -0
- package/src/utils/tokens.ts +23 -0
package/src/session.ts
CHANGED
|
@@ -81,9 +81,22 @@ export class AgentWidgetSession {
|
|
|
81
81
|
this.messages = this.sortMessages(this.messages);
|
|
82
82
|
this.client = new AgentWidgetClient(config);
|
|
83
83
|
|
|
84
|
+
// Hydrate artifacts from config (mirrors `initialMessages`). Restored
|
|
85
|
+
// records are forced to `status: "complete"` — a mid-stream artifact should
|
|
86
|
+
// never reappear after a refresh with its skeleton still showing.
|
|
87
|
+
for (const rec of config.initialArtifacts ?? []) {
|
|
88
|
+
this.artifacts.set(rec.id, { ...rec, status: "complete" });
|
|
89
|
+
}
|
|
90
|
+
if (config.initialSelectedArtifactId != null) {
|
|
91
|
+
this.selectedArtifactId = config.initialSelectedArtifactId;
|
|
92
|
+
}
|
|
93
|
+
|
|
84
94
|
if (this.messages.length) {
|
|
85
95
|
this.callbacks.onMessagesChanged([...this.messages]);
|
|
86
96
|
}
|
|
97
|
+
if (this.artifacts.size > 0) {
|
|
98
|
+
this.emitArtifactsState();
|
|
99
|
+
}
|
|
87
100
|
this.callbacks.onStatusChanged(this.status);
|
|
88
101
|
}
|
|
89
102
|
|
|
@@ -968,6 +981,194 @@ export class AgentWidgetSession {
|
|
|
968
981
|
}
|
|
969
982
|
}
|
|
970
983
|
|
|
984
|
+
/**
|
|
985
|
+
* Resolve a paused `ask_user_question` LOCAL tool call.
|
|
986
|
+
*
|
|
987
|
+
* When the server emits `step_await` for `ask_user_question`, the widget
|
|
988
|
+
* renders the answer-pill sheet and calls this method once the user
|
|
989
|
+
* picks. Steps:
|
|
990
|
+
* 1. POST the answer to `/resume` via `client.resumeFlow`.
|
|
991
|
+
* 2. Pipe the resulting SSE stream through `connectStream()` so the
|
|
992
|
+
* paused agent execution continues.
|
|
993
|
+
* 3. Append a user-visible bubble with the answer text so the
|
|
994
|
+
* transcript reads naturally.
|
|
995
|
+
*/
|
|
996
|
+
/**
|
|
997
|
+
* Persist in-progress answers and the current page index for a multi-question
|
|
998
|
+
* `ask_user_question` payload, so a refresh resumes on the same page with
|
|
999
|
+
* prior answers intact. Called by ui.ts on every Back/Next/pick interaction.
|
|
1000
|
+
*/
|
|
1001
|
+
public persistAskUserQuestionProgress(
|
|
1002
|
+
toolMessage: AgentWidgetMessage,
|
|
1003
|
+
progress: {
|
|
1004
|
+
answers: Record<string, string | string[]>;
|
|
1005
|
+
currentIndex: number;
|
|
1006
|
+
}
|
|
1007
|
+
): void {
|
|
1008
|
+
const current = this.messages.find((m) => m.id === toolMessage.id);
|
|
1009
|
+
if (!current) return;
|
|
1010
|
+
this.upsertMessage({
|
|
1011
|
+
...current,
|
|
1012
|
+
agentMetadata: {
|
|
1013
|
+
...current.agentMetadata,
|
|
1014
|
+
askUserQuestionAnswers: progress.answers,
|
|
1015
|
+
askUserQuestionIndex: progress.currentIndex,
|
|
1016
|
+
},
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Flip an `ask_user_question` tool message from awaiting → answered so
|
|
1022
|
+
* render passes stop re-mounting its answer-pill sheet. Idempotent.
|
|
1023
|
+
* When `answers` is provided, persists the full structured answer Record
|
|
1024
|
+
* atomically with the answered flag — guarding against later events that
|
|
1025
|
+
* could re-emit the tool message and clobber the per-pick persisted
|
|
1026
|
+
* answers via top-level merge.
|
|
1027
|
+
*/
|
|
1028
|
+
public markAskUserQuestionResolved(
|
|
1029
|
+
toolMessage: AgentWidgetMessage,
|
|
1030
|
+
answers?: Record<string, string | string[]>
|
|
1031
|
+
): void {
|
|
1032
|
+
const current = this.messages.find((m) => m.id === toolMessage.id);
|
|
1033
|
+
if (!current) return;
|
|
1034
|
+
this.upsertMessage({
|
|
1035
|
+
...current,
|
|
1036
|
+
agentMetadata: {
|
|
1037
|
+
...current.agentMetadata,
|
|
1038
|
+
awaitingLocalTool: false,
|
|
1039
|
+
askUserQuestionAnswered: true,
|
|
1040
|
+
...(answers ? { askUserQuestionAnswers: answers } : {}),
|
|
1041
|
+
},
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
public async resolveAskUserQuestion(
|
|
1046
|
+
toolMessage: AgentWidgetMessage,
|
|
1047
|
+
answer: string | Record<string, string | string[]>
|
|
1048
|
+
): Promise<void> {
|
|
1049
|
+
// Idempotent — guards against rapid double-clicks on answer pills before
|
|
1050
|
+
// the re-render swaps the card to its collapsed/answered state.
|
|
1051
|
+
const live = this.messages.find((m) => m.id === toolMessage.id);
|
|
1052
|
+
if (live?.agentMetadata?.askUserQuestionAnswered === true) return;
|
|
1053
|
+
|
|
1054
|
+
const executionId = toolMessage.agentMetadata?.executionId;
|
|
1055
|
+
const toolName = toolMessage.toolCall?.name;
|
|
1056
|
+
if (!executionId || !toolName) {
|
|
1057
|
+
this.callbacks.onError?.(
|
|
1058
|
+
new Error(
|
|
1059
|
+
"resolveAskUserQuestion: message is missing executionId or toolCall.name"
|
|
1060
|
+
)
|
|
1061
|
+
);
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// Flip answered flag first so the next render skips the sheet re-mount,
|
|
1066
|
+
// avoiding the race between removeAskUserQuestionSheet's 180ms slide-out
|
|
1067
|
+
// timer and the renders that fire as the resume stream lands. Pass the
|
|
1068
|
+
// structured answer Record (when present) so it's atomically persisted
|
|
1069
|
+
// alongside the flag — the answered-state review card depends on
|
|
1070
|
+
// `agentMetadata.askUserQuestionAnswers` being populated at render time.
|
|
1071
|
+
//
|
|
1072
|
+
// For single-question payloads, callers (built-in pick handler, plugins)
|
|
1073
|
+
// resolve with a plain string. Derive a `{ [questionText]: answer }` Record
|
|
1074
|
+
// from the toolCall args so the answered-card render path is consistent
|
|
1075
|
+
// with grouped flows.
|
|
1076
|
+
let structuredAnswers: Record<string, string | string[]> | undefined =
|
|
1077
|
+
typeof answer === "string" ? undefined : answer;
|
|
1078
|
+
if (structuredAnswers === undefined && typeof answer === "string") {
|
|
1079
|
+
const args = toolMessage.toolCall?.args as
|
|
1080
|
+
| { questions?: Array<{ question?: unknown }> }
|
|
1081
|
+
| undefined;
|
|
1082
|
+
const questions = Array.isArray(args?.questions) ? args!.questions : [];
|
|
1083
|
+
if (questions.length === 1) {
|
|
1084
|
+
const qText = typeof questions[0]?.question === "string"
|
|
1085
|
+
? (questions[0].question as string)
|
|
1086
|
+
: "";
|
|
1087
|
+
if (qText) structuredAnswers = { [qText]: answer };
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
this.markAskUserQuestionResolved(toolMessage, structuredAnswers);
|
|
1091
|
+
|
|
1092
|
+
// Inject Q→A pair messages — one assistant bubble per question, one user
|
|
1093
|
+
// bubble per answer — so the transcript reads like a normal conversation.
|
|
1094
|
+
// The original ask_user_question tool message is suppressed by the
|
|
1095
|
+
// renderer once `askUserQuestionAnswered` is true. Skipped questions get
|
|
1096
|
+
// a muted italic `*Skipped*` user bubble (rendered through the standard
|
|
1097
|
+
// markdown pipeline).
|
|
1098
|
+
const toolCallId = toolMessage.toolCall!.id;
|
|
1099
|
+
const args = toolMessage.toolCall?.args as
|
|
1100
|
+
| { questions?: Array<{ question?: unknown; header?: unknown }> }
|
|
1101
|
+
| undefined;
|
|
1102
|
+
const questions = Array.isArray(args?.questions) ? args!.questions : [];
|
|
1103
|
+
if (questions.length === 0) {
|
|
1104
|
+
const fallback =
|
|
1105
|
+
typeof answer === "string"
|
|
1106
|
+
? answer
|
|
1107
|
+
: Object.entries(answer)
|
|
1108
|
+
.map(
|
|
1109
|
+
([q, v]) => `${q}: ${Array.isArray(v) ? v.join(", ") : v}`
|
|
1110
|
+
)
|
|
1111
|
+
.join(" | ");
|
|
1112
|
+
this.appendMessage({
|
|
1113
|
+
id: `ask-user-answer-${toolCallId}`,
|
|
1114
|
+
role: "user",
|
|
1115
|
+
content: fallback,
|
|
1116
|
+
createdAt: new Date().toISOString(),
|
|
1117
|
+
streaming: false,
|
|
1118
|
+
sequence: this.nextSequence(),
|
|
1119
|
+
});
|
|
1120
|
+
} else {
|
|
1121
|
+
const stored = structuredAnswers ?? {};
|
|
1122
|
+
questions.forEach((p, i) => {
|
|
1123
|
+
const qText = typeof p?.question === "string" ? p.question : "";
|
|
1124
|
+
if (!qText) return;
|
|
1125
|
+
const ans = stored[qText];
|
|
1126
|
+
const answerStr = Array.isArray(ans)
|
|
1127
|
+
? ans.join(", ")
|
|
1128
|
+
: typeof ans === "string"
|
|
1129
|
+
? ans
|
|
1130
|
+
: "";
|
|
1131
|
+
this.appendMessage({
|
|
1132
|
+
id: `ask-user-q-${toolCallId}-${i}`,
|
|
1133
|
+
role: "assistant",
|
|
1134
|
+
content: qText,
|
|
1135
|
+
createdAt: new Date().toISOString(),
|
|
1136
|
+
streaming: false,
|
|
1137
|
+
sequence: this.nextSequence(),
|
|
1138
|
+
});
|
|
1139
|
+
this.appendMessage({
|
|
1140
|
+
id: `ask-user-a-${toolCallId}-${i}`,
|
|
1141
|
+
role: "user",
|
|
1142
|
+
content: answerStr || "*Skipped*",
|
|
1143
|
+
createdAt: new Date().toISOString(),
|
|
1144
|
+
streaming: false,
|
|
1145
|
+
sequence: this.nextSequence(),
|
|
1146
|
+
});
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
try {
|
|
1151
|
+
const response = await this.client.resumeFlow(executionId, {
|
|
1152
|
+
[toolName]: answer,
|
|
1153
|
+
});
|
|
1154
|
+
|
|
1155
|
+
if (!response.ok) {
|
|
1156
|
+
const errorData = await response.json().catch(() => null);
|
|
1157
|
+
throw new Error(
|
|
1158
|
+
errorData?.error ?? `Resume failed: ${response.status}`
|
|
1159
|
+
);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
if (response.body) {
|
|
1163
|
+
await this.connectStream(response.body);
|
|
1164
|
+
}
|
|
1165
|
+
} catch (error) {
|
|
1166
|
+
this.callbacks.onError?.(
|
|
1167
|
+
error instanceof Error ? error : new Error(String(error))
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
971
1172
|
public cancel() {
|
|
972
1173
|
this.abortController?.abort();
|
|
973
1174
|
this.abortController = null;
|
|
@@ -1123,6 +1324,18 @@ export class AgentWidgetSession {
|
|
|
1123
1324
|
this.callbacks.onMessagesChanged([...this.messages]);
|
|
1124
1325
|
}
|
|
1125
1326
|
|
|
1327
|
+
public hydrateArtifacts(
|
|
1328
|
+
artifacts: PersonaArtifactRecord[],
|
|
1329
|
+
selectedId: string | null = null
|
|
1330
|
+
) {
|
|
1331
|
+
this.artifacts.clear();
|
|
1332
|
+
for (const rec of artifacts) {
|
|
1333
|
+
this.artifacts.set(rec.id, { ...rec, status: "complete" });
|
|
1334
|
+
}
|
|
1335
|
+
this.selectedArtifactId = selectedId;
|
|
1336
|
+
this.emitArtifactsState();
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1126
1339
|
private handleEvent = (event: AgentWidgetEvent) => {
|
|
1127
1340
|
if (event.type === "message") {
|
|
1128
1341
|
this.upsertMessage(event.message);
|
|
@@ -1317,9 +1530,35 @@ export class AgentWidgetSession {
|
|
|
1317
1530
|
return;
|
|
1318
1531
|
}
|
|
1319
1532
|
|
|
1320
|
-
this.messages = this.messages.map((existing, idx) =>
|
|
1321
|
-
idx
|
|
1322
|
-
|
|
1533
|
+
this.messages = this.messages.map((existing, idx) => {
|
|
1534
|
+
if (idx !== index) return existing;
|
|
1535
|
+
const merged = { ...existing, ...withSequence };
|
|
1536
|
+
// Preserve `ask_user_question` answered state across re-emissions.
|
|
1537
|
+
// Top-level merge would otherwise replace `agentMetadata` wholesale —
|
|
1538
|
+
// post-resume events (e.g. `tool_complete` re-emitted from a stale
|
|
1539
|
+
// client-side cache) would wipe `askUserQuestionAnswered` and
|
|
1540
|
+
// `askUserQuestionAnswers`, causing the answered review card to
|
|
1541
|
+
// lose its answers and revert to "(skipped)" placeholders.
|
|
1542
|
+
if (
|
|
1543
|
+
existing.agentMetadata?.askUserQuestionAnswered === true &&
|
|
1544
|
+
withSequence.agentMetadata
|
|
1545
|
+
) {
|
|
1546
|
+
merged.agentMetadata = {
|
|
1547
|
+
...withSequence.agentMetadata,
|
|
1548
|
+
askUserQuestionAnswered: true,
|
|
1549
|
+
...(existing.agentMetadata.askUserQuestionAnswers
|
|
1550
|
+
? {
|
|
1551
|
+
askUserQuestionAnswers:
|
|
1552
|
+
existing.agentMetadata.askUserQuestionAnswers,
|
|
1553
|
+
}
|
|
1554
|
+
: {}),
|
|
1555
|
+
// Keep awaiting flag false once resolved — never let a stale
|
|
1556
|
+
// re-emit flip us back to awaiting.
|
|
1557
|
+
awaitingLocalTool: false,
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
return merged;
|
|
1561
|
+
});
|
|
1323
1562
|
this.messages = this.sortMessages(this.messages);
|
|
1324
1563
|
this.callbacks.onMessagesChanged([...this.messages]);
|
|
1325
1564
|
}
|
package/src/styles/widget.css
CHANGED
|
@@ -1759,6 +1759,30 @@
|
|
|
1759
1759
|
animation: persona-message-actions-fade-in 0.3s ease-out forwards;
|
|
1760
1760
|
}
|
|
1761
1761
|
|
|
1762
|
+
/* ask_user_question — collapsed answered state.
|
|
1763
|
+
* When the user picks an option, the interactive card is replaced with a
|
|
1764
|
+
* plain assistant bubble showing the question text. A short fade + slight
|
|
1765
|
+
* upward slide sells the "card resolved into history" feel.
|
|
1766
|
+
*/
|
|
1767
|
+
@keyframes persona-ask-resolved {
|
|
1768
|
+
from {
|
|
1769
|
+
opacity: 0;
|
|
1770
|
+
transform: translateY(-4px);
|
|
1771
|
+
}
|
|
1772
|
+
to {
|
|
1773
|
+
opacity: 1;
|
|
1774
|
+
transform: translateY(0);
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
[data-ask-answered="true"] {
|
|
1778
|
+
animation: persona-ask-resolved 0.22s ease-out;
|
|
1779
|
+
}
|
|
1780
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1781
|
+
[data-ask-answered="true"] {
|
|
1782
|
+
animation: none;
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1762
1786
|
/* Action bar alignment */
|
|
1763
1787
|
.persona-message-actions-left {
|
|
1764
1788
|
justify-content: flex-start;
|
|
@@ -2957,3 +2981,411 @@
|
|
|
2957
2981
|
background-clip: border-box !important;
|
|
2958
2982
|
}
|
|
2959
2983
|
}
|
|
2984
|
+
|
|
2985
|
+
/* ========================================================================
|
|
2986
|
+
* ask_user_question — built-in answer-pill sheet
|
|
2987
|
+
* Slides in over the composer when the assistant invokes `ask_user_question`.
|
|
2988
|
+
* Overridable via `config.features.askUserQuestion.styles`.
|
|
2989
|
+
* ======================================================================== */
|
|
2990
|
+
|
|
2991
|
+
[data-persona-root] .persona-hidden {
|
|
2992
|
+
display: none !important;
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
/* In-transcript stub — small "Awaiting…" chip. */
|
|
2996
|
+
[data-persona-root] .persona-ask-stub {
|
|
2997
|
+
padding: 0.35rem 0.7rem;
|
|
2998
|
+
border-radius: 999px;
|
|
2999
|
+
font-size: 0.8rem;
|
|
3000
|
+
color: var(--persona-muted, #6b7280);
|
|
3001
|
+
background: var(--persona-container, #f3f4f6);
|
|
3002
|
+
border: 1px dashed var(--persona-border, #e5e7eb);
|
|
3003
|
+
}
|
|
3004
|
+
|
|
3005
|
+
[data-persona-root] .persona-ask-stub-label {
|
|
3006
|
+
font-weight: 500;
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
/* Sheet container — absolute inside composerOverlay. */
|
|
3010
|
+
[data-persona-root] .persona-ask-sheet {
|
|
3011
|
+
position: absolute;
|
|
3012
|
+
left: 0.75rem;
|
|
3013
|
+
right: 0.75rem;
|
|
3014
|
+
bottom: calc(100% + 0.5rem);
|
|
3015
|
+
box-sizing: border-box;
|
|
3016
|
+
padding: 0.85rem 1rem;
|
|
3017
|
+
background: var(--persona-ask-sheet-bg, var(--persona-surface, #ffffff));
|
|
3018
|
+
border: 1px solid var(--persona-ask-sheet-border, var(--persona-border, #e5e7eb));
|
|
3019
|
+
border-radius: 1rem;
|
|
3020
|
+
box-shadow: var(--persona-ask-sheet-shadow, 0 12px 28px -10px rgba(0, 0, 0, 0.15), 0 4px 10px -6px rgba(0, 0, 0, 0.08));
|
|
3021
|
+
transition: transform var(--persona-ask-sheet-duration, 180ms) ease, opacity var(--persona-ask-sheet-duration, 180ms) ease;
|
|
3022
|
+
opacity: 1;
|
|
3023
|
+
transform: translateY(0);
|
|
3024
|
+
}
|
|
3025
|
+
|
|
3026
|
+
[data-persona-root] .persona-ask-sheet.persona-ask-sheet-enter {
|
|
3027
|
+
opacity: 0;
|
|
3028
|
+
transform: translateY(8px);
|
|
3029
|
+
}
|
|
3030
|
+
|
|
3031
|
+
[data-persona-root] .persona-ask-sheet.persona-ask-sheet-leave {
|
|
3032
|
+
opacity: 0;
|
|
3033
|
+
transform: translateY(8px);
|
|
3034
|
+
pointer-events: none;
|
|
3035
|
+
}
|
|
3036
|
+
|
|
3037
|
+
/* Header row — question + close button */
|
|
3038
|
+
[data-persona-root] .persona-ask-sheet-header {
|
|
3039
|
+
margin-bottom: 0.55rem;
|
|
3040
|
+
}
|
|
3041
|
+
|
|
3042
|
+
[data-persona-root] .persona-ask-sheet-question {
|
|
3043
|
+
font-size: 0.92rem;
|
|
3044
|
+
font-weight: 500;
|
|
3045
|
+
line-height: 1.35;
|
|
3046
|
+
color: var(--persona-text, #1f2937);
|
|
3047
|
+
min-height: 1.35em;
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
[data-persona-root] .persona-ask-question-skeleton {
|
|
3051
|
+
display: block;
|
|
3052
|
+
width: 60%;
|
|
3053
|
+
height: 0.85rem;
|
|
3054
|
+
border-radius: 0.3rem;
|
|
3055
|
+
background: linear-gradient(90deg,
|
|
3056
|
+
var(--persona-container, #f3f4f6) 0%,
|
|
3057
|
+
var(--persona-border, #e5e7eb) 50%,
|
|
3058
|
+
var(--persona-container, #f3f4f6) 100%);
|
|
3059
|
+
background-size: 200% 100%;
|
|
3060
|
+
animation: persona-ask-skeleton-shimmer 1.2s ease-in-out infinite;
|
|
3061
|
+
color: transparent;
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
[data-persona-root] .persona-ask-sheet-step-inline {
|
|
3065
|
+
flex: 0 0 auto;
|
|
3066
|
+
font-size: 0.78rem;
|
|
3067
|
+
line-height: 1;
|
|
3068
|
+
color: var(--persona-text-muted, #6b7280);
|
|
3069
|
+
font-variant-numeric: tabular-nums;
|
|
3070
|
+
letter-spacing: 0.01em;
|
|
3071
|
+
white-space: nowrap;
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3074
|
+
[data-persona-root] .persona-ask-sheet-step-inline:empty {
|
|
3075
|
+
display: none;
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
/* Option list — stacked one per row by default ("rows" layout). The "pills"
|
|
3079
|
+
layout opt-in switches to horizontal wrap with compact pills; see also
|
|
3080
|
+
horizontalPillsAskPlugin example for a custom variant. */
|
|
3081
|
+
[data-persona-root] .persona-ask-pills {
|
|
3082
|
+
display: flex;
|
|
3083
|
+
flex-direction: column;
|
|
3084
|
+
flex-wrap: nowrap;
|
|
3085
|
+
row-gap: 0.4rem;
|
|
3086
|
+
column-gap: 0;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
[data-persona-root] .persona-ask-pills--rows {
|
|
3090
|
+
flex-direction: column;
|
|
3091
|
+
flex-wrap: nowrap;
|
|
3092
|
+
gap: 0.4rem;
|
|
3093
|
+
}
|
|
3094
|
+
|
|
3095
|
+
/* Pills layout opt-in — horizontal wrap, auto-width compact pills. */
|
|
3096
|
+
[data-persona-root] .persona-ask-sheet--pills .persona-ask-pills:not(.persona-ask-pills--rows) {
|
|
3097
|
+
flex-direction: row;
|
|
3098
|
+
flex-wrap: wrap;
|
|
3099
|
+
gap: 0.4rem;
|
|
3100
|
+
}
|
|
3101
|
+
|
|
3102
|
+
[data-persona-root] .persona-ask-sheet--pills .persona-ask-pills:not(.persona-ask-pills--rows) .persona-ask-pill {
|
|
3103
|
+
width: auto;
|
|
3104
|
+
padding: 0.4rem 0.9rem;
|
|
3105
|
+
border-radius: var(--persona-ask-pill-radius, 9999px);
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3108
|
+
[data-persona-root] .persona-ask-pill {
|
|
3109
|
+
display: flex;
|
|
3110
|
+
align-items: center;
|
|
3111
|
+
justify-content: flex-start;
|
|
3112
|
+
width: 100%;
|
|
3113
|
+
text-align: left;
|
|
3114
|
+
padding: 0.65rem 0.9rem;
|
|
3115
|
+
border-radius: var(--persona-ask-pill-radius, 0.6rem);
|
|
3116
|
+
background: var(--persona-ask-pill-bg, transparent);
|
|
3117
|
+
color: var(--persona-ask-pill-fg, var(--persona-text, #1f2937));
|
|
3118
|
+
border: 1px solid var(--persona-border, #e5e7eb);
|
|
3119
|
+
font-size: 0.9rem;
|
|
3120
|
+
font-weight: 500;
|
|
3121
|
+
cursor: pointer;
|
|
3122
|
+
transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3125
|
+
[data-persona-root] .persona-ask-pill:hover:not(:disabled):not(.persona-ask-pill-skeleton):not(.persona-ask-pill-selected):not([aria-pressed="true"]) {
|
|
3126
|
+
border-color: var(--persona-text, #1f2937);
|
|
3127
|
+
background: var(--persona-container, #f3f4f6);
|
|
3128
|
+
}
|
|
3129
|
+
|
|
3130
|
+
[data-persona-root] .persona-ask-pill:active {
|
|
3131
|
+
transform: translateY(1px);
|
|
3132
|
+
}
|
|
3133
|
+
|
|
3134
|
+
[data-persona-root] .persona-ask-pill-selected,
|
|
3135
|
+
[data-persona-root] .persona-ask-pill[aria-pressed="true"] {
|
|
3136
|
+
background: var(--persona-ask-pill-bg-selected, var(--persona-accent, #0f0f0f));
|
|
3137
|
+
color: var(--persona-ask-pill-fg-selected, #fafafa);
|
|
3138
|
+
border-color: var(--persona-ask-pill-bg-selected, var(--persona-accent, #0f0f0f));
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
[data-persona-root] .persona-ask-pill:focus:not(:focus-visible) {
|
|
3142
|
+
outline: none;
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3145
|
+
[data-persona-root] .persona-ask-pill:focus-visible {
|
|
3146
|
+
outline: 2px solid var(--persona-accent, #0f0f0f);
|
|
3147
|
+
outline-offset: 2px;
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3150
|
+
[data-persona-root] .persona-ask-pill-custom {
|
|
3151
|
+
border-style: dashed;
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
[data-persona-root] .persona-ask-pill-skeleton {
|
|
3155
|
+
min-width: 5rem;
|
|
3156
|
+
height: 2rem;
|
|
3157
|
+
padding: 0;
|
|
3158
|
+
border: 1px solid var(--persona-border, #e5e7eb);
|
|
3159
|
+
background: linear-gradient(90deg,
|
|
3160
|
+
var(--persona-container, #f3f4f6) 0%,
|
|
3161
|
+
var(--persona-border, #e5e7eb) 50%,
|
|
3162
|
+
var(--persona-container, #f3f4f6) 100%);
|
|
3163
|
+
background-size: 200% 100%;
|
|
3164
|
+
animation: persona-ask-skeleton-shimmer 1.2s ease-in-out infinite;
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3167
|
+
@keyframes persona-ask-skeleton-shimmer {
|
|
3168
|
+
0% { background-position: 100% 50%; }
|
|
3169
|
+
100% { background-position: -100% 50%; }
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
/* Row layout — full-width stacked rows with always-visible description
|
|
3173
|
+
and a right-edge affordance (number badge for single-select, check for
|
|
3174
|
+
multi-select). Layered on top of .persona-ask-pill base styles. */
|
|
3175
|
+
[data-persona-root] .persona-ask-row {
|
|
3176
|
+
align-items: stretch;
|
|
3177
|
+
justify-content: space-between;
|
|
3178
|
+
gap: 0.75rem;
|
|
3179
|
+
padding: 0.7rem 0.9rem;
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
[data-persona-root] .persona-ask-row-content {
|
|
3183
|
+
display: flex;
|
|
3184
|
+
flex-direction: column;
|
|
3185
|
+
gap: 0.15rem;
|
|
3186
|
+
flex: 1 1 auto;
|
|
3187
|
+
min-width: 0;
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
[data-persona-root] .persona-ask-row-label {
|
|
3191
|
+
font-size: 0.92rem;
|
|
3192
|
+
font-weight: 600;
|
|
3193
|
+
line-height: 1.25;
|
|
3194
|
+
color: inherit;
|
|
3195
|
+
white-space: normal;
|
|
3196
|
+
overflow-wrap: anywhere;
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
[data-persona-root] .persona-ask-row-description {
|
|
3200
|
+
font-size: 0.82rem;
|
|
3201
|
+
font-weight: 400;
|
|
3202
|
+
line-height: 1.35;
|
|
3203
|
+
color: var(--persona-text-muted, #6b7280);
|
|
3204
|
+
white-space: normal;
|
|
3205
|
+
overflow-wrap: anywhere;
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
[data-persona-root] .persona-ask-pill-selected .persona-ask-row-description,
|
|
3209
|
+
[data-persona-root] .persona-ask-pill[aria-pressed="true"] .persona-ask-row-description {
|
|
3210
|
+
color: var(--persona-ask-pill-fg-selected, #fafafa);
|
|
3211
|
+
opacity: 0.85;
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
[data-persona-root] .persona-ask-row-affordance {
|
|
3215
|
+
display: inline-flex;
|
|
3216
|
+
align-items: center;
|
|
3217
|
+
justify-content: center;
|
|
3218
|
+
flex: 0 0 auto;
|
|
3219
|
+
align-self: center;
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
[data-persona-root] .persona-ask-row-badge {
|
|
3223
|
+
display: inline-flex;
|
|
3224
|
+
align-items: center;
|
|
3225
|
+
justify-content: center;
|
|
3226
|
+
width: 1.5rem;
|
|
3227
|
+
height: 1.5rem;
|
|
3228
|
+
border-radius: 0.4rem;
|
|
3229
|
+
border: 1px solid var(--persona-border, #e5e7eb);
|
|
3230
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3231
|
+
font-size: 0.78rem;
|
|
3232
|
+
font-weight: 600;
|
|
3233
|
+
color: var(--persona-text-muted, #6b7280);
|
|
3234
|
+
background: transparent;
|
|
3235
|
+
}
|
|
3236
|
+
|
|
3237
|
+
[data-persona-root] .persona-ask-pill-selected .persona-ask-row-badge,
|
|
3238
|
+
[data-persona-root] .persona-ask-pill[aria-pressed="true"] .persona-ask-row-badge {
|
|
3239
|
+
border-color: var(--persona-ask-pill-fg-selected, #fafafa);
|
|
3240
|
+
color: var(--persona-ask-pill-fg-selected, #fafafa);
|
|
3241
|
+
}
|
|
3242
|
+
|
|
3243
|
+
[data-persona-root] .persona-ask-row-check {
|
|
3244
|
+
display: inline-flex;
|
|
3245
|
+
align-items: center;
|
|
3246
|
+
justify-content: center;
|
|
3247
|
+
width: 1.4rem;
|
|
3248
|
+
height: 1.4rem;
|
|
3249
|
+
border-radius: 0.35rem;
|
|
3250
|
+
border: 1.5px solid var(--persona-border, #d1d5db);
|
|
3251
|
+
background: transparent;
|
|
3252
|
+
position: relative;
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
[data-persona-root] .persona-ask-pill-selected .persona-ask-row-check,
|
|
3256
|
+
[data-persona-root] .persona-ask-pill[aria-pressed="true"] .persona-ask-row-check {
|
|
3257
|
+
background: var(--persona-ask-pill-fg-selected, #fafafa);
|
|
3258
|
+
border-color: var(--persona-ask-pill-fg-selected, #fafafa);
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3261
|
+
[data-persona-root] .persona-ask-pill-selected .persona-ask-row-check::after,
|
|
3262
|
+
[data-persona-root] .persona-ask-pill[aria-pressed="true"] .persona-ask-row-check::after {
|
|
3263
|
+
content: "";
|
|
3264
|
+
width: 0.45rem;
|
|
3265
|
+
height: 0.75rem;
|
|
3266
|
+
border-right: 2px solid var(--persona-ask-pill-bg-selected, var(--persona-accent, #0f0f0f));
|
|
3267
|
+
border-bottom: 2px solid var(--persona-ask-pill-bg-selected, var(--persona-accent, #0f0f0f));
|
|
3268
|
+
transform: rotate(45deg) translate(-1px, -1px);
|
|
3269
|
+
}
|
|
3270
|
+
|
|
3271
|
+
[data-persona-root] .persona-ask-row.persona-ask-pill-skeleton {
|
|
3272
|
+
height: 3rem;
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
/* Other row (rows mode) — composite row that contains the free-text input
|
|
3276
|
+
* directly. The input fills the row body; the badge sits on the right. */
|
|
3277
|
+
[data-persona-root] .persona-ask-row--other {
|
|
3278
|
+
cursor: text;
|
|
3279
|
+
}
|
|
3280
|
+
|
|
3281
|
+
[data-persona-root] .persona-ask-row-input {
|
|
3282
|
+
flex: 1;
|
|
3283
|
+
min-width: 0;
|
|
3284
|
+
border: none;
|
|
3285
|
+
background: transparent;
|
|
3286
|
+
padding: 0;
|
|
3287
|
+
margin: 0;
|
|
3288
|
+
font: inherit;
|
|
3289
|
+
font-size: 0.92rem;
|
|
3290
|
+
color: inherit;
|
|
3291
|
+
outline: none;
|
|
3292
|
+
width: 100%;
|
|
3293
|
+
}
|
|
3294
|
+
|
|
3295
|
+
[data-persona-root] .persona-ask-row-input::placeholder {
|
|
3296
|
+
color: var(--persona-text-muted, #6b7280);
|
|
3297
|
+
opacity: 1;
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3300
|
+
/* Free-text expansion row (pills layout only) */
|
|
3301
|
+
[data-persona-root] .persona-ask-free-text {
|
|
3302
|
+
width: 100%;
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
[data-persona-root] .persona-ask-free-text--rows {
|
|
3306
|
+
margin-top: 0.4rem;
|
|
3307
|
+
}
|
|
3308
|
+
|
|
3309
|
+
[data-persona-root] .persona-ask-free-text-input {
|
|
3310
|
+
padding: 0.5rem 0.8rem;
|
|
3311
|
+
border: 1px solid var(--persona-border, #e5e7eb);
|
|
3312
|
+
border-radius: 0.55rem;
|
|
3313
|
+
font-size: 0.88rem;
|
|
3314
|
+
background: var(--persona-ask-input-bg, var(--persona-surface, #ffffff));
|
|
3315
|
+
color: var(--persona-text, #1f2937);
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3318
|
+
[data-persona-root] .persona-ask-free-text-input:focus {
|
|
3319
|
+
outline: 2px solid var(--persona-accent, #0f0f0f);
|
|
3320
|
+
outline-offset: 1px;
|
|
3321
|
+
}
|
|
3322
|
+
|
|
3323
|
+
[data-persona-root] .persona-ask-free-text-submit,
|
|
3324
|
+
[data-persona-root] .persona-ask-multi-submit {
|
|
3325
|
+
padding: 0.5rem 1rem;
|
|
3326
|
+
border: none;
|
|
3327
|
+
border-radius: 0.55rem;
|
|
3328
|
+
background: var(--persona-accent, #0f0f0f);
|
|
3329
|
+
color: #fafafa;
|
|
3330
|
+
font-size: 0.85rem;
|
|
3331
|
+
font-weight: 600;
|
|
3332
|
+
cursor: pointer;
|
|
3333
|
+
transition: opacity 0.15s ease;
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
[data-persona-root] .persona-ask-free-text-submit:disabled,
|
|
3337
|
+
[data-persona-root] .persona-ask-multi-submit:disabled {
|
|
3338
|
+
opacity: 0.4;
|
|
3339
|
+
cursor: not-allowed;
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
/* Nav row — Back / Skip / Next-or-Submit buttons for grouped payloads. */
|
|
3343
|
+
[data-persona-root] .persona-ask-nav-back,
|
|
3344
|
+
[data-persona-root] .persona-ask-nav-skip {
|
|
3345
|
+
padding: 0.45rem 0.85rem;
|
|
3346
|
+
border: 1px solid transparent;
|
|
3347
|
+
border-radius: 0.55rem;
|
|
3348
|
+
background: transparent;
|
|
3349
|
+
color: var(--persona-text-muted, #6b7280);
|
|
3350
|
+
font-size: 0.85rem;
|
|
3351
|
+
font-weight: 500;
|
|
3352
|
+
cursor: pointer;
|
|
3353
|
+
transition: background 0.15s ease, color 0.15s ease;
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
[data-persona-root] .persona-ask-nav-back:hover:not(:disabled),
|
|
3357
|
+
[data-persona-root] .persona-ask-nav-skip:hover:not(:disabled) {
|
|
3358
|
+
background: var(--persona-container, #f3f4f6);
|
|
3359
|
+
color: var(--persona-text, #1f2937);
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3362
|
+
[data-persona-root] .persona-ask-nav-back:disabled {
|
|
3363
|
+
opacity: 0.35;
|
|
3364
|
+
cursor: not-allowed;
|
|
3365
|
+
}
|
|
3366
|
+
|
|
3367
|
+
[data-persona-root] .persona-ask-nav-next {
|
|
3368
|
+
padding: 0.5rem 1rem;
|
|
3369
|
+
border: none;
|
|
3370
|
+
border-radius: 0.55rem;
|
|
3371
|
+
background: var(--persona-accent, #0f0f0f);
|
|
3372
|
+
color: #fafafa;
|
|
3373
|
+
font-size: 0.85rem;
|
|
3374
|
+
font-weight: 600;
|
|
3375
|
+
cursor: pointer;
|
|
3376
|
+
transition: opacity 0.15s ease;
|
|
3377
|
+
}
|
|
3378
|
+
|
|
3379
|
+
[data-persona-root] .persona-ask-nav-next:disabled {
|
|
3380
|
+
opacity: 0.4;
|
|
3381
|
+
cursor: not-allowed;
|
|
3382
|
+
}
|
|
3383
|
+
|
|
3384
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3385
|
+
[data-persona-root] .persona-ask-sheet,
|
|
3386
|
+
[data-persona-root] .persona-ask-pill-skeleton,
|
|
3387
|
+
[data-persona-root] .persona-ask-question-skeleton {
|
|
3388
|
+
transition: none !important;
|
|
3389
|
+
animation: none !important;
|
|
3390
|
+
}
|
|
3391
|
+
}
|