@smooai/chat-widget 0.7.0 → 0.9.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/chat-widget.global.js +11564 -3
- package/dist/chat-widget.global.js.map +1 -1
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +123 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/element.ts +119 -4
- package/src/styles.ts +18 -0
package/dist/index.d.ts
CHANGED
|
@@ -201,6 +201,20 @@ declare class SmoothAgentChatElement extends HTMLElement {
|
|
|
201
201
|
private buildRestoreCard;
|
|
202
202
|
/** Format an ISO timestamp as a short, locale-aware label (best-effort). */
|
|
203
203
|
private formatWhen;
|
|
204
|
+
/**
|
|
205
|
+
* Wire as-you-type formatting + an inline validity hint onto the pre-chat
|
|
206
|
+
* phone input (libphonenumber-js, US default region). Autofill is preserved:
|
|
207
|
+
* the input keeps its `type="tel"` + `autocomplete="tel"` + implicit <label>,
|
|
208
|
+
* and we also reformat on `change` so a browser-autofilled value gets
|
|
209
|
+
* formatted/validated too.
|
|
210
|
+
*
|
|
211
|
+
* As-you-type caret note: `AsYouType` reformats the entire string, which
|
|
212
|
+
* moves the caret to the end on a mid-string edit. To avoid fighting the
|
|
213
|
+
* user, we only rewrite the value when the caret is at the end (the typical
|
|
214
|
+
* append-a-digit case) and never on a deletion — so backspacing the
|
|
215
|
+
* formatting characters works naturally.
|
|
216
|
+
*/
|
|
217
|
+
private wirePhoneField;
|
|
204
218
|
/** Collect identity + consent from the pre-chat form, then drop into the chat view. */
|
|
205
219
|
private handlePrechatSubmit;
|
|
206
220
|
/** 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/loader-core.ts","../src/persistence.ts","../src/conversation.ts","../src/fingerprint.ts"],"mappings":";;;;;;;;AAOA;;;UAAiB,eAAA;EAEb;EAAA,IAAA;EAIA;EAFA,UAAA;EAMA;EAJA,OAAA;EAQA;EANA,WAAA;EAUA;EARA,SAAA;EAgBA;EAdA,eAAA;EAkBA;EAhBA,mBAAA;EAkBsB;EAhBtB,UAAA;EA2BQ;EAzBR,cAAA;;EAEA,MAAA;EAuBsB;EAjBtB,iBAAA;EAmB6B;EAjB7B,qBAAA;EAwFuB;EAtFvB,kBAAA;EAyBA;EAvBA,sBAAA;AAAA;;;;;;;;;KAWQ,cAAA;AAAA,UAEK,gBAAA;EAiCb;;;;EA5BA,QAAA;EAyCA;;;;EApCA,IAAA,GAAO,cAAA;EA6DP;EA3DA,OAAA;EA2DuB;EAzDvB,SAAA;;EAEA,QAAA;;EAEA,SAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/element.ts","../src/loader-core.ts","../src/persistence.ts","../src/conversation.ts","../src/fingerprint.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AsYouType, isValidPhoneNumber, parsePhoneNumber } from "libphonenumber-js/min";
|
|
1
2
|
import { ProtocolError, SmoothAgentClient } from "@smooai/smooth-operator";
|
|
2
3
|
import { createStore } from "zustand/vanilla";
|
|
3
4
|
import { persist } from "zustand/middleware";
|
|
@@ -1864,6 +1865,24 @@ function buildStyles(theme, mode = "popover") {
|
|
|
1864
1865
|
border-color: color-mix(in srgb, var(--sac-primary) 60%, transparent);
|
|
1865
1866
|
box-shadow: 0 0 0 4px color-mix(in srgb, var(--sac-primary) 14%, transparent);
|
|
1866
1867
|
}
|
|
1868
|
+
/* Inline phone validity — subtle, themed. Empty stays neutral (optional field). */
|
|
1869
|
+
.pc-field.valid input {
|
|
1870
|
+
border-color: color-mix(in srgb, var(--sac-primary) 55%, #2faa6a 45%);
|
|
1871
|
+
}
|
|
1872
|
+
.pc-field.invalid input {
|
|
1873
|
+
border-color: color-mix(in srgb, #e2566b 62%, var(--sac-border) 38%);
|
|
1874
|
+
}
|
|
1875
|
+
.pc-field.invalid input:focus {
|
|
1876
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, #e2566b 16%, transparent);
|
|
1877
|
+
}
|
|
1878
|
+
.pc-field .pc-hint {
|
|
1879
|
+
min-height: 13px;
|
|
1880
|
+
margin-top: 1px;
|
|
1881
|
+
font-size: 11.5px;
|
|
1882
|
+
font-weight: 500;
|
|
1883
|
+
line-height: 1.2;
|
|
1884
|
+
color: color-mix(in srgb, #e2566b 78%, var(--sac-text) 22%);
|
|
1885
|
+
}
|
|
1867
1886
|
.pc-submit {
|
|
1868
1887
|
margin-top: 4px;
|
|
1869
1888
|
border: none;
|
|
@@ -2034,7 +2053,46 @@ function buildStyles(theme, mode = "popover") {
|
|
|
2034
2053
|
}
|
|
2035
2054
|
//#endregion
|
|
2036
2055
|
//#region src/element.ts
|
|
2056
|
+
/**
|
|
2057
|
+
* `<smooth-agent-chat>` — a framework-light embeddable chat web component.
|
|
2058
|
+
*
|
|
2059
|
+
* A clean, dependency-light web component that preserves a familiar embedding
|
|
2060
|
+
* model — a launcher + popover panel, declarative HTML attributes, and a
|
|
2061
|
+
* programmatic API — while talking to the `@smooai/smooth-operator` protocol
|
|
2062
|
+
* client. The visual layer is the "Aurora Glass" design system (see
|
|
2063
|
+
* {@link buildStyles}): a spring launcher with a live presence pulse, a
|
|
2064
|
+
* glass-depth panel, a gradient brand avatar + status dot, an animated typing
|
|
2065
|
+
* indicator, message rise-in, refined source cards, and an icon composer. Every
|
|
2066
|
+
* color is driven by `--sac-*` custom properties so a host's brand flows through.
|
|
2067
|
+
*
|
|
2068
|
+
* Embedding model:
|
|
2069
|
+
* <smooth-agent-chat endpoint="ws://localhost:8787/ws" agent-id="…"></smooth-agent-chat>
|
|
2070
|
+
* or programmatically via {@link mountChatWidget}.
|
|
2071
|
+
*/
|
|
2037
2072
|
const ELEMENT_TAG = "smooth-agent-chat";
|
|
2073
|
+
/**
|
|
2074
|
+
* Default region for phone parsing/formatting on the pre-chat form. The widget
|
|
2075
|
+
* is US-first; the backend does the authoritative E.164 normalization (SMOODEV-2153),
|
|
2076
|
+
* so this only governs the as-you-type display + the inline validity hint and the
|
|
2077
|
+
* best-effort E.164 we send when the number already parses as valid.
|
|
2078
|
+
*/
|
|
2079
|
+
const PHONE_DEFAULT_REGION = "US";
|
|
2080
|
+
/**
|
|
2081
|
+
* Best-effort E.164 for an as-typed phone number. Returns the canonical
|
|
2082
|
+
* `+1…` form when the value parses to a valid number in {@link PHONE_DEFAULT_REGION},
|
|
2083
|
+
* otherwise `null` (caller falls back to sending the raw value — the backend
|
|
2084
|
+
* re-parses and normalizes/nulls authoritatively).
|
|
2085
|
+
*/
|
|
2086
|
+
function phoneToE164(value) {
|
|
2087
|
+
const v = value.trim();
|
|
2088
|
+
if (!v) return null;
|
|
2089
|
+
try {
|
|
2090
|
+
if (!isValidPhoneNumber(v, PHONE_DEFAULT_REGION)) return null;
|
|
2091
|
+
return parsePhoneNumber(v, PHONE_DEFAULT_REGION).number;
|
|
2092
|
+
} catch {
|
|
2093
|
+
return null;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2038
2096
|
const OBSERVED = [
|
|
2039
2097
|
"endpoint",
|
|
2040
2098
|
"agent-id",
|
|
@@ -2224,7 +2282,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2224
2282
|
const gating = needsUserInfo(resolved) && !this.userInfoSatisfied;
|
|
2225
2283
|
this.gating = gating;
|
|
2226
2284
|
const showPhone = resolved.requirePhone || resolved.collectPhone;
|
|
2227
|
-
const field = (name, type, label, autocomplete, required) => `<label class="pc-field"><span>${escapeHtml(label)}</span><input name="${name}" type="${type}" autocomplete="${autocomplete}"${required ? " required" : ""}
|
|
2285
|
+
const field = (name, type, label, autocomplete, required, hint = false) => `<label class="pc-field"><span>${escapeHtml(label)}</span><input name="${name}" type="${type}" autocomplete="${autocomplete}"${required ? " required" : ""} />${hint ? "<span class=\"pc-hint\" aria-live=\"polite\"></span>" : ""}</label>`;
|
|
2228
2286
|
const consentBox = (name, label) => `<label class="pc-consent"><input name="${name}" type="checkbox" /><span>${escapeHtml(label)}</span></label>`;
|
|
2229
2287
|
const consentHtml = resolved.collectConsent ? `<div class="pc-consents">
|
|
2230
2288
|
${consentBox("emailOptIn", "Email me product news and offers.")}
|
|
@@ -2239,7 +2297,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2239
2297
|
<form class="pc-form" novalidate>
|
|
2240
2298
|
${resolved.requireName ? field("name", "text", "Name", "name", true) : ""}
|
|
2241
2299
|
${resolved.requireEmail ? field("email", "email", "Email", "email", true) : ""}
|
|
2242
|
-
${showPhone ? field("phone", "tel", "Phone", "tel", resolved.requirePhone) : ""}
|
|
2300
|
+
${showPhone ? field("phone", "tel", "Phone", "tel", resolved.requirePhone, true) : ""}
|
|
2243
2301
|
${consentHtml}
|
|
2244
2302
|
<button type="submit" class="pc-submit">Start chat</button>
|
|
2245
2303
|
</form>
|
|
@@ -2291,6 +2349,7 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2291
2349
|
ev.preventDefault();
|
|
2292
2350
|
this.handlePrechatSubmit(pcForm);
|
|
2293
2351
|
});
|
|
2352
|
+
this.wirePhoneField(pcForm);
|
|
2294
2353
|
container.querySelector(".restore-link")?.addEventListener("click", () => {
|
|
2295
2354
|
(async () => {
|
|
2296
2355
|
this.identityRestore = { phase: "awaiting_email" };
|
|
@@ -2566,16 +2625,77 @@ var SmoothAgentChatElement = class extends HTMLElement {
|
|
|
2566
2625
|
return "";
|
|
2567
2626
|
}
|
|
2568
2627
|
}
|
|
2628
|
+
/**
|
|
2629
|
+
* Wire as-you-type formatting + an inline validity hint onto the pre-chat
|
|
2630
|
+
* phone input (libphonenumber-js, US default region). Autofill is preserved:
|
|
2631
|
+
* the input keeps its `type="tel"` + `autocomplete="tel"` + implicit <label>,
|
|
2632
|
+
* and we also reformat on `change` so a browser-autofilled value gets
|
|
2633
|
+
* formatted/validated too.
|
|
2634
|
+
*
|
|
2635
|
+
* As-you-type caret note: `AsYouType` reformats the entire string, which
|
|
2636
|
+
* moves the caret to the end on a mid-string edit. To avoid fighting the
|
|
2637
|
+
* user, we only rewrite the value when the caret is at the end (the typical
|
|
2638
|
+
* append-a-digit case) and never on a deletion — so backspacing the
|
|
2639
|
+
* formatting characters works naturally.
|
|
2640
|
+
*/
|
|
2641
|
+
wirePhoneField(form) {
|
|
2642
|
+
const input = form?.querySelector("input[name=\"phone\"]");
|
|
2643
|
+
if (!input) return;
|
|
2644
|
+
const hint = input.parentElement?.querySelector(".pc-hint");
|
|
2645
|
+
const updateHint = () => {
|
|
2646
|
+
const v = input.value.trim();
|
|
2647
|
+
const field = input.closest(".pc-field");
|
|
2648
|
+
if (!v) {
|
|
2649
|
+
field?.classList.remove("valid", "invalid");
|
|
2650
|
+
if (hint) hint.textContent = "";
|
|
2651
|
+
return;
|
|
2652
|
+
}
|
|
2653
|
+
const ok = isValidPhoneNumber(v, PHONE_DEFAULT_REGION);
|
|
2654
|
+
field?.classList.toggle("valid", ok);
|
|
2655
|
+
field?.classList.toggle("invalid", !ok);
|
|
2656
|
+
if (hint) hint.textContent = ok ? "" : "Enter a valid phone number";
|
|
2657
|
+
};
|
|
2658
|
+
const reformat = () => {
|
|
2659
|
+
if (input.selectionStart === input.value.length && input.selectionEnd === input.value.length) {
|
|
2660
|
+
const formatted = new AsYouType(PHONE_DEFAULT_REGION).input(input.value);
|
|
2661
|
+
if (formatted.length >= input.value.length) input.value = formatted;
|
|
2662
|
+
}
|
|
2663
|
+
updateHint();
|
|
2664
|
+
};
|
|
2665
|
+
input.addEventListener("input", (ev) => {
|
|
2666
|
+
const ie = ev;
|
|
2667
|
+
if (typeof ie.inputType === "string" && ie.inputType.startsWith("delete")) {
|
|
2668
|
+
updateHint();
|
|
2669
|
+
return;
|
|
2670
|
+
}
|
|
2671
|
+
reformat();
|
|
2672
|
+
});
|
|
2673
|
+
input.addEventListener("change", reformat);
|
|
2674
|
+
}
|
|
2569
2675
|
/** Collect identity + consent from the pre-chat form, then drop into the chat view. */
|
|
2570
2676
|
handlePrechatSubmit(form) {
|
|
2571
2677
|
if (!form.reportValidity()) return;
|
|
2572
2678
|
const data = new FormData(form);
|
|
2573
2679
|
const val = (k) => data.get(k)?.trim() || void 0;
|
|
2574
2680
|
const checked = (k) => data.get(k) === "on";
|
|
2681
|
+
const rawPhone = val("phone");
|
|
2682
|
+
const phoneInput = form.querySelector("input[name=\"phone\"]");
|
|
2683
|
+
if (rawPhone && phoneInput && !isValidPhoneNumber(rawPhone, PHONE_DEFAULT_REGION)) {
|
|
2684
|
+
const required = phoneInput.hasAttribute("required");
|
|
2685
|
+
const field = phoneInput.closest(".pc-field");
|
|
2686
|
+
field?.classList.add("invalid");
|
|
2687
|
+
const hint = field?.querySelector(".pc-hint");
|
|
2688
|
+
if (hint) hint.textContent = "Enter a valid phone number";
|
|
2689
|
+
if (required) {
|
|
2690
|
+
phoneInput.focus();
|
|
2691
|
+
return;
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
const phone = rawPhone ? phoneToE164(rawPhone) ?? rawPhone : void 0;
|
|
2575
2695
|
this.controller?.setUserInfo({
|
|
2576
2696
|
name: val("name"),
|
|
2577
2697
|
email: val("email"),
|
|
2578
|
-
phone
|
|
2698
|
+
phone,
|
|
2579
2699
|
consent: {
|
|
2580
2700
|
emailOptIn: checked("emailOptIn"),
|
|
2581
2701
|
smsOptIn: checked("smsOptIn")
|