@sonordev/site-kit 7.1.2 → 7.3.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/AGENTS.md +1 -1
- package/CHANGELOG.md +60 -0
- package/README.md +9 -8
- package/agent-manifest.json +17 -7
- package/dist/{AnalyticsProvider-ZB33W6MC.js → AnalyticsProvider-DJQA66AG.js} +4 -4
- package/dist/{ArticleViewTracker-GMHYLLLZ.js → ArticleViewTracker-GFOAXFV7.js} +3 -3
- package/dist/{BlocksPopup-EA6LYL25.js → BlocksPopup-AHDU34TL.js} +5 -5
- package/dist/ChatWidget-FHBAHFZX.js +17 -0
- package/dist/{FileField-QKA3JB2Q.js → FileField-J5W5MIAZ.js} +3 -3
- package/dist/{FormSpotlight-AQTIA5TP.js → FormSpotlight-PE5YZBFZ.js} +20 -6
- package/dist/{FormStage-FDTLTP3B.js → FormStage-OOPQC27J.js} +27 -7
- package/dist/ManagedForm-JRZAJ7SZ.js +16 -0
- package/dist/{ManagedNewsletterForm-J6QSAGGP.js → ManagedNewsletterForm-TC5542ZG.js} +7 -5
- package/dist/{SignalCore-JZNXOLNT.js → SignalCore-2YP5FCAS.js} +3 -3
- package/dist/SiteChat-EGEZJJVV.js +5 -0
- package/dist/{SiteDesignReporter-W4EJUSTE.js → SiteDesignReporter-YEEWJKWN.js} +5 -5
- package/dist/SitePopups-LQBIXIFV.js +10 -0
- package/dist/SitemapSync-LSZ2EYOF.js +8 -0
- package/dist/_client/booking-widget.js +5 -5
- package/dist/affiliates/index.js +3 -3
- package/dist/analytics/index.js +4 -4
- package/dist/analytics/send-gate.d.ts +1 -1
- package/dist/articles/index.js +2 -2
- package/dist/articles/server-ui.js +3 -2
- package/dist/articles/server.js +2 -1
- package/dist/{engage → chat}/ChatWidget.d.ts +7 -6
- package/dist/{engage → chat}/EchoUiActions.d.ts +1 -1
- package/dist/chat/SiteChat.d.ts +25 -0
- package/dist/{engage → chat}/brand-color.d.ts +1 -1
- package/dist/{engage → chat}/chat-messages.d.ts +1 -1
- package/dist/{engage → chat}/echo-config.d.ts +1 -1
- package/dist/chat/index.d.ts +10 -6
- package/dist/chat/index.js +14 -8
- package/dist/{engage → chat}/launcher-placement.d.ts +1 -7
- package/dist/{engage → chat}/socket-loader.d.ts +2 -2
- package/dist/chat/types.d.ts +136 -0
- package/dist/chunk-27FISYK4.js +4 -0
- package/dist/{chunk-HF57LG73.js → chunk-2AD3CDRR.js} +43 -29
- package/dist/{chunk-M3YEPKP7.js → chunk-2ECWEUHP.js} +1 -1
- package/dist/{chunk-LUXVWITO.js → chunk-4NTBQNHA.js} +247 -78
- package/dist/{chunk-AH5Q262S.js → chunk-56KNHB4U.js} +1 -1
- package/dist/{chunk-GLHQ3LRO.js → chunk-6U3VLV2C.js} +1 -1
- package/dist/{chunk-3SDOQUUF.js → chunk-BEBR4OJD.js} +2 -2
- package/dist/{chunk-JSZN6LDZ.js → chunk-BF7TZYC3.js} +38 -31
- package/dist/{chunk-AQSNPZY4.js → chunk-C2FZBUSS.js} +80 -1
- package/dist/{chunk-PHYMNUJU.js → chunk-CYUFBKJQ.js} +1 -1
- package/dist/{chunk-6WIQCXOO.js → chunk-DNPNYWVL.js} +1 -1
- package/dist/{chunk-V6FDQLR7.js → chunk-EPT6FJUY.js} +53 -21
- package/dist/chunk-HODO5BX5.js +28 -0
- package/dist/chunk-HW7B43E5.js +14 -0
- package/dist/{chunk-PGMVL4AB.js → chunk-I2YX3HVD.js} +2 -2
- package/dist/{chunk-JTU2GOM4.js → chunk-L7U23XI2.js} +18 -6
- package/dist/{chunk-YEMPUQVU.js → chunk-MKMD2HJW.js} +2 -2
- package/dist/{chunk-Q4W23JYM.js → chunk-MRQ2U4LZ.js} +1 -1
- package/dist/chunk-MVR4FY5R.js +187 -0
- package/dist/{chunk-VGH4MDTU.js → chunk-NI2XNEMR.js} +1 -1
- package/dist/{chunk-4Y5FWDPM.js → chunk-NZ4RXN3G.js} +55 -7
- package/dist/{chunk-RHNWA34F.js → chunk-O5RGXTWU.js} +41 -7
- package/dist/{chunk-TXBAOEKG.js → chunk-PKGN32AU.js} +5 -4
- package/dist/chunk-Q6E4OPGG.js +40 -0
- package/dist/chunk-RDPW4D33.js +45 -0
- package/dist/{chunk-UXOGCKL6.js → chunk-T4DLETKR.js} +1 -1
- package/dist/{chunk-NK4CSJNP.js → chunk-UPRSH6Q4.js} +2 -2
- package/dist/{chunk-ERXXITG4.js → chunk-VF4F5WXZ.js} +1 -1
- package/dist/chunk-VWWITFWM.js +300 -0
- package/dist/{chunk-WWSHFRDL.js → chunk-WDQB4OXY.js} +7 -3
- package/dist/{chunk-VDF5DFWT.js → chunk-WGG6GTKW.js} +1 -1
- package/dist/{chunk-CSTQDNGK.js → chunk-WGIDC6QP.js} +43 -24
- package/dist/{chunk-V3PUVBME.js → chunk-XLSQTTUE.js} +2 -4
- package/dist/{chunk-JBE46QJZ.js → chunk-Y6LP36UW.js} +1 -1
- package/dist/chunk-YJLS6JBI.js +370 -0
- package/dist/{chunk-QEDHRBAT.js → chunk-Z65DHMTW.js} +26 -9
- package/dist/{chunk-ILU5I6RW.js → chunk-ZHS2XFLV.js} +1 -1
- package/dist/{chunk-D5EC5KVO.js → chunk-ZKHI4E2B.js} +2 -2
- package/dist/{chunk-CIG5UL2S.js → chunk-ZTLMPUO6.js} +3 -2
- package/dist/client/index.js +3 -3
- package/dist/commerce/index.js +4 -4
- package/dist/contracts/color.d.ts +1 -1
- package/dist/contracts/entries.d.ts +1 -1
- package/dist/contracts/error-page.d.ts +183 -0
- package/dist/contracts/llms.d.ts +1 -0
- package/dist/contracts/proposal-sitemap.d.ts +130 -0
- package/dist/contracts/schema-placeholders.d.ts +87 -0
- package/dist/engage/EngageWidget.d.ts +13 -12
- package/dist/engage/index.d.ts +10 -9
- package/dist/engage/index.js +31 -35
- package/dist/engage/types.d.ts +19 -244
- package/dist/fleet/FleetHeartbeat.d.ts +1 -1
- package/dist/fleet/index.js +4 -4
- package/dist/forms/FormEnhancer.d.ts +25 -12
- package/dist/forms/ServerForm.d.ts +11 -10
- package/dist/forms/StaticForm.d.ts +3 -1
- package/dist/forms/field-autocomplete.d.ts +28 -0
- package/dist/forms/form-dom-values.d.ts +42 -0
- package/dist/forms/index.js +11 -9
- package/dist/forms/server.js +6 -4
- package/dist/forms/static.js +3 -2
- package/dist/forms/submitForm.d.ts +8 -1
- package/dist/forms/types.d.ts +41 -2
- package/dist/forms/useForm.d.ts +21 -4
- package/dist/forms/webmcp.d.ts +38 -0
- package/dist/images/index.js +4 -4
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -1
- package/dist/layout/SiteKitClientProviders.d.ts +3 -3
- package/dist/layout/SiteKitLayout.d.ts +4 -4
- package/dist/layout/client.d.ts +3 -3
- package/dist/layout/client.js +7 -7
- package/dist/layout/index.js +8 -8
- package/dist/layout/types.d.ts +5 -4
- package/dist/llms/agent-access.d.ts +4 -0
- package/dist/llms/contract.js +1 -1
- package/dist/llms/index.js +6 -6
- package/dist/maps/index.js +3 -3
- package/dist/mcp/WebMcpTools.d.ts +5 -4
- package/dist/mcp/client.js +14 -7
- package/dist/mcp/discovery.d.ts +48 -0
- package/dist/mcp/handlers.d.ts +13 -7
- package/dist/mcp/index.d.ts +5 -3
- package/dist/mcp/index.js +62 -30
- package/dist/mcp/serverCard.d.ts +6 -7
- package/dist/mcp/sonor.js +14 -11
- package/dist/revalidate/index.js +2 -2
- package/dist/seo/client.js +4 -4
- package/dist/seo/index.js +15 -8
- package/dist/seo/llms/contract.js +1 -1
- package/dist/seo/llms.js +6 -6
- package/dist/seo/register-sitemap-cli.js +1 -1
- package/dist/seo/sitemap.js +4 -4
- package/dist/server/index.js +2 -2
- package/dist/shared/dialog.d.ts +27 -0
- package/dist/shared/identity.d.ts +1 -1
- package/dist/shared/layers.d.ts +7 -0
- package/dist/shared/mid-form.d.ts +53 -0
- package/dist/shared/reporting-gate.d.ts +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/visual-viewport-gap.d.ts +1 -1
- package/dist/signal/index.js +2 -2
- package/dist/signal/types.d.ts +1 -1
- package/dist/sitemap/index.js +4 -4
- package/dist/{socket-loader-R24ZSRSQ.js → socket-loader-CGIPEG74.js} +1 -1
- package/dist/sync/index.js +5 -5
- package/dist/types.d.ts +3 -1
- package/dist/{web-vitals.attribution-GD6LGLVF.js → web-vitals.attribution-N2PCCF4Q.js} +1 -1
- package/dist/website/BlocksPopup.d.ts +1 -1
- package/dist/website/PopupBlocks.d.ts +5 -2
- package/dist/website/SitePopups.d.ts +25 -0
- package/dist/website/images.js +4 -4
- package/dist/website/index.js +6 -6
- package/dist/website/popup-rules.d.ts +46 -0
- package/dist/website/popup-types.d.ts +113 -0
- package/dist/website/popups.d.ts +2 -6
- package/dist/website/popups.js +6 -14
- package/dist/{writeLLMsTxt-G3JBNBC5.js → writeLLMsTxt-2NQVDGYI.js} +3 -3
- package/docs/MIGRATING-TO-7.md +41 -9
- package/docs.json +2 -1
- package/package.json +2 -2
- package/src/analytics/README.md +2 -2
- package/src/articles/README.md +4 -1
- package/src/{engage → chat}/README.md +63 -62
- package/src/forms/README.md +49 -3
- package/src/layout/README.md +8 -5
- package/src/llms/README.md +69 -0
- package/src/mcp/README.md +50 -16
- package/src/seo/README.md +3 -1
- package/src/sync/README.md +10 -0
- package/src/website/README.md +133 -0
- package/dist/ChatWidget-UCDWMWCW.js +0 -15
- package/dist/EngageWidget-7ZYSK4GE.js +0 -11
- package/dist/ManagedForm-H7BVAH2W.js +0 -14
- package/dist/SitemapSync-XBANGKHZ.js +0 -8
- package/dist/chunk-NDF4A5JM.js +0 -37
- package/dist/chunk-VLARKWZU.js +0 -100
- package/dist/chunk-YCJT4JJG.js +0 -837
- package/dist/engage/DesignRenderer.d.ts +0 -57
- package/dist/engage/element-rules.d.ts +0 -38
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { readAgentSubmit, formToolAttributes } from './chunk-Q6E4OPGG.js';
|
|
3
|
+
import { isFieldVisible, validateField, isFieldComplete, unseenControlValues } from './chunk-C2FZBUSS.js';
|
|
4
|
+
import { normalizeFormConfig, DEFAULT_FORM_SUCCESS_MESSAGE } from './chunk-5SQK3D53.js';
|
|
4
5
|
import { DEFAULT_HONEYPOT_FIELD } from './chunk-NJCTQH2P.js';
|
|
5
6
|
import { onPageLeave } from './chunk-L2V5PUFN.js';
|
|
6
7
|
import { uuid } from './chunk-GJWI74ZZ.js';
|
|
7
|
-
import { sonorFetch, sonorBeacon } from './chunk-
|
|
8
|
+
import { sonorFetch, sonorBeacon } from './chunk-BEBR4OJD.js';
|
|
8
9
|
import { useRef, useCallback, useEffect, useState, useMemo } from 'react';
|
|
9
10
|
|
|
10
11
|
// src/forms/field-interactions.ts
|
|
@@ -567,7 +568,8 @@ async function submitForm({
|
|
|
567
568
|
config,
|
|
568
569
|
values,
|
|
569
570
|
honeypotValue,
|
|
570
|
-
formLoadedAt
|
|
571
|
+
formLoadedAt,
|
|
572
|
+
agentInvoked
|
|
571
573
|
}) {
|
|
572
574
|
const { apiUrl, apiKey } = getApiConfig();
|
|
573
575
|
if (!apiKey) {
|
|
@@ -606,7 +608,8 @@ async function submitForm({
|
|
|
606
608
|
// Sub-site host — preserved on form_submissions for lead attribution
|
|
607
609
|
// across multi-site projects. Resolved by SiteKitClientProviders.
|
|
608
610
|
site: typeof window !== "undefined" ? window.__SITE_KIT_SITE__ || window.location.host : void 0,
|
|
609
|
-
_formLoadedAt: formLoadedAt
|
|
611
|
+
_formLoadedAt: formLoadedAt,
|
|
612
|
+
...agentInvoked ? { agentInvoked: true } : {}
|
|
610
613
|
}
|
|
611
614
|
};
|
|
612
615
|
const response = await sonorFetch(
|
|
@@ -800,23 +803,24 @@ function useForm(formIdOrSlug, options = {}) {
|
|
|
800
803
|
setErrors(newErrors);
|
|
801
804
|
return Object.keys(newErrors).length === 0;
|
|
802
805
|
}, [fields, validateField2]);
|
|
803
|
-
const
|
|
806
|
+
const validateAllFor = useCallback((vals) => {
|
|
807
|
+
const visible = (field) => isFieldVisible(field, vals);
|
|
804
808
|
const newErrors = {};
|
|
805
809
|
for (const field of allFields) {
|
|
806
|
-
const error =
|
|
810
|
+
const error = validateField(field, vals, visible);
|
|
807
811
|
if (error) newErrors[field.slug] = error;
|
|
808
812
|
}
|
|
809
813
|
setErrors(newErrors);
|
|
810
|
-
return
|
|
811
|
-
}, [allFields
|
|
812
|
-
const buildVisibleValues = useCallback(() => {
|
|
814
|
+
return newErrors;
|
|
815
|
+
}, [allFields]);
|
|
816
|
+
const buildVisibleValues = useCallback((vals) => {
|
|
813
817
|
const out = {};
|
|
814
818
|
for (const field of allFields) {
|
|
815
|
-
if (!
|
|
816
|
-
if (field.slug in
|
|
819
|
+
if (!isFieldVisible(field, vals)) continue;
|
|
820
|
+
if (field.slug in vals) out[field.slug] = vals[field.slug];
|
|
817
821
|
}
|
|
818
822
|
return out;
|
|
819
|
-
}, [allFields
|
|
823
|
+
}, [allFields]);
|
|
820
824
|
const setFieldValue = useCallback((key, value) => {
|
|
821
825
|
setValuesState((prev) => ({ ...prev, [key]: value }));
|
|
822
826
|
trackFieldChange(key);
|
|
@@ -862,19 +866,25 @@ function useForm(formIdOrSlug, options = {}) {
|
|
|
862
866
|
trackStepChange(targetStep);
|
|
863
867
|
}
|
|
864
868
|
}, [totalSteps, trackStepChange]);
|
|
865
|
-
const submit = useCallback(async () => {
|
|
866
|
-
if (!form) return;
|
|
867
|
-
if (isSubmittingRef.current) return;
|
|
868
|
-
|
|
869
|
+
const submit = useCallback(async (options2) => {
|
|
870
|
+
if (!form) return { status: "failed", message: "The form is still loading." };
|
|
871
|
+
if (isSubmittingRef.current) return { status: "busy" };
|
|
872
|
+
const domFills = options2 && typeof options2 === "object" && options2.domFills && typeof options2.domFills === "object" ? options2.domFills : null;
|
|
873
|
+
const agentInvoked = !!options2 && typeof options2 === "object" && options2.agentInvoked === true;
|
|
874
|
+
const vals = domFills && Object.keys(domFills).length > 0 ? { ...values, ...domFills } : values;
|
|
875
|
+
if (vals !== values) setValuesState(vals);
|
|
876
|
+
const invalid = validateAllFor(vals);
|
|
877
|
+
if (Object.keys(invalid).length > 0) return { status: "invalid", errors: invalid };
|
|
869
878
|
isSubmittingRef.current = true;
|
|
870
879
|
setIsSubmitting(true);
|
|
871
880
|
setSubmitError(null);
|
|
872
881
|
try {
|
|
873
882
|
const data = await submitForm({
|
|
874
883
|
config: form,
|
|
875
|
-
values: buildVisibleValues(),
|
|
884
|
+
values: buildVisibleValues(vals),
|
|
876
885
|
honeypotValue: "",
|
|
877
|
-
formLoadedAt: formLoadedAt()
|
|
886
|
+
formLoadedAt: formLoadedAt(),
|
|
887
|
+
agentInvoked
|
|
878
888
|
});
|
|
879
889
|
trackComplete();
|
|
880
890
|
setIsComplete(true);
|
|
@@ -883,15 +893,35 @@ function useForm(formIdOrSlug, options = {}) {
|
|
|
883
893
|
if (finalRedirect) {
|
|
884
894
|
window.location.href = finalRedirect;
|
|
885
895
|
}
|
|
896
|
+
const confirmation = typeof form.success_message === "string" && form.success_message.trim() ? form.success_message.trim() : DEFAULT_FORM_SUCCESS_MESSAGE;
|
|
897
|
+
return { status: "sent", message: confirmation, submissionId: data.submissionId || void 0 };
|
|
886
898
|
} catch (error) {
|
|
887
899
|
console.error("[useForm] Submission error:", error);
|
|
888
|
-
|
|
900
|
+
const message = "Something went wrong sending your submission. Please try again.";
|
|
901
|
+
setSubmitError(message);
|
|
889
902
|
onError?.(error);
|
|
903
|
+
return { status: "failed", message };
|
|
890
904
|
} finally {
|
|
891
905
|
isSubmittingRef.current = false;
|
|
892
906
|
setIsSubmitting(false);
|
|
893
907
|
}
|
|
894
|
-
}, [form,
|
|
908
|
+
}, [form, values, validateAllFor, buildVisibleValues, trackComplete, onSuccess, onError, redirectUrl]);
|
|
909
|
+
const handleSubmit = useCallback((event) => {
|
|
910
|
+
event.preventDefault();
|
|
911
|
+
const agent = readAgentSubmit(event.nativeEvent);
|
|
912
|
+
if (form?.is_multi_step && step < totalSteps) {
|
|
913
|
+
const moved = nextStep();
|
|
914
|
+
agent.respond(
|
|
915
|
+
Promise.resolve(
|
|
916
|
+
moved ? { status: "next_step", step: step + 1, totalSteps } : { status: "invalid", errors: {} }
|
|
917
|
+
)
|
|
918
|
+
);
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
const domFills = unseenControlValues(event.currentTarget, allFields, "", values);
|
|
922
|
+
agent.respond(submit({ agentInvoked: agent.invoked, domFills }));
|
|
923
|
+
}, [form, step, totalSteps, nextStep, allFields, values, submit]);
|
|
924
|
+
const toolAttributes = useMemo(() => form ? formToolAttributes(form) : null, [form]);
|
|
895
925
|
const reset = useCallback(() => {
|
|
896
926
|
setValuesState(initialValues);
|
|
897
927
|
setErrors({});
|
|
@@ -926,6 +956,8 @@ function useForm(formIdOrSlug, options = {}) {
|
|
|
926
956
|
validateField: validateField2,
|
|
927
957
|
isFieldVisible: isFieldVisible2,
|
|
928
958
|
submit,
|
|
959
|
+
handleSubmit,
|
|
960
|
+
toolAttributes,
|
|
929
961
|
isSubmitting,
|
|
930
962
|
isComplete,
|
|
931
963
|
reset,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// src/chat/echo-config.ts
|
|
2
|
+
var SONOR_PUBLIC_ECHO_DEFAULTS = {
|
|
3
|
+
signalUrl: "https://signal.sonor.io",
|
|
4
|
+
welcomeMessage: "Hi! I'm Echo, Sonor's AI assistant. I can answer questions about our platform, help you understand pricing, or get you started with a demo. What would you like to know?",
|
|
5
|
+
suggestedQuestions: [
|
|
6
|
+
"What does Sonor do?",
|
|
7
|
+
"How does Signal AI work?",
|
|
8
|
+
"What are the pricing plans?",
|
|
9
|
+
"Can I migrate from HubSpot?",
|
|
10
|
+
"How does the SEO module work?"
|
|
11
|
+
],
|
|
12
|
+
brandColor: "#2563eb",
|
|
13
|
+
// blue-600 (~5.2:1 on white, AA); overridden by --sk-primary CSS var or API brand_primary
|
|
14
|
+
assistantName: "Echo"
|
|
15
|
+
};
|
|
16
|
+
function getEchoWidgetProps(config = SONOR_PUBLIC_ECHO_DEFAULTS) {
|
|
17
|
+
return {
|
|
18
|
+
signal_enabled: true,
|
|
19
|
+
signal_url: config.signalUrl || SONOR_PUBLIC_ECHO_DEFAULTS.signalUrl,
|
|
20
|
+
welcome_message: config.welcomeMessage || SONOR_PUBLIC_ECHO_DEFAULTS.welcomeMessage,
|
|
21
|
+
suggested_questions: config.suggestedQuestions || SONOR_PUBLIC_ECHO_DEFAULTS.suggestedQuestions,
|
|
22
|
+
brand_color: config.brandColor || SONOR_PUBLIC_ECHO_DEFAULTS.brandColor,
|
|
23
|
+
assistant_name: config.assistantName || SONOR_PUBLIC_ECHO_DEFAULTS.assistantName,
|
|
24
|
+
assistant_avatar: config.assistantAvatar
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { SONOR_PUBLIC_ECHO_DEFAULTS, getEchoWidgetProps };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/mcp/declarative.ts
|
|
2
|
+
function declarativeToolForm(options) {
|
|
3
|
+
const attributes = {
|
|
4
|
+
toolname: options.name,
|
|
5
|
+
tooldescription: options.description
|
|
6
|
+
};
|
|
7
|
+
if (options.autoSubmit) attributes.toolautosubmit = "";
|
|
8
|
+
return attributes;
|
|
9
|
+
}
|
|
10
|
+
function declarativeToolField(description) {
|
|
11
|
+
return { toolparamdescription: description };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { declarativeToolField, declarativeToolForm };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { toHexColor, normalizeDesignTokens, designTokensHash } from './chunk-IHG36STL.js';
|
|
2
2
|
import { contrastRatio, parseColor, relativeLuminance } from './chunk-S22FSH7C.js';
|
|
3
3
|
import { resolveAnalyticsTarget } from './chunk-43OCZ3JA.js';
|
|
4
|
-
import { sonorFetch } from './chunk-
|
|
5
|
-
import { SITE_KIT_VERSION } from './chunk-
|
|
4
|
+
import { sonorFetch } from './chunk-BEBR4OJD.js';
|
|
5
|
+
import { SITE_KIT_VERSION } from './chunk-56KNHB4U.js';
|
|
6
6
|
|
|
7
7
|
// src/website/design.ts
|
|
8
8
|
var SITE_DESIGN_PATH = "/api/public/site/design";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { detectTimezone, releaseSlotHold, fetchBookingTypeDetails, fetchBookingTypes, fetchAvailability, createSlotHold, createBooking, formatDuration, formatDate, formatTime, prepareMeeting } from './chunk-
|
|
2
|
+
import { detectTimezone, releaseSlotHold, fetchBookingTypeDetails, fetchBookingTypes, fetchAvailability, createSlotHold, createBooking, formatDuration, formatDate, formatTime, prepareMeeting } from './chunk-2ECWEUHP.js';
|
|
3
3
|
import { useState, useRef, useMemo, useCallback, useEffect, useId } from 'react';
|
|
4
4
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -163,6 +163,12 @@ function toLocalDateStr(d) {
|
|
|
163
163
|
const day = String(d.getDate()).padStart(2, "0");
|
|
164
164
|
return `${y}-${m}-${day}`;
|
|
165
165
|
}
|
|
166
|
+
function dayLabel(d) {
|
|
167
|
+
return d.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric", year: "numeric" });
|
|
168
|
+
}
|
|
169
|
+
function slotLabel(slot, timezone) {
|
|
170
|
+
return `${formatTime(slot.start, timezone)}, ${formatDate(slot.start, timezone)}`;
|
|
171
|
+
}
|
|
166
172
|
function ChevronLeft() {
|
|
167
173
|
return /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M12.5 15L7.5 10L12.5 5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
168
174
|
}
|
|
@@ -706,8 +712,8 @@ function BookingWidget({
|
|
|
706
712
|
if (!disabled && !busyRef.current) setSelectedDate(date);
|
|
707
713
|
},
|
|
708
714
|
disabled,
|
|
709
|
-
"aria-label": date
|
|
710
|
-
"aria-pressed": sel
|
|
715
|
+
"aria-label": dayLabel(date),
|
|
716
|
+
"aria-pressed": Boolean(sel),
|
|
711
717
|
children: date.getDate()
|
|
712
718
|
},
|
|
713
719
|
date.toISOString()
|
|
@@ -965,13 +971,15 @@ function TimeButton({
|
|
|
965
971
|
timezone,
|
|
966
972
|
loading
|
|
967
973
|
}) {
|
|
974
|
+
const time = formatTime(slot.start, timezone);
|
|
975
|
+
const label = slotLabel(slot, timezone);
|
|
968
976
|
if (selected && !confirmed) {
|
|
969
977
|
return /* @__PURE__ */ jsxs("div", { className: "bw-time-btn-wrap selected", children: [
|
|
970
|
-
/* @__PURE__ */ jsx("
|
|
971
|
-
/* @__PURE__ */ jsx("button", { className: "bw-time-confirm", onClick: onConfirm, disabled: loading, children: loading ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : "Confirm" })
|
|
978
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "bw-time-text", "aria-label": label, "aria-pressed": "true", onClick, disabled: loading, children: time }),
|
|
979
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "bw-time-confirm", "aria-label": `Confirm ${label}`, onClick: onConfirm, disabled: loading, children: loading ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : "Confirm" })
|
|
972
980
|
] });
|
|
973
981
|
}
|
|
974
|
-
return /* @__PURE__ */ jsx("button", { className: `bw-time-btn${selected ? " selected" : ""}`, onClick, disabled: loading, children:
|
|
982
|
+
return /* @__PURE__ */ jsx("button", { type: "button", className: `bw-time-btn${selected ? " selected" : ""}`, "aria-label": label, "aria-pressed": selected, onClick, disabled: loading, children: time });
|
|
975
983
|
}
|
|
976
984
|
var WIDGET_CSS = `
|
|
977
985
|
/* \u2500\u2500 Base \u2500\u2500 */
|
|
@@ -1159,7 +1167,11 @@ var WIDGET_CSS = `
|
|
|
1159
1167
|
.bw-time-btn-wrap .bw-time-text {
|
|
1160
1168
|
flex: 1; padding: 10px 12px; font-size: 0.875rem; font-weight: 500; color: var(--sk-text-primary); text-align: center;
|
|
1161
1169
|
background: var(--sk-primary-light);
|
|
1170
|
+
-webkit-appearance: none; appearance: none; border: none; border-radius: 0; margin: 0;
|
|
1171
|
+
font-family: inherit; line-height: inherit; letter-spacing: inherit; cursor: default;
|
|
1162
1172
|
}
|
|
1173
|
+
/* The wrap clips its children, so focus rings go inside, in the text color. */
|
|
1174
|
+
.bw-time-btn-wrap button:focus-visible { outline-color: currentColor; outline-offset: -2px; }
|
|
1163
1175
|
.bw-time-confirm {
|
|
1164
1176
|
display: inline-flex; align-items: center; justify-content: center; gap: 4px;
|
|
1165
1177
|
min-height: 44px; padding: 10px 16px; border: none;
|
|
@@ -3,7 +3,7 @@ import { registerAnalyticsDispatcher } from './chunk-LCDVPAMR.js';
|
|
|
3
3
|
import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-24QZEO3Q.js';
|
|
4
4
|
import { onPageLeave } from './chunk-L2V5PUFN.js';
|
|
5
5
|
import { resolveAnalyticsTarget } from './chunk-43OCZ3JA.js';
|
|
6
|
-
import { sonorFetch, sonorBeacon } from './chunk-
|
|
6
|
+
import { sonorFetch, sonorBeacon } from './chunk-BEBR4OJD.js';
|
|
7
7
|
import { createContext, useRef, useEffect, useState, useMemo, useCallback, useContext } from 'react';
|
|
8
8
|
import { usePathname } from 'next/navigation';
|
|
9
9
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -157,7 +157,7 @@ function WebVitals({
|
|
|
157
157
|
useEffect(() => {
|
|
158
158
|
let cancelled = false;
|
|
159
159
|
let teardown;
|
|
160
|
-
import('./web-vitals.attribution-
|
|
160
|
+
import('./web-vitals.attribution-N2PCCF4Q.js').then(({ onCLS, onLCP, onTTFB, onINP, onFCP }) => {
|
|
161
161
|
if (cancelled) return;
|
|
162
162
|
const { propApiUrl: propApiUrl2, propApiKey: propApiKey2, propSite: propSite2, allowInFrame: allowInFrame2, allowLocalhost: allowLocalhost2, debug: debug2, visitorId: visitorId2, sessionId: sessionId2, sessionTimeout: sessionTimeout2 } = propsRef.current;
|
|
163
163
|
const sent = /* @__PURE__ */ new Map();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { getSiteDesignTokens, tokensForReport, shouldReportDesign, sendSiteDesign } from './chunk-
|
|
2
|
+
import { getSiteDesignTokens, tokensForReport, shouldReportDesign, sendSiteDesign } from './chunk-I2YX3HVD.js';
|
|
3
3
|
import { designTokensHash } from './chunk-IHG36STL.js';
|
|
4
4
|
import { useDeferredActivation } from './chunk-YC7ELZS3.js';
|
|
5
5
|
import { resolveAnalyticsTarget } from './chunk-43OCZ3JA.js';
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useDeferredActivation } from './chunk-YC7ELZS3.js';
|
|
3
|
+
import { shellValuesToCarry } from './chunk-C2FZBUSS.js';
|
|
4
|
+
import { normalizeFormConfig } from './chunk-5SQK3D53.js';
|
|
5
|
+
import { DEFAULT_HONEYPOT_FIELD } from './chunk-NJCTQH2P.js';
|
|
6
|
+
import React, { useRef, useEffect, useState, useMemo, useCallback } from 'react';
|
|
7
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
var loadInteractiveForm = () => import('./ManagedForm-JRZAJ7SZ.js').then((m) => m.ManagedForm);
|
|
10
|
+
var REPLAY_WAIT_MS = 8e3;
|
|
11
|
+
function FormEnhancer({
|
|
12
|
+
formId,
|
|
13
|
+
initialConfig,
|
|
14
|
+
className,
|
|
15
|
+
experience,
|
|
16
|
+
defaultValues,
|
|
17
|
+
onSuccess,
|
|
18
|
+
onError,
|
|
19
|
+
enter = "fade",
|
|
20
|
+
defer = true,
|
|
21
|
+
children
|
|
22
|
+
}) {
|
|
23
|
+
const idle = useDeferredActivation(defer);
|
|
24
|
+
const [engaged, setEngaged] = useState(false);
|
|
25
|
+
const hostRef = useRef(null);
|
|
26
|
+
const [Interactive, setInteractive] = useState(null);
|
|
27
|
+
const [carried, setCarried] = useState(null);
|
|
28
|
+
const pendingSubmitRef = useRef(false);
|
|
29
|
+
const [enhanced, setEnhanced] = useState(false);
|
|
30
|
+
const fields = useMemo(() => {
|
|
31
|
+
if (!initialConfig) return void 0;
|
|
32
|
+
try {
|
|
33
|
+
return normalizeFormConfig(initialConfig).fields;
|
|
34
|
+
} catch {
|
|
35
|
+
return void 0;
|
|
36
|
+
}
|
|
37
|
+
}, [initialConfig]);
|
|
38
|
+
const honeypotName = initialConfig && typeof initialConfig.honeypot_field === "string" && initialConfig.honeypot_field || DEFAULT_HONEYPOT_FIELD;
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (Interactive) return;
|
|
41
|
+
const form = hostRef.current?.querySelector("form");
|
|
42
|
+
if (!form) return;
|
|
43
|
+
const onSubmit = (event) => {
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
pendingSubmitRef.current = true;
|
|
46
|
+
setEngaged(true);
|
|
47
|
+
};
|
|
48
|
+
const onEngage = () => setEngaged(true);
|
|
49
|
+
form.addEventListener("submit", onSubmit);
|
|
50
|
+
form.addEventListener("focusin", onEngage);
|
|
51
|
+
form.addEventListener("input", onEngage);
|
|
52
|
+
form.addEventListener("change", onEngage);
|
|
53
|
+
for (const button of Array.from(form.querySelectorAll("button[data-sk-shell-submit]"))) {
|
|
54
|
+
button.disabled = false;
|
|
55
|
+
}
|
|
56
|
+
return () => {
|
|
57
|
+
form.removeEventListener("submit", onSubmit);
|
|
58
|
+
form.removeEventListener("focusin", onEngage);
|
|
59
|
+
form.removeEventListener("input", onEngage);
|
|
60
|
+
form.removeEventListener("change", onEngage);
|
|
61
|
+
};
|
|
62
|
+
}, [Interactive]);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (Interactive || !(idle || engaged)) return;
|
|
65
|
+
let cancelled = false;
|
|
66
|
+
loadInteractiveForm().then((Component) => {
|
|
67
|
+
if (cancelled) return;
|
|
68
|
+
const form = hostRef.current?.querySelector("form") ?? null;
|
|
69
|
+
const active = typeof document !== "undefined" ? document.activeElement : null;
|
|
70
|
+
const focusName = form && active && form.contains(active) ? active.name || null : null;
|
|
71
|
+
setCarried({ values: shellValuesToCarry(form, fields, honeypotName), focusName });
|
|
72
|
+
setInteractive(() => Component);
|
|
73
|
+
}).catch((err) => {
|
|
74
|
+
console.error("[Forms] Enhancement failed to load; keeping the form as rendered:", err);
|
|
75
|
+
});
|
|
76
|
+
return () => {
|
|
77
|
+
cancelled = true;
|
|
78
|
+
};
|
|
79
|
+
}, [Interactive, idle, engaged, fields, honeypotName]);
|
|
80
|
+
const onEnhancedMount = useCallback(() => {
|
|
81
|
+
setEnhanced(true);
|
|
82
|
+
const host = hostRef.current;
|
|
83
|
+
if (!host) return;
|
|
84
|
+
const focusName = carried?.focusName;
|
|
85
|
+
if (focusName) {
|
|
86
|
+
const target = Array.from(host.querySelectorAll("input, select, textarea")).find(
|
|
87
|
+
(el) => el.name === focusName
|
|
88
|
+
);
|
|
89
|
+
target?.focus({ preventScroll: true });
|
|
90
|
+
}
|
|
91
|
+
if (!pendingSubmitRef.current) return;
|
|
92
|
+
pendingSubmitRef.current = false;
|
|
93
|
+
const started = Date.now();
|
|
94
|
+
const tryReplay = () => {
|
|
95
|
+
const form = hostRef.current?.querySelector("form");
|
|
96
|
+
if (form) {
|
|
97
|
+
form.requestSubmit();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (Date.now() - started < REPLAY_WAIT_MS) requestAnimationFrame(tryReplay);
|
|
101
|
+
};
|
|
102
|
+
requestAnimationFrame(tryReplay);
|
|
103
|
+
}, [carried]);
|
|
104
|
+
const seededValues = useMemo(
|
|
105
|
+
() => carried && Object.keys(carried.values).length > 0 ? { ...defaultValues || {}, ...carried.values } : defaultValues,
|
|
106
|
+
[carried, defaultValues]
|
|
107
|
+
);
|
|
108
|
+
return /* @__PURE__ */ jsxs(
|
|
109
|
+
"div",
|
|
110
|
+
{
|
|
111
|
+
ref: hostRef,
|
|
112
|
+
"data-sk-form-mount": enhanced ? "enhanced" : "shell",
|
|
113
|
+
"data-sk-part": "form-mount",
|
|
114
|
+
"data-sk-carried": carried && Object.keys(carried.values).length > 0 ? "true" : void 0,
|
|
115
|
+
style: enter === "fade" ? FADE_HOST : void 0,
|
|
116
|
+
children: [
|
|
117
|
+
enter === "fade" && /* @__PURE__ */ jsx(EnterStyles, {}),
|
|
118
|
+
Interactive ? /* @__PURE__ */ jsx(Enhanced, { onMount: onEnhancedMount, fallback: children, children: /* @__PURE__ */ jsx(
|
|
119
|
+
Interactive,
|
|
120
|
+
{
|
|
121
|
+
formId,
|
|
122
|
+
initialConfig,
|
|
123
|
+
className,
|
|
124
|
+
experience,
|
|
125
|
+
defaultValues: seededValues,
|
|
126
|
+
onSuccess,
|
|
127
|
+
onError
|
|
128
|
+
}
|
|
129
|
+
) }) : children
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
var Enhanced = class extends React.Component {
|
|
135
|
+
constructor() {
|
|
136
|
+
super(...arguments);
|
|
137
|
+
this.state = { failed: false };
|
|
138
|
+
}
|
|
139
|
+
static getDerivedStateFromError() {
|
|
140
|
+
return { failed: true };
|
|
141
|
+
}
|
|
142
|
+
componentDidCatch(err) {
|
|
143
|
+
console.error("[Forms] Enhancement failed; keeping the native form:", err);
|
|
144
|
+
}
|
|
145
|
+
componentDidMount() {
|
|
146
|
+
if (!this.state.failed) this.props.onMount();
|
|
147
|
+
}
|
|
148
|
+
render() {
|
|
149
|
+
if (this.state.failed) return this.props.fallback;
|
|
150
|
+
return /* @__PURE__ */ jsx(FrameTag, { children: this.props.children });
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
function FrameTag({ children }) {
|
|
154
|
+
const ref = useRef(null);
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
const el = ref.current;
|
|
157
|
+
if (!el) return;
|
|
158
|
+
el.setAttribute("data-sk-enter", "");
|
|
159
|
+
const id = requestAnimationFrame(() => el.removeAttribute("data-sk-enter"));
|
|
160
|
+
return () => cancelAnimationFrame(id);
|
|
161
|
+
}, []);
|
|
162
|
+
return /* @__PURE__ */ jsx("div", { ref, style: { display: "contents" }, children });
|
|
163
|
+
}
|
|
164
|
+
var FADE_HOST = {
|
|
165
|
+
transition: "opacity var(--sk-form-enter-duration, 320ms) var(--sk-form-enter-easing, cubic-bezier(.22,1,.36,1))"
|
|
166
|
+
};
|
|
167
|
+
function EnterStyles() {
|
|
168
|
+
return /* @__PURE__ */ jsx(
|
|
169
|
+
"style",
|
|
170
|
+
{
|
|
171
|
+
dangerouslySetInnerHTML: {
|
|
172
|
+
__html: `
|
|
173
|
+
[data-sk-part="form-mount"][data-sk-form-mount="shell"]{opacity:.55}
|
|
174
|
+
[data-sk-part="form-mount"][data-sk-form-mount="enhanced"]{opacity:1}
|
|
175
|
+
[data-sk-part="form-mount"] [data-sk-enter]{opacity:0;transform:translateY(var(--sk-form-enter-distance,6px))}
|
|
176
|
+
[data-sk-part="form-mount"] [data-sk-enter] *{transition:none!important}
|
|
177
|
+
@media (prefers-reduced-motion: reduce){
|
|
178
|
+
[data-sk-part="form-mount"]{transition:none!important}
|
|
179
|
+
[data-sk-part="form-mount"][data-sk-form-mount="shell"]{opacity:1}
|
|
180
|
+
[data-sk-part="form-mount"] [data-sk-enter]{opacity:1;transform:none}
|
|
181
|
+
}`
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export { FormEnhancer };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { secretsMatch, readCappedBody } from './chunk-XTRZGXB2.js';
|
|
2
|
-
import { SITE_KIT_VERSION } from './chunk-
|
|
2
|
+
import { SITE_KIT_VERSION } from './chunk-56KNHB4U.js';
|
|
3
3
|
|
|
4
4
|
// src/llms/revalidate.ts
|
|
5
5
|
function createLlmsRevalidateHandler(secret, options) {
|
|
@@ -16,14 +16,64 @@ var MANAGED_LLM_SCHEMA_KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
|
16
16
|
"speakable",
|
|
17
17
|
"additionalType"
|
|
18
18
|
]);
|
|
19
|
+
var SENTENCE_SHARE = 0.4;
|
|
20
|
+
var ELLIPSIS = "\u2026";
|
|
21
|
+
var CLOSERS = /* @__PURE__ */ new Set(['"', "'", ")", "]", "\u201D", "\u2019", "\xBB"]);
|
|
22
|
+
var ABBREVIATIONS = /* @__PURE__ */ new Set([
|
|
23
|
+
"mr",
|
|
24
|
+
"mrs",
|
|
25
|
+
"ms",
|
|
26
|
+
"dr",
|
|
27
|
+
"prof",
|
|
28
|
+
"st",
|
|
29
|
+
"mt",
|
|
30
|
+
"ft",
|
|
31
|
+
"jr",
|
|
32
|
+
"sr",
|
|
33
|
+
"inc",
|
|
34
|
+
"ltd",
|
|
35
|
+
"co",
|
|
36
|
+
"corp",
|
|
37
|
+
"vs",
|
|
38
|
+
"no"
|
|
39
|
+
]);
|
|
40
|
+
var TRAILING_SEPARATORS = /[\s.,;:\-\u2013\u2014/&([{]+$/;
|
|
41
|
+
function clipAtWordBoundary(text, max) {
|
|
42
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
43
|
+
if (flat.length <= max) return flat;
|
|
44
|
+
if (max < 2) return flat.slice(0, Math.max(0, max));
|
|
45
|
+
const floor = Math.floor(max * (1 - SENTENCE_SHARE));
|
|
46
|
+
for (let end = max; end > floor; end--) {
|
|
47
|
+
if (endsSentence(flat, end)) return flat.slice(0, end);
|
|
48
|
+
}
|
|
49
|
+
const room = max - 1;
|
|
50
|
+
const space = flat.lastIndexOf(" ", room);
|
|
51
|
+
if (space <= 0) return `${flat.slice(0, room)}${ELLIPSIS}`;
|
|
52
|
+
if (endsSentence(flat, space)) return flat.slice(0, space);
|
|
53
|
+
const head = flat.slice(0, space).replace(TRAILING_SEPARATORS, "");
|
|
54
|
+
return `${head || flat.slice(0, room)}${ELLIPSIS}`;
|
|
55
|
+
}
|
|
56
|
+
function endsSentence(flat, end) {
|
|
57
|
+
if (flat[end] !== " ") return false;
|
|
58
|
+
let i = end - 1;
|
|
59
|
+
while (i > 0 && CLOSERS.has(flat[i])) i--;
|
|
60
|
+
const terminator = flat[i];
|
|
61
|
+
if (terminator === "!" || terminator === "?") return true;
|
|
62
|
+
return terminator === "." && !isAbbreviation(flat, i);
|
|
63
|
+
}
|
|
64
|
+
function isAbbreviation(flat, dot) {
|
|
65
|
+
let start = dot;
|
|
66
|
+
while (start > 0 && flat[start - 1] !== " ") start--;
|
|
67
|
+
const token = flat.slice(start, dot).replace(/^[("'[\u201c\u2018]+/, "").toLowerCase();
|
|
68
|
+
if (token.includes(".") || /^[a-z]$/.test(token)) return true;
|
|
69
|
+
return ABBREVIATIONS.has(token);
|
|
70
|
+
}
|
|
19
71
|
function sanitizeLlmsPublicSummary(raw) {
|
|
20
72
|
if (raw === null || raw === void 0) return null;
|
|
21
73
|
if (typeof raw !== "string") return null;
|
|
22
74
|
let s = raw.trim().replace(/\s+/g, " ");
|
|
23
75
|
s = s.replace(/[\[\]\r\n]/g, " ").replace(/\s+/g, " ").trim();
|
|
24
|
-
|
|
25
|
-
s = `${s.slice(0, LLMS_PUBLIC_SUMMARY_MAX_LENGTH - 1).trimEnd()}\u2026`;
|
|
26
|
-
}
|
|
76
|
+
s = clipAtWordBoundary(s, LLMS_PUBLIC_SUMMARY_MAX_LENGTH);
|
|
27
77
|
if (/\b[\w.%+-]+@[\w.-]+\.[A-Za-z]{2,}\b/.test(s)) return null;
|
|
28
78
|
if (/\b\+?\d[\d\s().-]{8,}\b/.test(s)) return null;
|
|
29
79
|
if (s.length < 8) return null;
|
|
@@ -34,9 +84,7 @@ function sanitizeLlmsDisclaimerLine(raw) {
|
|
|
34
84
|
if (typeof raw !== "string") return null;
|
|
35
85
|
let s = raw.trim().replace(/\s+/g, " ");
|
|
36
86
|
s = s.replace(/[\[\]\r\n]/g, " ").replace(/\s+/g, " ").trim();
|
|
37
|
-
|
|
38
|
-
s = `${s.slice(0, LLMS_DISCLAIMER_MAX_LENGTH - 1).trimEnd()}\u2026`;
|
|
39
|
-
}
|
|
87
|
+
s = clipAtWordBoundary(s, LLMS_DISCLAIMER_MAX_LENGTH);
|
|
40
88
|
if (/\b[\w.%+-]+@[\w.-]+\.[A-Za-z]{2,}\b/.test(s)) return null;
|
|
41
89
|
if (/\b\+?\d[\d\s().-]{8,}\b/.test(s)) return null;
|
|
42
90
|
if (s.length < 3) return null;
|
|
@@ -94,4 +142,4 @@ function pickManagedLlmSchemaForJsonLd(schema) {
|
|
|
94
142
|
return Object.keys(out).length ? out : null;
|
|
95
143
|
}
|
|
96
144
|
|
|
97
|
-
export { LLMS_DISCLAIMER_MAX_LENGTH, LLMS_PUBLIC_SUMMARY_MAX_LENGTH, LLM_GEO_CONTRACT_VERSION, MANAGED_LLM_SCHEMA_KNOWN_KEYS, isEmittableReviewNode, pickManagedLlmSchemaForJsonLd, sanitizeLlmsDisclaimerLine, sanitizeLlmsPublicSummary, sanitizePrimaryLanguageTag };
|
|
145
|
+
export { LLMS_DISCLAIMER_MAX_LENGTH, LLMS_PUBLIC_SUMMARY_MAX_LENGTH, LLM_GEO_CONTRACT_VERSION, MANAGED_LLM_SCHEMA_KNOWN_KEYS, clipAtWordBoundary, isEmittableReviewNode, pickManagedLlmSchemaForJsonLd, sanitizeLlmsDisclaimerLine, sanitizeLlmsPublicSummary, sanitizePrimaryLanguageTag };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
|
+
import { VISUAL_VIEWPORT_GAP_PROPERTY } from './chunk-6T6CQVNL.js';
|
|
2
3
|
import { GlassStyles } from './chunk-JE4A5S4F.js';
|
|
3
|
-
import {
|
|
4
|
-
import { useForm } from './chunk-
|
|
4
|
+
import { DEFAULT_WIDGET_Z_INDEX } from './chunk-27FISYK4.js';
|
|
5
|
+
import { useForm } from './chunk-EPT6FJUY.js';
|
|
5
6
|
import { parseColor, relativeLuminance, DARK_LUMINANCE, contrastRatio } from './chunk-S22FSH7C.js';
|
|
6
|
-
import { sonorFetch } from './chunk-
|
|
7
|
+
import { sonorFetch } from './chunk-BEBR4OJD.js';
|
|
7
8
|
import { useState, useEffect, useRef, useLayoutEffect, useCallback, Fragment as Fragment$1 } from 'react';
|
|
8
9
|
import { lexer } from 'marked';
|
|
9
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -144,7 +145,7 @@ function Markdown({ children, components }) {
|
|
|
144
145
|
return /* @__PURE__ */ jsx(Fragment, { children: blocks(lexer(children, { gfm: true }), components) });
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
// src/
|
|
148
|
+
// src/chat/brand-color.ts
|
|
148
149
|
var TEXT_CONTRAST = 4.5;
|
|
149
150
|
var RESTING_TINT = 0.082;
|
|
150
151
|
var UNREADABLE_BRAND_SHARE = 40;
|
|
@@ -454,7 +455,40 @@ function EchoUiActions({ actions, primaryColor, primaryRgb, brandText, onSuggest
|
|
|
454
455
|
] });
|
|
455
456
|
}
|
|
456
457
|
|
|
457
|
-
// src/
|
|
458
|
+
// src/chat/launcher-placement.ts
|
|
459
|
+
var DEFAULT_LAUNCHER_OFFSET_BOTTOM = "20px";
|
|
460
|
+
var LAUNCHER_OFFSET_PROPERTY = "--sk-echo-offset-bottom";
|
|
461
|
+
var SIDE_GUTTER = "20px";
|
|
462
|
+
var POPUP_ABOVE_LAUNCHER = "70px";
|
|
463
|
+
var POPUP_VERTICAL_RESERVE = "100px";
|
|
464
|
+
function toCssLength(value) {
|
|
465
|
+
if (typeof value === "number") return Number.isFinite(value) ? `${value}px` : void 0;
|
|
466
|
+
const trimmed = value?.trim();
|
|
467
|
+
return trimmed ? trimmed : void 0;
|
|
468
|
+
}
|
|
469
|
+
function chatLauncherStyles({ position, offsetBottom, zIndex } = {}) {
|
|
470
|
+
const side = position === "bottom-left" ? { left: SIDE_GUTTER } : { right: SIDE_GUTTER };
|
|
471
|
+
const offset = toCssLength(offsetBottom) ?? DEFAULT_LAUNCHER_OFFSET_BOTTOM;
|
|
472
|
+
const layer = typeof zIndex === "number" && Number.isFinite(zIndex) ? zIndex : DEFAULT_WIDGET_Z_INDEX;
|
|
473
|
+
const clearance = `var(${LAUNCHER_OFFSET_PROPERTY}, ${offset}) + env(safe-area-inset-bottom, 0px) + var(${VISUAL_VIEWPORT_GAP_PROPERTY}, 0px)`;
|
|
474
|
+
return {
|
|
475
|
+
launcher: {
|
|
476
|
+
...side,
|
|
477
|
+
bottom: `calc(${clearance})`
|
|
478
|
+
},
|
|
479
|
+
popup: {
|
|
480
|
+
...side,
|
|
481
|
+
bottom: `calc(${clearance} + ${POPUP_ABOVE_LAUNCHER})`,
|
|
482
|
+
maxHeight: `calc(100dvh - (${clearance}) - ${POPUP_VERTICAL_RESERVE})`
|
|
483
|
+
},
|
|
484
|
+
// One beneath the launcher. At 0 or below, the same layer instead: -1
|
|
485
|
+
// would paint the popup behind the page's own content, and at a shared
|
|
486
|
+
// layer the launcher, which renders after the popup, still paints on top.
|
|
487
|
+
zIndex: { launcher: layer, popup: layer > 0 ? layer - 1 : layer }
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// src/chat/chat-messages.ts
|
|
458
492
|
function userRequestedHandoff(text) {
|
|
459
493
|
const lower = text.toLowerCase().trim();
|
|
460
494
|
const patterns = [
|
|
@@ -839,7 +873,7 @@ function EchoChat({ projectId, widgetConfig, config, apiUrl: propApiUrl, signalU
|
|
|
839
873
|
socketRef.current.disconnect();
|
|
840
874
|
socketRef.current = null;
|
|
841
875
|
}
|
|
842
|
-
const { createSocket } = await import('./socket-loader-
|
|
876
|
+
const { createSocket } = await import('./socket-loader-CGIPEG74.js');
|
|
843
877
|
const namespaceUrl = `${baseUrl.replace(/\/$/, "")}/engage/chat`;
|
|
844
878
|
const socket = await createSocket(namespaceUrl, {
|
|
845
879
|
query: { projectId, visitorId, sessionId: currentSessionId },
|
|
@@ -1800,4 +1834,4 @@ function EchoChat({ projectId, widgetConfig, config, apiUrl: propApiUrl, signalU
|
|
|
1800
1834
|
] });
|
|
1801
1835
|
}
|
|
1802
1836
|
|
|
1803
|
-
export { ChatWidget, EchoChat, isChatEnabled };
|
|
1837
|
+
export { ChatWidget, DEFAULT_LAUNCHER_OFFSET_BOTTOM, EchoChat, chatLauncherStyles, isChatEnabled };
|