@webless/agent 0.7.0 → 0.7.3
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/{chunk-CYI3OSWG.js → chunk-GS65OJFL.js} +346 -141
- package/dist/chunk-GS65OJFL.js.map +1 -0
- package/dist/embed.cjs +352 -132
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.css +108 -8
- package/dist/embed.css.map +1 -1
- package/dist/embed.d.cts +2 -2
- package/dist/embed.d.ts +2 -2
- package/dist/embed.js +16 -1
- package/dist/embed.js.map +1 -1
- package/dist/{manifest-BNJQfEow.d.cts → manifest-sR_C4rh_.d.cts} +1 -0
- package/dist/{manifest-BNJQfEow.d.ts → manifest-sR_C4rh_.d.ts} +1 -0
- package/dist/react.cjs +337 -132
- package/dist/react.cjs.map +1 -1
- package/dist/react.css +108 -8
- package/dist/react.css.map +1 -1
- package/dist/react.d.cts +4 -3
- package/dist/react.d.ts +4 -3
- package/dist/react.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-CYI3OSWG.js.map +0 -1
package/dist/embed.cjs
CHANGED
|
@@ -3804,42 +3804,72 @@ function emptyValues(form) {
|
|
|
3804
3804
|
for (const field of form?.fields ?? []) values[field.id] = "";
|
|
3805
3805
|
return values;
|
|
3806
3806
|
}
|
|
3807
|
+
function createDraft(form) {
|
|
3808
|
+
return {
|
|
3809
|
+
form,
|
|
3810
|
+
values: emptyValues(form),
|
|
3811
|
+
expanded: Boolean(form),
|
|
3812
|
+
submitted: false,
|
|
3813
|
+
dismissalSent: false,
|
|
3814
|
+
attempted: false
|
|
3815
|
+
};
|
|
3816
|
+
}
|
|
3807
3817
|
function Composer({
|
|
3808
3818
|
disabled = false,
|
|
3809
3819
|
placeholder = "Ask anything\u2026",
|
|
3810
3820
|
variant = "default",
|
|
3811
3821
|
form = null,
|
|
3822
|
+
allowFormResume = true,
|
|
3812
3823
|
onSubmit
|
|
3813
3824
|
}) {
|
|
3814
3825
|
const [value, setValue] = (0, import_react8.useState)("");
|
|
3815
|
-
const [
|
|
3816
|
-
() => emptyValues(form)
|
|
3817
|
-
);
|
|
3818
|
-
const [blurred, setBlurred] = (0, import_react8.useState)({});
|
|
3826
|
+
const [draft, setDraft] = (0, import_react8.useState)(() => createDraft(form));
|
|
3819
3827
|
const inputRef = (0, import_react8.useRef)(null);
|
|
3820
3828
|
const firstFieldRef = (0, import_react8.useRef)(null);
|
|
3829
|
+
const formRef = (0, import_react8.useRef)(null);
|
|
3821
3830
|
const formId = (0, import_react8.useId)();
|
|
3822
|
-
|
|
3823
|
-
const
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
setBlurred({});
|
|
3827
|
-
}, [form?.id]);
|
|
3831
|
+
if (form && form.id !== draft.form?.id) setDraft(createDraft(form));
|
|
3832
|
+
const savedForm = allowFormResume && !draft.submitted ? draft.form : null;
|
|
3833
|
+
const activeForm = !disabled && draft.expanded ? savedForm : null;
|
|
3834
|
+
const hasDraft = Object.values(draft.values).some((value2) => value2.trim());
|
|
3828
3835
|
(0, import_react8.useEffect)(() => {
|
|
3829
3836
|
if (activeForm) firstFieldRef.current?.focus();
|
|
3830
|
-
|
|
3837
|
+
else if ((savedForm || draft.submitted) && !disabled)
|
|
3838
|
+
inputRef.current?.focus();
|
|
3839
|
+
}, [activeForm?.id, disabled, savedForm?.id, draft.submitted]);
|
|
3831
3840
|
function submitChat() {
|
|
3832
3841
|
const trimmed = value.trim();
|
|
3833
3842
|
if (!trimmed || disabled) return;
|
|
3834
|
-
|
|
3843
|
+
const shareDismissal = savedForm && !draft.dismissalSent;
|
|
3844
|
+
onSubmit?.(
|
|
3845
|
+
shareDismissal ? `I'd like to keep chatting without sharing the requested details for now. Please don't ask for them again unless I choose to proceed with something that needs them.
|
|
3846
|
+
|
|
3847
|
+
${trimmed}` : trimmed
|
|
3848
|
+
);
|
|
3849
|
+
if (shareDismissal)
|
|
3850
|
+
setDraft((current) => ({ ...current, dismissalSent: true }));
|
|
3835
3851
|
setValue("");
|
|
3836
3852
|
inputRef.current?.focus();
|
|
3837
3853
|
}
|
|
3838
3854
|
function submitForm() {
|
|
3839
|
-
if (!activeForm || disabled
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3855
|
+
if (!activeForm || disabled) return;
|
|
3856
|
+
if (!isComposerFormComplete(activeForm, draft.values)) {
|
|
3857
|
+
setDraft((current) => ({ ...current, attempted: true }));
|
|
3858
|
+
const invalidField = activeForm.fields.find(
|
|
3859
|
+
(field) => !isValidComposerFieldValue(field, draft.values[field.id] ?? "")
|
|
3860
|
+
);
|
|
3861
|
+
const control = invalidField && formRef.current?.elements.namedItem(invalidField.id);
|
|
3862
|
+
if (control instanceof HTMLElement) control.focus();
|
|
3863
|
+
return;
|
|
3864
|
+
}
|
|
3865
|
+
onSubmit?.(formatComposerFormMessage(activeForm, draft.values));
|
|
3866
|
+
setDraft((current) => ({
|
|
3867
|
+
...current,
|
|
3868
|
+
values: emptyValues(activeForm),
|
|
3869
|
+
expanded: false,
|
|
3870
|
+
submitted: true,
|
|
3871
|
+
attempted: false
|
|
3872
|
+
}));
|
|
3843
3873
|
}
|
|
3844
3874
|
function handleSubmit(event) {
|
|
3845
3875
|
event.preventDefault();
|
|
@@ -3863,112 +3893,151 @@ function Composer({
|
|
|
3863
3893
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3864
3894
|
"form",
|
|
3865
3895
|
{
|
|
3896
|
+
ref: formRef,
|
|
3897
|
+
noValidate: true,
|
|
3866
3898
|
className: [
|
|
3867
3899
|
"composer",
|
|
3868
3900
|
variant === "dock" ? "composer--dock" : "",
|
|
3869
3901
|
activeForm ? "composer--form" : ""
|
|
3870
3902
|
].filter(Boolean).join(" "),
|
|
3871
3903
|
onSubmit: handleSubmit,
|
|
3872
|
-
children: activeForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3904
|
+
children: activeForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3905
|
+
"div",
|
|
3906
|
+
{
|
|
3907
|
+
className: "composer__sheet",
|
|
3908
|
+
role: "group",
|
|
3909
|
+
"aria-label": "Contact details",
|
|
3910
|
+
children: [
|
|
3911
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__form-heading", children: [
|
|
3912
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Share your details" }),
|
|
3913
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Optional" }),
|
|
3914
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: "You can also keep chatting." })
|
|
3915
|
+
] }),
|
|
3916
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__fields", children: activeForm.fields.map((field, index) => {
|
|
3917
|
+
const fieldId = `${formId}-${field.id}`;
|
|
3918
|
+
const invalid = draft.attempted && !isValidComposerFieldValue(field, draft.values[field.id] ?? "");
|
|
3919
|
+
const controlProps = {
|
|
3920
|
+
id: fieldId,
|
|
3921
|
+
name: field.id,
|
|
3922
|
+
disabled,
|
|
3923
|
+
required: field.required,
|
|
3924
|
+
autoComplete: field.autocomplete,
|
|
3925
|
+
placeholder: field.placeholder,
|
|
3926
|
+
spellCheck: false,
|
|
3927
|
+
value: draft.values[field.id] ?? "",
|
|
3928
|
+
"aria-invalid": invalid || void 0,
|
|
3929
|
+
"aria-describedby": invalid ? `${fieldId}-error` : void 0,
|
|
3930
|
+
onChange: (event) => {
|
|
3931
|
+
const next = readComposerControlValue(event);
|
|
3932
|
+
setDraft((current) => ({
|
|
3933
|
+
...current,
|
|
3934
|
+
values: { ...current.values, [field.id]: next }
|
|
3935
|
+
}));
|
|
3936
|
+
},
|
|
3937
|
+
onKeyDown: handleFormKeyDown
|
|
3938
|
+
};
|
|
3939
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3940
|
+
"div",
|
|
3941
|
+
{
|
|
3942
|
+
className: [
|
|
3943
|
+
"composer__row",
|
|
3944
|
+
field.kind === "textarea" ? "composer__row--grow" : ""
|
|
3945
|
+
].filter(Boolean).join(" "),
|
|
3946
|
+
children: [
|
|
3947
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "composer__label", htmlFor: fieldId, children: [
|
|
3948
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "composer__field-label", children: field.label }),
|
|
3949
|
+
field.kind === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3950
|
+
"textarea",
|
|
3951
|
+
{
|
|
3952
|
+
...controlProps,
|
|
3953
|
+
ref: index === 0 ? (node) => {
|
|
3954
|
+
firstFieldRef.current = node;
|
|
3955
|
+
} : void 0,
|
|
3956
|
+
className: "composer__control composer__control--area",
|
|
3957
|
+
rows: 3
|
|
3958
|
+
}
|
|
3959
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3960
|
+
"input",
|
|
3961
|
+
{
|
|
3962
|
+
...controlProps,
|
|
3963
|
+
ref: index === 0 ? (node) => {
|
|
3964
|
+
firstFieldRef.current = node;
|
|
3965
|
+
} : void 0,
|
|
3966
|
+
className: "composer__control",
|
|
3967
|
+
type: field.kind,
|
|
3968
|
+
inputMode: field.kind === "tel" ? "tel" : void 0
|
|
3969
|
+
}
|
|
3970
|
+
)
|
|
3971
|
+
] }),
|
|
3972
|
+
invalid ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "composer__error", id: `${fieldId}-error`, children: field.kind === "email" ? "Enter a valid email to share your details." : `Add your ${field.label.toLowerCase()} to share your details.` }) : null
|
|
3973
|
+
]
|
|
3974
|
+
},
|
|
3975
|
+
field.id
|
|
3976
|
+
);
|
|
3977
|
+
}) }),
|
|
3978
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__toolbar", children: [
|
|
3979
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3980
|
+
"button",
|
|
3981
|
+
{
|
|
3982
|
+
type: "submit",
|
|
3983
|
+
className: "composer__action composer__action--primary",
|
|
3984
|
+
disabled,
|
|
3985
|
+
children: "Share details"
|
|
3986
|
+
}
|
|
3987
|
+
),
|
|
3988
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3989
|
+
"button",
|
|
3990
|
+
{
|
|
3991
|
+
type: "button",
|
|
3992
|
+
className: "composer__action",
|
|
3993
|
+
disabled,
|
|
3994
|
+
onClick: () => setDraft((current) => ({ ...current, expanded: false })),
|
|
3995
|
+
children: "Keep chatting"
|
|
3996
|
+
}
|
|
3997
|
+
)
|
|
3998
|
+
] })
|
|
3999
|
+
]
|
|
4000
|
+
}
|
|
4001
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
4002
|
+
savedForm ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__resume", children: [
|
|
4003
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: hasDraft ? "Your details aren\u2019t shared yet" : "Contact details are optional" }),
|
|
4004
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
4005
|
+
"button",
|
|
3899
4006
|
{
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
);
|
|
3935
|
-
}),
|
|
3936
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "composer__toolbar", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3937
|
-
"button",
|
|
3938
|
-
{
|
|
3939
|
-
type: "submit",
|
|
3940
|
-
className: "composer__send",
|
|
3941
|
-
disabled: disabled || !canSendForm,
|
|
3942
|
-
"aria-label": "Send details",
|
|
3943
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
|
|
3944
|
-
}
|
|
3945
|
-
) })
|
|
3946
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__field", children: [
|
|
3947
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3948
|
-
"textarea",
|
|
3949
|
-
{
|
|
3950
|
-
ref: inputRef,
|
|
3951
|
-
className: "composer__input",
|
|
3952
|
-
rows: 1,
|
|
3953
|
-
value,
|
|
3954
|
-
placeholder,
|
|
3955
|
-
disabled,
|
|
3956
|
-
spellCheck: false,
|
|
3957
|
-
"aria-label": "Message",
|
|
3958
|
-
onChange: (event) => setValue(event.target.value),
|
|
3959
|
-
onKeyDown: handleChatKeyDown
|
|
3960
|
-
}
|
|
3961
|
-
),
|
|
3962
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3963
|
-
"button",
|
|
3964
|
-
{
|
|
3965
|
-
type: "submit",
|
|
3966
|
-
className: "composer__send",
|
|
3967
|
-
disabled: disabled || !value.trim(),
|
|
3968
|
-
"aria-label": "Send message",
|
|
3969
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
|
|
3970
|
-
}
|
|
3971
|
-
)
|
|
4007
|
+
type: "button",
|
|
4008
|
+
disabled,
|
|
4009
|
+
onClick: () => setDraft((current) => ({ ...current, expanded: true })),
|
|
4010
|
+
children: hasDraft ? "Resume details" : "Add details"
|
|
4011
|
+
}
|
|
4012
|
+
)
|
|
4013
|
+
] }) : null,
|
|
4014
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__field", children: [
|
|
4015
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
4016
|
+
"textarea",
|
|
4017
|
+
{
|
|
4018
|
+
ref: inputRef,
|
|
4019
|
+
className: "composer__input",
|
|
4020
|
+
rows: 1,
|
|
4021
|
+
value,
|
|
4022
|
+
placeholder,
|
|
4023
|
+
disabled,
|
|
4024
|
+
spellCheck: false,
|
|
4025
|
+
"aria-label": "Message",
|
|
4026
|
+
onChange: (event) => setValue(event.target.value),
|
|
4027
|
+
onKeyDown: handleChatKeyDown
|
|
4028
|
+
}
|
|
4029
|
+
),
|
|
4030
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
4031
|
+
"button",
|
|
4032
|
+
{
|
|
4033
|
+
type: "submit",
|
|
4034
|
+
className: "composer__send",
|
|
4035
|
+
disabled: disabled || !value.trim(),
|
|
4036
|
+
"aria-label": "Send message",
|
|
4037
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
|
|
4038
|
+
}
|
|
4039
|
+
)
|
|
4040
|
+
] })
|
|
3972
4041
|
] })
|
|
3973
4042
|
}
|
|
3974
4043
|
);
|
|
@@ -4517,6 +4586,126 @@ function toSpeechText(text) {
|
|
|
4517
4586
|
function isSpeechSupported() {
|
|
4518
4587
|
return typeof window !== "undefined" && "speechSynthesis" in window && typeof window.SpeechSynthesisUtterance === "function";
|
|
4519
4588
|
}
|
|
4589
|
+
function stopSpeech() {
|
|
4590
|
+
if (!isSpeechSupported()) return;
|
|
4591
|
+
window.speechSynthesis.cancel();
|
|
4592
|
+
}
|
|
4593
|
+
var speechInterruptListeners = /* @__PURE__ */ new Set();
|
|
4594
|
+
var pageListenersAttached = false;
|
|
4595
|
+
var lastPathname = "";
|
|
4596
|
+
var originalPushState = null;
|
|
4597
|
+
var originalReplaceState = null;
|
|
4598
|
+
var patchedPushState = null;
|
|
4599
|
+
var patchedReplaceState = null;
|
|
4600
|
+
function currentPathname() {
|
|
4601
|
+
return window.location.pathname;
|
|
4602
|
+
}
|
|
4603
|
+
function notifySpeechInterrupts() {
|
|
4604
|
+
if (speechInterruptListeners.size === 0) return;
|
|
4605
|
+
stopSpeech();
|
|
4606
|
+
for (const listener of speechInterruptListeners) {
|
|
4607
|
+
listener();
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
function interruptIfPathChanged(nextPath) {
|
|
4611
|
+
if (nextPath === lastPathname) return;
|
|
4612
|
+
lastPathname = nextPath;
|
|
4613
|
+
notifySpeechInterrupts();
|
|
4614
|
+
}
|
|
4615
|
+
function patchHistoryMethod(original) {
|
|
4616
|
+
return function patched(data, unused, url) {
|
|
4617
|
+
const result = original.call(this, data, unused, url);
|
|
4618
|
+
interruptIfPathChanged(currentPathname());
|
|
4619
|
+
return result;
|
|
4620
|
+
};
|
|
4621
|
+
}
|
|
4622
|
+
function historyMethodState(name) {
|
|
4623
|
+
return name === "pushState" ? {
|
|
4624
|
+
original: originalPushState,
|
|
4625
|
+
patched: patchedPushState,
|
|
4626
|
+
set(original, patched) {
|
|
4627
|
+
originalPushState = original;
|
|
4628
|
+
patchedPushState = patched;
|
|
4629
|
+
}
|
|
4630
|
+
} : {
|
|
4631
|
+
original: originalReplaceState,
|
|
4632
|
+
patched: patchedReplaceState,
|
|
4633
|
+
set(original, patched) {
|
|
4634
|
+
originalReplaceState = original;
|
|
4635
|
+
patchedReplaceState = patched;
|
|
4636
|
+
}
|
|
4637
|
+
};
|
|
4638
|
+
}
|
|
4639
|
+
function patchHistoryNamed(name) {
|
|
4640
|
+
const state = historyMethodState(name);
|
|
4641
|
+
const current = history[name];
|
|
4642
|
+
if (state.patched && current === state.patched) return;
|
|
4643
|
+
const patched = patchHistoryMethod(current);
|
|
4644
|
+
state.set(current, patched);
|
|
4645
|
+
history[name] = patched;
|
|
4646
|
+
}
|
|
4647
|
+
function restoreHistoryMethod(name) {
|
|
4648
|
+
const state = historyMethodState(name);
|
|
4649
|
+
if (!state.patched || !state.original || typeof history === "undefined") {
|
|
4650
|
+
return false;
|
|
4651
|
+
}
|
|
4652
|
+
if (history[name] !== state.patched) return false;
|
|
4653
|
+
history[name] = state.original;
|
|
4654
|
+
state.set(null, null);
|
|
4655
|
+
return true;
|
|
4656
|
+
}
|
|
4657
|
+
function handlePageHide() {
|
|
4658
|
+
notifySpeechInterrupts();
|
|
4659
|
+
}
|
|
4660
|
+
function handlePopState() {
|
|
4661
|
+
interruptIfPathChanged(currentPathname());
|
|
4662
|
+
}
|
|
4663
|
+
function handleVisibilityChange() {
|
|
4664
|
+
if (document.visibilityState === "hidden") {
|
|
4665
|
+
notifySpeechInterrupts();
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
function attachPageListeners() {
|
|
4669
|
+
if (pageListenersAttached || typeof window === "undefined") return;
|
|
4670
|
+
pageListenersAttached = true;
|
|
4671
|
+
window.addEventListener("pagehide", handlePageHide);
|
|
4672
|
+
window.addEventListener("popstate", handlePopState);
|
|
4673
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
4674
|
+
}
|
|
4675
|
+
function detachPageListeners() {
|
|
4676
|
+
if (!pageListenersAttached || typeof window === "undefined") return;
|
|
4677
|
+
window.removeEventListener("pagehide", handlePageHide);
|
|
4678
|
+
window.removeEventListener("popstate", handlePopState);
|
|
4679
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
4680
|
+
pageListenersAttached = false;
|
|
4681
|
+
}
|
|
4682
|
+
function ensureSpeechInterruptsPatched() {
|
|
4683
|
+
if (typeof window === "undefined") return;
|
|
4684
|
+
lastPathname = currentPathname();
|
|
4685
|
+
patchHistoryNamed("pushState");
|
|
4686
|
+
patchHistoryNamed("replaceState");
|
|
4687
|
+
attachPageListeners();
|
|
4688
|
+
}
|
|
4689
|
+
function teardownSpeechInterrupts() {
|
|
4690
|
+
detachPageListeners();
|
|
4691
|
+
restoreHistoryMethod("pushState");
|
|
4692
|
+
restoreHistoryMethod("replaceState");
|
|
4693
|
+
if (!patchedPushState && !patchedReplaceState) {
|
|
4694
|
+
lastPathname = "";
|
|
4695
|
+
}
|
|
4696
|
+
}
|
|
4697
|
+
function subscribeSpeechInterrupts(onInterrupt) {
|
|
4698
|
+
if (typeof window === "undefined") return () => {
|
|
4699
|
+
};
|
|
4700
|
+
ensureSpeechInterruptsPatched();
|
|
4701
|
+
speechInterruptListeners.add(onInterrupt);
|
|
4702
|
+
return () => {
|
|
4703
|
+
speechInterruptListeners.delete(onInterrupt);
|
|
4704
|
+
if (speechInterruptListeners.size === 0) {
|
|
4705
|
+
teardownSpeechInterrupts();
|
|
4706
|
+
}
|
|
4707
|
+
};
|
|
4708
|
+
}
|
|
4520
4709
|
|
|
4521
4710
|
// src/react/components/MessageActions/MessageActions.tsx
|
|
4522
4711
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
@@ -4772,15 +4961,20 @@ function MessageActions({
|
|
|
4772
4961
|
const [menuOpen, setMenuOpen] = (0, import_react11.useState)(false);
|
|
4773
4962
|
const [menuPosition, setMenuPosition] = (0, import_react11.useState)(null);
|
|
4774
4963
|
const [speaking, setSpeaking] = (0, import_react11.useState)(false);
|
|
4964
|
+
const [speechSupported, setSpeechSupported] = (0, import_react11.useState)(null);
|
|
4775
4965
|
const copyTimerRef = (0, import_react11.useRef)(null);
|
|
4776
4966
|
const menuRef = (0, import_react11.useRef)(null);
|
|
4777
4967
|
const portaledMenuRef = (0, import_react11.useRef)(null);
|
|
4778
4968
|
const moreButtonRef = (0, import_react11.useRef)(null);
|
|
4779
4969
|
const answeredLabel = formatAnsweredAt(answeredAt ?? 0);
|
|
4780
4970
|
const resolvedSpeechText = speechText ?? toSpeechText(copyText);
|
|
4781
|
-
const canReadAloud = readAloud && isSpeechSupported() && resolvedSpeechText;
|
|
4782
|
-
const showMenu = Boolean(answeredLabel) || Boolean(receiptSteps) || canReadAloud;
|
|
4783
4971
|
const canOpenReceipt = Boolean(receiptSteps) && Boolean(onOpenReceipt);
|
|
4972
|
+
const readAloudEligible = Boolean(readAloud && resolvedSpeechText);
|
|
4973
|
+
const canReadAloud = readAloudEligible && speechSupported === true;
|
|
4974
|
+
const showMenu = canOpenReceipt || (speechSupported === null ? readAloudEligible : canReadAloud);
|
|
4975
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
4976
|
+
setSpeechSupported(isSpeechSupported());
|
|
4977
|
+
}, []);
|
|
4784
4978
|
(0, import_react11.useLayoutEffect)(() => {
|
|
4785
4979
|
if (!menuOpen || !moreButtonRef.current || !portaledMenuRef.current) {
|
|
4786
4980
|
setMenuPosition(null);
|
|
@@ -4798,17 +4992,16 @@ function MessageActions({
|
|
|
4798
4992
|
})
|
|
4799
4993
|
);
|
|
4800
4994
|
}, [menuOpen, menuPortalRoot]);
|
|
4801
|
-
(0, import_react11.useEffect)(
|
|
4802
|
-
() => ()
|
|
4995
|
+
(0, import_react11.useEffect)(() => {
|
|
4996
|
+
const unsubscribe = subscribeSpeechInterrupts(() => setSpeaking(false));
|
|
4997
|
+
return () => {
|
|
4998
|
+
unsubscribe();
|
|
4803
4999
|
if (copyTimerRef.current !== null) {
|
|
4804
5000
|
window.clearTimeout(copyTimerRef.current);
|
|
4805
5001
|
}
|
|
4806
|
-
|
|
4807
|
-
}
|
|
4808
|
-
|
|
4809
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4810
|
-
[]
|
|
4811
|
-
);
|
|
5002
|
+
stopSpeech();
|
|
5003
|
+
};
|
|
5004
|
+
}, []);
|
|
4812
5005
|
(0, import_react11.useEffect)(() => {
|
|
4813
5006
|
if (!menuOpen) return;
|
|
4814
5007
|
const handlePointerDown = (event) => {
|
|
@@ -4847,14 +5040,14 @@ function MessageActions({
|
|
|
4847
5040
|
if (!canReadAloud) return;
|
|
4848
5041
|
setMenuOpen(false);
|
|
4849
5042
|
if (speaking) {
|
|
4850
|
-
|
|
5043
|
+
stopSpeech();
|
|
4851
5044
|
setSpeaking(false);
|
|
4852
5045
|
return;
|
|
4853
5046
|
}
|
|
4854
5047
|
const utterance = new SpeechSynthesisUtterance(resolvedSpeechText);
|
|
4855
5048
|
utterance.onend = () => setSpeaking(false);
|
|
4856
5049
|
utterance.onerror = () => setSpeaking(false);
|
|
4857
|
-
|
|
5050
|
+
stopSpeech();
|
|
4858
5051
|
window.speechSynthesis.speak(utterance);
|
|
4859
5052
|
setSpeaking(true);
|
|
4860
5053
|
}
|
|
@@ -5752,8 +5945,9 @@ function AgentRail({
|
|
|
5752
5945
|
colorScheme = "auto",
|
|
5753
5946
|
brandLabel = "",
|
|
5754
5947
|
brandLogoUrl,
|
|
5755
|
-
poweredByLabel
|
|
5948
|
+
poweredByLabel,
|
|
5756
5949
|
disclaimerLabel,
|
|
5950
|
+
disclaimerLink,
|
|
5757
5951
|
answerReceipt = false,
|
|
5758
5952
|
readAloud = false,
|
|
5759
5953
|
composerPlaceholder = "Ask anything\u2026",
|
|
@@ -6188,7 +6382,15 @@ function AgentRail({
|
|
|
6188
6382
|
onRetry ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", onClick: onRetry, children: "Try again" }) : null
|
|
6189
6383
|
] }) : null
|
|
6190
6384
|
] }) }),
|
|
6191
|
-
showDisclaimerLabel ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "agent-rail__disclaimer", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children:
|
|
6385
|
+
showDisclaimerLabel ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "agent-rail__disclaimer", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: disclaimerLink ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
6386
|
+
"a",
|
|
6387
|
+
{
|
|
6388
|
+
href: disclaimerLink,
|
|
6389
|
+
rel: "noopener noreferrer",
|
|
6390
|
+
target: "_blank",
|
|
6391
|
+
children: resolvedDisclaimerLabel
|
|
6392
|
+
}
|
|
6393
|
+
) : resolvedDisclaimerLabel }) }) : null,
|
|
6192
6394
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
|
|
6193
6395
|
showJumpToLatest ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
6194
6396
|
"button",
|
|
@@ -6206,10 +6408,12 @@ function AgentRail({
|
|
|
6206
6408
|
{
|
|
6207
6409
|
variant: expanded || mobileFullscreen ? "dock" : "default",
|
|
6208
6410
|
disabled: isBusy,
|
|
6209
|
-
form: composerForm,
|
|
6411
|
+
form: composerForm && lastMessage ? { ...composerForm, id: `${lastMessage.id}:${composerForm.id}` } : null,
|
|
6412
|
+
allowFormResume: !state.pendingOffer && !waitingForBooking && !hasPendingConfirmation,
|
|
6210
6413
|
placeholder: composerPlaceholder,
|
|
6211
6414
|
onSubmit: handleSubmit
|
|
6212
|
-
}
|
|
6415
|
+
},
|
|
6416
|
+
state.messages.find((message) => message.role === "visitor")?.id ?? "empty"
|
|
6213
6417
|
),
|
|
6214
6418
|
poweredByLabel ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "agent-rail__footer", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: poweredByLabel }) }) }) : null
|
|
6215
6419
|
] })
|
|
@@ -6653,8 +6857,9 @@ function AgentWidget({
|
|
|
6653
6857
|
brandLabel: agentName,
|
|
6654
6858
|
brandLogoUrl: branding?.logoUrl,
|
|
6655
6859
|
composerPlaceholder: branding?.composerPlaceholder ?? "Ask a question\u2026",
|
|
6656
|
-
poweredByLabel: branding?.poweredByLabel
|
|
6860
|
+
poweredByLabel: branding?.poweredByLabel,
|
|
6657
6861
|
disclaimerLabel: branding?.disclaimer,
|
|
6862
|
+
disclaimerLink: branding?.disclaimerLink,
|
|
6658
6863
|
answerReceipt: branding?.answerReceipt,
|
|
6659
6864
|
readAloud: branding?.readAloud,
|
|
6660
6865
|
state,
|
|
@@ -6808,6 +7013,20 @@ function normalizeOptionalValue(value) {
|
|
|
6808
7013
|
const normalized = value?.trim();
|
|
6809
7014
|
return normalized || void 0;
|
|
6810
7015
|
}
|
|
7016
|
+
function normalizeOptionalHttpUrl(value) {
|
|
7017
|
+
if (value === null) return null;
|
|
7018
|
+
const normalized = value?.trim();
|
|
7019
|
+
if (!normalized) return void 0;
|
|
7020
|
+
try {
|
|
7021
|
+
const url = new URL(normalized);
|
|
7022
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
7023
|
+
return void 0;
|
|
7024
|
+
}
|
|
7025
|
+
return normalized;
|
|
7026
|
+
} catch {
|
|
7027
|
+
return void 0;
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
6811
7030
|
function normalizeAgentBranding(branding) {
|
|
6812
7031
|
if (!branding) return void 0;
|
|
6813
7032
|
const colors = branding.colors ? Object.fromEntries(
|
|
@@ -6825,6 +7044,7 @@ function normalizeAgentBranding(branding) {
|
|
|
6825
7044
|
composerPlaceholder: normalizeOptionalValue(branding.composerPlaceholder),
|
|
6826
7045
|
poweredByLabel: normalizeOptionalValue(branding.poweredByLabel),
|
|
6827
7046
|
disclaimer: branding.disclaimer === null ? null : normalizeOptionalValue(branding.disclaimer),
|
|
7047
|
+
disclaimerLink: normalizeOptionalHttpUrl(branding.disclaimerLink),
|
|
6828
7048
|
answerReceipt: branding.answerReceipt === true ? true : void 0,
|
|
6829
7049
|
readAloud: branding.readAloud === true ? true : void 0,
|
|
6830
7050
|
fontFamily: normalizeOptionalValue(branding.fontFamily),
|