@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/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). */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/element.ts","../src/conversation.ts"],"mappings":"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"}
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) {