@smooai/chat-widget 0.3.0 → 0.4.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 +9 -6
- package/dist/chat-widget.global.js +162 -1
- package/dist/chat-widget.global.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +162 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/element.ts +111 -1
- package/src/styles.ts +57 -0
package/dist/index.d.ts
CHANGED
|
@@ -113,6 +113,9 @@ declare class SmoothAgentChatElement extends HTMLElement {
|
|
|
113
113
|
private hasSent;
|
|
114
114
|
/** Starter prompts shown as chips in the empty state. */
|
|
115
115
|
private examplePrompts;
|
|
116
|
+
/** Current mid-turn interrupt (OTP / tool-confirmation), or null. */
|
|
117
|
+
private interrupt;
|
|
118
|
+
private interruptEl;
|
|
116
119
|
private panelEl;
|
|
117
120
|
private launcherEl;
|
|
118
121
|
private messagesEl;
|
|
@@ -135,6 +138,12 @@ declare class SmoothAgentChatElement extends HTMLElement {
|
|
|
135
138
|
closeChat(): void;
|
|
136
139
|
private readConfig;
|
|
137
140
|
private render;
|
|
141
|
+
/**
|
|
142
|
+
* Render (or clear) the mid-turn interrupt overlay above the composer:
|
|
143
|
+
* an OTP code prompt or a tool-write confirmation. Server-supplied text is
|
|
144
|
+
* set via `textContent` (never innerHTML); only static icons use innerHTML.
|
|
145
|
+
*/
|
|
146
|
+
private renderInterrupt;
|
|
138
147
|
/** Collect identity from the pre-chat form, then drop into the chat view. */
|
|
139
148
|
private handlePrechatSubmit;
|
|
140
149
|
/** Send a starter prompt (from a chip click). */
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/element.ts","../src/conversation.ts"],"mappings":";;;;;;AAOA;;;;UAAiB,eAAA;EAIb;EAFA,IAAA;EAMA;EAJA,UAAA;EAQA;EANA,OAAA;EAUA;EARA,WAAA;EAYA;EAVA,SAAA;EAkBA;EAhBA,eAAA;EAoBA;EAlBA,mBAAA;EAkBsB;EAhBtB,UAAA;EA2BsB;EAzBtB,cAAA;EAyBsB;EAvBtB,MAAA;EAyBa;EAnBb,iBAAA;;EAEA,qBAAA;EAsBA;EApBA,kBAAA;EAyBO;EAvBP,sBAAA;AAAA;;;;;;;;;KAWQ,cAAA;AAAA,UAEK,gBAAA;EAuCb;;;;EAlCA,QAAA;EAyCuB;;;;EApCvB,IAAA,GAAO,cAAA;ECxCa;ED0CpB,OAAA;EC1CoB;ED4CpB,SAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/element.ts","../src/conversation.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -820,6 +820,63 @@ function buildStyles(theme, mode = "popover") {
|
|
|
820
820
|
transform: translateY(-1px);
|
|
821
821
|
}
|
|
822
822
|
|
|
823
|
+
/* ─────────────── OTP / tool-confirmation interrupt ────────────────── */
|
|
824
|
+
.interrupt { padding: 0 14px; }
|
|
825
|
+
.int-card {
|
|
826
|
+
border: 1px solid color-mix(in srgb, var(--sac-primary) 35%, var(--sac-border));
|
|
827
|
+
background: color-mix(in srgb, var(--sac-primary) 8%, var(--sac-surface-2));
|
|
828
|
+
border-radius: 14px;
|
|
829
|
+
padding: 12px 13px;
|
|
830
|
+
animation: sac-msg-in .3s var(--sac-ease) both;
|
|
831
|
+
}
|
|
832
|
+
.int-head { display: flex; align-items: center; gap: 8px; }
|
|
833
|
+
.int-ico { display: flex; color: var(--sac-primary); }
|
|
834
|
+
.int-ico svg { width: 17px; height: 17px; }
|
|
835
|
+
.int-title { font-size: 13.5px; font-weight: 650; }
|
|
836
|
+
.int-desc { margin-top: 5px; font-size: 12.5px; line-height: 1.45; color: color-mix(in srgb, var(--sac-text) 80%, transparent); }
|
|
837
|
+
.int-sent { margin-top: 6px; font-size: 11.5px; color: color-mix(in srgb, var(--sac-text) 60%, transparent); }
|
|
838
|
+
.int-row { display: flex; gap: 8px; margin-top: 10px; }
|
|
839
|
+
.int-input {
|
|
840
|
+
flex: 1;
|
|
841
|
+
min-width: 0;
|
|
842
|
+
border: 1px solid color-mix(in srgb, var(--sac-border) 80%, transparent);
|
|
843
|
+
background: var(--sac-bg);
|
|
844
|
+
color: var(--sac-text);
|
|
845
|
+
border-radius: 10px;
|
|
846
|
+
padding: 9px 11px;
|
|
847
|
+
font-family: inherit;
|
|
848
|
+
font-size: 14px;
|
|
849
|
+
letter-spacing: .14em;
|
|
850
|
+
outline: none;
|
|
851
|
+
transition: border-color .2s ease, box-shadow .2s ease;
|
|
852
|
+
}
|
|
853
|
+
.int-input:focus {
|
|
854
|
+
border-color: color-mix(in srgb, var(--sac-primary) 60%, transparent);
|
|
855
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--sac-primary) 14%, transparent);
|
|
856
|
+
}
|
|
857
|
+
.int-btn {
|
|
858
|
+
border: 1px solid color-mix(in srgb, var(--sac-border) 80%, transparent);
|
|
859
|
+
background: var(--sac-surface-2);
|
|
860
|
+
color: var(--sac-text);
|
|
861
|
+
border-radius: 10px;
|
|
862
|
+
padding: 9px 14px;
|
|
863
|
+
font-family: inherit;
|
|
864
|
+
font-size: 13px;
|
|
865
|
+
font-weight: 600;
|
|
866
|
+
cursor: pointer;
|
|
867
|
+
transition: transform .2s var(--sac-ease), background .2s ease, border-color .2s ease;
|
|
868
|
+
}
|
|
869
|
+
.int-btn:hover { transform: translateY(-1px); }
|
|
870
|
+
.int-btn.primary {
|
|
871
|
+
border: none;
|
|
872
|
+
background: linear-gradient(150deg, var(--sac-primary), var(--sac-primary-2));
|
|
873
|
+
color: var(--sac-primary-text);
|
|
874
|
+
box-shadow: 0 6px 14px -6px color-mix(in srgb, var(--sac-primary) 65%, transparent);
|
|
875
|
+
}
|
|
876
|
+
.int-row .int-btn { flex: 1; }
|
|
877
|
+
.int-row .int-input + .int-btn { flex: 0 0 auto; }
|
|
878
|
+
.int-error { margin-top: 8px; font-size: 12px; color: #f87171; }
|
|
879
|
+
|
|
823
880
|
.hidden { display: none !important; }
|
|
824
881
|
|
|
825
882
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -854,7 +911,11 @@ const ICON = {
|
|
|
854
911
|
/** Send — an upward arrow. */
|
|
855
912
|
send: `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 19V6M12 6l-5.5 5.5M12 6l5.5 5.5" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
856
913
|
/** Sources disclosure caret. */
|
|
857
|
-
chev: `<svg width="11" height="11" viewBox="0 0 24 24" fill="none"><path d="m9 6 6 6-6 6" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg
|
|
914
|
+
chev: `<svg width="11" height="11" viewBox="0 0 24 24" fill="none"><path d="m9 6 6 6-6 6" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
915
|
+
/** OTP interrupt — a padlock. */
|
|
916
|
+
lock: `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="5" y="10.5" width="14" height="9.5" rx="2.2" stroke="currentColor" stroke-width="1.7"/><path d="M8 10.5V8a4 4 0 0 1 8 0v2.5" stroke="currentColor" stroke-width="1.7"/></svg>`,
|
|
917
|
+
/** Tool-confirmation interrupt — a shield. */
|
|
918
|
+
shield: `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3 5 6v5c0 4.4 3 7.2 7 8.5 4-1.3 7-4.1 7-8.5V6l-7-3Z" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/><path d="m9 11.5 2 2 4-4" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg>`
|
|
858
919
|
};
|
|
859
920
|
/**
|
|
860
921
|
* Return `url` only if it is a valid absolute `http(s)` URL, else `null`.
|
|
@@ -891,6 +952,9 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
891
952
|
hasSent = false;
|
|
892
953
|
/** Starter prompts shown as chips in the empty state. */
|
|
893
954
|
examplePrompts = [];
|
|
955
|
+
/** Current mid-turn interrupt (OTP / tool-confirmation), or null. */
|
|
956
|
+
interrupt = null;
|
|
957
|
+
interruptEl = null;
|
|
894
958
|
panelEl = null;
|
|
895
959
|
launcherEl = null;
|
|
896
960
|
messagesEl = null;
|
|
@@ -983,6 +1047,10 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
983
1047
|
this.status = status;
|
|
984
1048
|
this.renderStatus();
|
|
985
1049
|
this.renderComposerState();
|
|
1050
|
+
},
|
|
1051
|
+
onInterrupt: (interrupt) => {
|
|
1052
|
+
this.interrupt = interrupt;
|
|
1053
|
+
this.renderInterrupt();
|
|
986
1054
|
}
|
|
987
1055
|
});
|
|
988
1056
|
if (resolved.startOpen) this.open = true;
|
|
@@ -1025,6 +1093,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
1025
1093
|
</div>`;
|
|
1026
1094
|
const chatHtml = `
|
|
1027
1095
|
<div class="messages"></div>
|
|
1096
|
+
<div class="interrupt hidden"></div>
|
|
1028
1097
|
<div class="composer-wrap">
|
|
1029
1098
|
<div class="composer">
|
|
1030
1099
|
<textarea rows="1" placeholder="${escapeHtml(resolved.placeholder)}"></textarea>
|
|
@@ -1051,6 +1120,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
1051
1120
|
this.dotEl = container.querySelector(".dot");
|
|
1052
1121
|
this.inputEl = container.querySelector("textarea");
|
|
1053
1122
|
this.sendBtn = container.querySelector(".send");
|
|
1123
|
+
this.interruptEl = container.querySelector(".interrupt");
|
|
1054
1124
|
this.launcherEl?.addEventListener("click", () => this.openChat());
|
|
1055
1125
|
container.querySelector(".close")?.addEventListener("click", () => this.closeChat());
|
|
1056
1126
|
this.sendBtn?.addEventListener("click", () => this.submit());
|
|
@@ -1071,6 +1141,97 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
1071
1141
|
if (!gating) this.renderMessages(resolved.greeting);
|
|
1072
1142
|
this.renderStatus();
|
|
1073
1143
|
this.renderComposerState();
|
|
1144
|
+
this.renderInterrupt();
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Render (or clear) the mid-turn interrupt overlay above the composer:
|
|
1148
|
+
* an OTP code prompt or a tool-write confirmation. Server-supplied text is
|
|
1149
|
+
* set via `textContent` (never innerHTML); only static icons use innerHTML.
|
|
1150
|
+
*/
|
|
1151
|
+
renderInterrupt() {
|
|
1152
|
+
const el = this.interruptEl;
|
|
1153
|
+
if (!el) return;
|
|
1154
|
+
el.replaceChildren();
|
|
1155
|
+
const it = this.interrupt;
|
|
1156
|
+
if (!it) {
|
|
1157
|
+
el.classList.add("hidden");
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
el.classList.remove("hidden");
|
|
1161
|
+
const card = document.createElement("div");
|
|
1162
|
+
card.className = "int-card";
|
|
1163
|
+
const head = document.createElement("div");
|
|
1164
|
+
head.className = "int-head";
|
|
1165
|
+
const ico = document.createElement("span");
|
|
1166
|
+
ico.className = "int-ico";
|
|
1167
|
+
ico.innerHTML = it.kind === "otp" ? ICON.lock : ICON.shield;
|
|
1168
|
+
const title = document.createElement("span");
|
|
1169
|
+
title.className = "int-title";
|
|
1170
|
+
title.textContent = it.kind === "otp" ? "Verification required" : "Confirm this action";
|
|
1171
|
+
head.append(ico, title);
|
|
1172
|
+
card.appendChild(head);
|
|
1173
|
+
if (it.actionDescription) {
|
|
1174
|
+
const desc = document.createElement("div");
|
|
1175
|
+
desc.className = "int-desc";
|
|
1176
|
+
desc.textContent = it.actionDescription;
|
|
1177
|
+
card.appendChild(desc);
|
|
1178
|
+
}
|
|
1179
|
+
if (it.kind === "otp") {
|
|
1180
|
+
if (it.sent?.maskedDestination) {
|
|
1181
|
+
const sent = document.createElement("div");
|
|
1182
|
+
sent.className = "int-sent";
|
|
1183
|
+
sent.textContent = `Code sent to ${it.sent.maskedDestination}${it.sent.channel ? ` via ${it.sent.channel}` : ""}.`;
|
|
1184
|
+
card.appendChild(sent);
|
|
1185
|
+
}
|
|
1186
|
+
const row = document.createElement("div");
|
|
1187
|
+
row.className = "int-row";
|
|
1188
|
+
const input = document.createElement("input");
|
|
1189
|
+
input.className = "int-input";
|
|
1190
|
+
input.type = "text";
|
|
1191
|
+
input.inputMode = "numeric";
|
|
1192
|
+
input.autocomplete = "one-time-code";
|
|
1193
|
+
input.placeholder = "Enter code";
|
|
1194
|
+
const submit = () => {
|
|
1195
|
+
const code = input.value.trim();
|
|
1196
|
+
if (code) this.controller?.verifyOtp(code);
|
|
1197
|
+
};
|
|
1198
|
+
input.addEventListener("keydown", (ev) => {
|
|
1199
|
+
if (ev.key === "Enter") {
|
|
1200
|
+
ev.preventDefault();
|
|
1201
|
+
submit();
|
|
1202
|
+
}
|
|
1203
|
+
});
|
|
1204
|
+
const verify = document.createElement("button");
|
|
1205
|
+
verify.className = "int-btn primary";
|
|
1206
|
+
verify.type = "button";
|
|
1207
|
+
verify.textContent = "Verify";
|
|
1208
|
+
verify.addEventListener("click", submit);
|
|
1209
|
+
row.append(input, verify);
|
|
1210
|
+
card.appendChild(row);
|
|
1211
|
+
if (it.error) {
|
|
1212
|
+
const err = document.createElement("div");
|
|
1213
|
+
err.className = "int-error";
|
|
1214
|
+
err.textContent = it.attemptsRemaining != null ? `${it.error} (${it.attemptsRemaining} left)` : it.error;
|
|
1215
|
+
card.appendChild(err);
|
|
1216
|
+
}
|
|
1217
|
+
queueMicrotask(() => input.focus());
|
|
1218
|
+
} else {
|
|
1219
|
+
const row = document.createElement("div");
|
|
1220
|
+
row.className = "int-row";
|
|
1221
|
+
const decline = document.createElement("button");
|
|
1222
|
+
decline.className = "int-btn";
|
|
1223
|
+
decline.type = "button";
|
|
1224
|
+
decline.textContent = "Decline";
|
|
1225
|
+
decline.addEventListener("click", () => this.controller?.confirmTool(false));
|
|
1226
|
+
const approve = document.createElement("button");
|
|
1227
|
+
approve.className = "int-btn primary";
|
|
1228
|
+
approve.type = "button";
|
|
1229
|
+
approve.textContent = "Approve";
|
|
1230
|
+
approve.addEventListener("click", () => this.controller?.confirmTool(true));
|
|
1231
|
+
row.append(decline, approve);
|
|
1232
|
+
card.appendChild(row);
|
|
1233
|
+
}
|
|
1234
|
+
el.appendChild(card);
|
|
1074
1235
|
}
|
|
1075
1236
|
/** Collect identity from the pre-chat form, then drop into the chat view. */
|
|
1076
1237
|
handlePrechatSubmit(form) {
|