@sonordev/site-kit 4.0.0 → 4.0.2
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/agent-manifest.json +6 -1
- package/dist/AnalyticsProvider-5SX4ZRGN.js +31 -0
- package/dist/{AnalyticsProvider-HZTP36TY.js.map → AnalyticsProvider-5SX4ZRGN.js.map} +1 -1
- package/dist/AnalyticsProvider-6DIRTRRA.mjs +10 -0
- package/dist/{AnalyticsProvider-P6J5ZGZB.mjs.map → AnalyticsProvider-6DIRTRRA.mjs.map} +1 -1
- package/dist/ChatWidget-3SUC7HZA.js +20 -0
- package/dist/{ChatWidget-XJFFNLTK.js.map → ChatWidget-3SUC7HZA.js.map} +1 -1
- package/dist/ChatWidget-JTTERPI5.mjs +11 -0
- package/dist/{ChatWidget-Q4YJUQ36.mjs.map → ChatWidget-JTTERPI5.mjs.map} +1 -1
- package/dist/DatePicker-4WNKNNCV.mjs +4 -0
- package/dist/DatePicker-4WNKNNCV.mjs.map +1 -0
- package/dist/DatePicker-VPZR7RU3.js +13 -0
- package/dist/DatePicker-VPZR7RU3.js.map +1 -0
- package/dist/EngageWidget-3MDY2W5G.mjs +9 -0
- package/dist/{EngageWidget-IMQBLBII.mjs.map → EngageWidget-3MDY2W5G.mjs.map} +1 -1
- package/dist/EngageWidget-YVAIP2NW.js +18 -0
- package/dist/{EngageWidget-NGPAVLLE.js.map → EngageWidget-YVAIP2NW.js.map} +1 -1
- package/dist/FileField-PD52URLX.js +91 -0
- package/dist/FileField-PD52URLX.js.map +1 -0
- package/dist/FileField-XMBF3XCG.mjs +85 -0
- package/dist/FileField-XMBF3XCG.mjs.map +1 -0
- package/dist/{FormSpotlight-5YFKFZYS.mjs → FormSpotlight-72TYHDPV.mjs} +8 -7
- package/dist/FormSpotlight-72TYHDPV.mjs.map +1 -0
- package/dist/{FormSpotlight-7BH6QE6T.js → FormSpotlight-AL6KGMGG.js} +23 -22
- package/dist/FormSpotlight-AL6KGMGG.js.map +1 -0
- package/dist/{FormStage-KB4GYL5K.mjs → FormStage-GNBPJ7WX.mjs} +7 -7
- package/dist/FormStage-GNBPJ7WX.mjs.map +1 -0
- package/dist/{FormStage-7BVPTSSE.js → FormStage-NLO52ER2.js} +19 -19
- package/dist/FormStage-NLO52ER2.js.map +1 -0
- package/dist/ManagedForm-2SYVMJY6.mjs +14 -0
- package/dist/ManagedForm-2SYVMJY6.mjs.map +1 -0
- package/dist/ManagedForm-XWN3TVQQ.js +23 -0
- package/dist/ManagedForm-XWN3TVQQ.js.map +1 -0
- package/dist/{SignalCore-6GXPHNFA.mjs → SignalCore-4NOVH33M.mjs} +5 -5
- package/dist/{SignalCore-6GXPHNFA.mjs.map → SignalCore-4NOVH33M.mjs.map} +1 -1
- package/dist/{SignalCore-LJ3NUEU4.js → SignalCore-PD75O7GB.js} +11 -11
- package/dist/{SignalCore-LJ3NUEU4.js.map → SignalCore-PD75O7GB.js.map} +1 -1
- package/dist/SitemapSync-KKUF43DS.js +17 -0
- package/dist/{SitemapSync-BG2ZWSM6.js.map → SitemapSync-KKUF43DS.js.map} +1 -1
- package/dist/SitemapSync-UH6VZ55T.mjs +8 -0
- package/dist/{SitemapSync-5DGS2XLM.mjs.map → SitemapSync-UH6VZ55T.mjs.map} +1 -1
- package/dist/analytics/index.js +9 -9
- package/dist/analytics/index.mjs +4 -4
- package/dist/{chunk-BFADBU2B.js → chunk-2ACKOMAL.js} +105 -514
- package/dist/chunk-2ACKOMAL.js.map +1 -0
- package/dist/{chunk-64DQANST.js → chunk-2MIOQYF5.js} +6 -6
- package/dist/{chunk-64DQANST.js.map → chunk-2MIOQYF5.js.map} +1 -1
- package/dist/{chunk-FLTTRX4O.mjs → chunk-53RHVKTD.mjs} +5 -5
- package/dist/{chunk-FLTTRX4O.mjs.map → chunk-53RHVKTD.mjs.map} +1 -1
- package/dist/{chunk-NQRUCOI7.js → chunk-5QVXHD6V.js} +14 -14
- package/dist/{chunk-NQRUCOI7.js.map → chunk-5QVXHD6V.js.map} +1 -1
- package/dist/{chunk-J6UKM476.js → chunk-62Z4D3QR.js} +5 -5
- package/dist/{chunk-J6UKM476.js.map → chunk-62Z4D3QR.js.map} +1 -1
- package/dist/{chunk-744TJ7SN.mjs → chunk-6PNWJXAE.mjs} +3 -3
- package/dist/{chunk-744TJ7SN.mjs.map → chunk-6PNWJXAE.mjs.map} +1 -1
- package/dist/{chunk-NKKXKN5L.mjs → chunk-6ZFXASW6.mjs} +4 -4
- package/dist/{chunk-NKKXKN5L.mjs.map → chunk-6ZFXASW6.mjs.map} +1 -1
- package/dist/{chunk-YNIZKOEW.js → chunk-A624YYDG.js} +2 -2
- package/dist/{chunk-YNIZKOEW.js.map → chunk-A624YYDG.js.map} +1 -1
- package/dist/chunk-AJNT5GCU.mjs +183 -0
- package/dist/chunk-AJNT5GCU.mjs.map +1 -0
- package/dist/chunk-AQA4PFMJ.mjs +44 -0
- package/dist/chunk-AQA4PFMJ.mjs.map +1 -0
- package/dist/{chunk-AVHXVWWG.mjs → chunk-B7J7SU5A.mjs} +8 -8
- package/dist/{chunk-AVHXVWWG.mjs.map → chunk-B7J7SU5A.mjs.map} +1 -1
- package/dist/chunk-DVYYGHSG.js +285 -0
- package/dist/chunk-DVYYGHSG.js.map +1 -0
- package/dist/{chunk-HUYPO33T.mjs → chunk-FGN27J35.mjs} +4 -4
- package/dist/{chunk-HUYPO33T.mjs.map → chunk-FGN27J35.mjs.map} +1 -1
- package/dist/{chunk-O5Z7ZKYS.mjs → chunk-FZ643CZK.mjs} +4 -4
- package/dist/{chunk-O5Z7ZKYS.mjs.map → chunk-FZ643CZK.mjs.map} +1 -1
- package/dist/{chunk-3IXGYUUR.mjs → chunk-GCS4XZHC.mjs} +3 -3
- package/dist/{chunk-3IXGYUUR.mjs.map → chunk-GCS4XZHC.mjs.map} +1 -1
- package/dist/{chunk-BH3XILNX.mjs → chunk-HOB2A6JM.mjs} +3 -3
- package/dist/{chunk-BH3XILNX.mjs.map → chunk-HOB2A6JM.mjs.map} +1 -1
- package/dist/{chunk-U3OU4V56.mjs → chunk-JFVEKSZT.mjs} +5 -182
- package/dist/chunk-JFVEKSZT.mjs.map +1 -0
- package/dist/{chunk-PMCNKBYS.mjs → chunk-KNYK2VLX.mjs} +3 -3
- package/dist/{chunk-PMCNKBYS.mjs.map → chunk-KNYK2VLX.mjs.map} +1 -1
- package/dist/{chunk-6DJEXHZE.mjs → chunk-LB7LHVWI.mjs} +107 -503
- package/dist/chunk-LB7LHVWI.mjs.map +1 -0
- package/dist/{chunk-YOTQH4X4.js → chunk-LP6MC2RH.js} +14 -14
- package/dist/{chunk-YOTQH4X4.js.map → chunk-LP6MC2RH.js.map} +1 -1
- package/dist/chunk-LVCUT2OX.js +148 -0
- package/dist/chunk-LVCUT2OX.js.map +1 -0
- package/dist/chunk-LYAU5PRS.js +8 -0
- package/dist/{chunk-T7QIXFFM.js.map → chunk-LYAU5PRS.js.map} +1 -1
- package/dist/{chunk-OTAIUZED.js → chunk-MPACJDDG.js} +8 -8
- package/dist/{chunk-OTAIUZED.js.map → chunk-MPACJDDG.js.map} +1 -1
- package/dist/{chunk-W4WGNWQG.js → chunk-MRRTAJWQ.js} +3 -3
- package/dist/{chunk-W4WGNWQG.js.map → chunk-MRRTAJWQ.js.map} +1 -1
- package/dist/chunk-MU3D5IO7.mjs +283 -0
- package/dist/chunk-MU3D5IO7.mjs.map +1 -0
- package/dist/{chunk-L5NLP3EW.js → chunk-MVHR77V4.js} +11 -2
- package/dist/chunk-MVHR77V4.js.map +1 -0
- package/dist/chunk-MZY3MEUO.mjs +138 -0
- package/dist/chunk-MZY3MEUO.mjs.map +1 -0
- package/dist/chunk-NCWVR4BU.mjs +508 -0
- package/dist/chunk-NCWVR4BU.mjs.map +1 -0
- package/dist/{chunk-LKZF7343.js → chunk-NJN467OM.js} +14 -14
- package/dist/{chunk-LKZF7343.js.map → chunk-NJN467OM.js.map} +1 -1
- package/dist/{chunk-EZCDDRXA.mjs → chunk-NWJX6NHR.mjs} +4 -4
- package/dist/{chunk-EZCDDRXA.mjs.map → chunk-NWJX6NHR.mjs.map} +1 -1
- package/dist/chunk-NWPNFCNY.js +511 -0
- package/dist/chunk-NWPNFCNY.js.map +1 -0
- package/dist/{chunk-P64SKDBS.js → chunk-OP5FYTWJ.js} +12 -191
- package/dist/chunk-OP5FYTWJ.js.map +1 -0
- package/dist/{chunk-JM5JCIAY.js → chunk-PGND73EV.js} +4 -4
- package/dist/{chunk-JM5JCIAY.js.map → chunk-PGND73EV.js.map} +1 -1
- package/dist/chunk-QO5NS62X.js +46 -0
- package/dist/chunk-QO5NS62X.js.map +1 -0
- package/dist/chunk-QTN3F7D7.mjs +6 -0
- package/dist/{chunk-LLQEJDCA.mjs.map → chunk-QTN3F7D7.mjs.map} +1 -1
- package/dist/chunk-R4PCXP3F.mjs +60 -0
- package/dist/chunk-R4PCXP3F.mjs.map +1 -0
- package/dist/{chunk-BOWEGDKJ.js → chunk-RAX3HS4T.js} +15 -15
- package/dist/{chunk-BOWEGDKJ.js.map → chunk-RAX3HS4T.js.map} +1 -1
- package/dist/{chunk-SXE2TRRU.js → chunk-T2YAEBEY.js} +4 -4
- package/dist/{chunk-SXE2TRRU.js.map → chunk-T2YAEBEY.js.map} +1 -1
- package/dist/{chunk-I76F26IS.mjs → chunk-T5DXYGWK.mjs} +3 -3
- package/dist/{chunk-I76F26IS.mjs.map → chunk-T5DXYGWK.mjs.map} +1 -1
- package/dist/{chunk-KHJYA64F.mjs → chunk-U2CJZ6O5.mjs} +2 -2
- package/dist/{chunk-KHJYA64F.mjs.map → chunk-U2CJZ6O5.mjs.map} +1 -1
- package/dist/{chunk-TUVJQ6FS.mjs → chunk-UBNVD567.mjs} +3 -3
- package/dist/{chunk-TUVJQ6FS.mjs.map → chunk-UBNVD567.mjs.map} +1 -1
- package/dist/chunk-UQPUFRXF.mjs +104 -0
- package/dist/chunk-UQPUFRXF.mjs.map +1 -0
- package/dist/chunk-VLY3SFNH.js +64 -0
- package/dist/chunk-VLY3SFNH.js.map +1 -0
- package/dist/{chunk-MVMORDOM.mjs → chunk-VUIQLKJB.mjs} +3 -3
- package/dist/{chunk-MVMORDOM.mjs.map → chunk-VUIQLKJB.mjs.map} +1 -1
- package/dist/chunk-WHVUSVHA.js +110 -0
- package/dist/chunk-WHVUSVHA.js.map +1 -0
- package/dist/{chunk-H4F557CO.js → chunk-WNNY2BCV.js} +8 -8
- package/dist/{chunk-H4F557CO.js.map → chunk-WNNY2BCV.js.map} +1 -1
- package/dist/{chunk-KN2EYZYV.mjs → chunk-WSPGXSBU.mjs} +11 -2
- package/dist/chunk-WSPGXSBU.mjs.map +1 -0
- package/dist/{chunk-ZLVZOAJG.js → chunk-WXKEYKE6.js} +15 -15
- package/dist/{chunk-ZLVZOAJG.js.map → chunk-WXKEYKE6.js.map} +1 -1
- package/dist/{chunk-NWYXTJNW.mjs → chunk-XNPITFJ5.mjs} +3 -3
- package/dist/{chunk-NWYXTJNW.mjs.map → chunk-XNPITFJ5.mjs.map} +1 -1
- package/dist/{chunk-ZBFBNGQK.mjs → chunk-XRC3JZAK.mjs} +3 -3
- package/dist/{chunk-ZBFBNGQK.mjs.map → chunk-XRC3JZAK.mjs.map} +1 -1
- package/dist/{chunk-OWQFWDE2.js → chunk-Y26LKDE4.js} +9 -9
- package/dist/{chunk-OWQFWDE2.js.map → chunk-Y26LKDE4.js.map} +1 -1
- package/dist/{chunk-2OD3EGPO.js → chunk-ZK5VSIRO.js} +12 -12
- package/dist/{chunk-2OD3EGPO.js.map → chunk-ZK5VSIRO.js.map} +1 -1
- package/dist/{chunk-IPQ7Z5VT.js → chunk-ZPG4GTU7.js} +5 -5
- package/dist/{chunk-IPQ7Z5VT.js.map → chunk-ZPG4GTU7.js.map} +1 -1
- package/dist/chunk-ZRGCKWIT.js +188 -0
- package/dist/chunk-ZRGCKWIT.js.map +1 -0
- package/dist/cli/index.js +3 -3
- package/dist/cli/index.mjs +1 -1
- package/dist/client/index.js +5 -5
- package/dist/client/index.mjs +4 -4
- package/dist/commerce/index.js +56 -56
- package/dist/commerce/index.mjs +5 -5
- package/dist/engage/index.js +10 -9
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +7 -6
- package/dist/engage/index.mjs.map +1 -1
- package/dist/fleet/index.js +9 -9
- package/dist/fleet/index.mjs +5 -5
- package/dist/forms/FileField.d.ts +31 -0
- package/dist/forms/FileField.d.ts.map +1 -0
- package/dist/forms/FormClient.d.ts +12 -1
- package/dist/forms/FormClient.d.ts.map +1 -1
- package/dist/forms/FormEnhancer.d.ts +72 -0
- package/dist/forms/FormEnhancer.d.ts.map +1 -0
- package/dist/forms/FormField.d.ts +26 -3
- package/dist/forms/FormField.d.ts.map +1 -1
- package/dist/forms/FormSpotlight.d.ts.map +1 -1
- package/dist/forms/FormStage.d.ts.map +1 -1
- package/dist/forms/HoneypotField.d.ts +8 -2
- package/dist/forms/HoneypotField.d.ts.map +1 -1
- package/dist/forms/ManagedForm.d.ts +1 -1
- package/dist/forms/ManagedForm.d.ts.map +1 -1
- package/dist/forms/ServerForm.d.ts +73 -0
- package/dist/forms/ServerForm.d.ts.map +1 -0
- package/dist/forms/StaticForm.d.ts +50 -0
- package/dist/forms/StaticForm.d.ts.map +1 -0
- package/dist/forms/experience-chrome.d.ts.map +1 -1
- package/dist/forms/field-controls.d.ts +7 -0
- package/dist/forms/field-controls.d.ts.map +1 -0
- package/dist/forms/index.d.ts +7 -0
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +33 -537
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +14 -530
- package/dist/forms/index.mjs.map +1 -1
- package/dist/forms/native-fallback.d.ts +41 -0
- package/dist/forms/native-fallback.d.ts.map +1 -0
- package/dist/forms/native-fallback.test.d.ts +2 -0
- package/dist/forms/native-fallback.test.d.ts.map +1 -0
- package/dist/forms/normalize-config.d.ts +18 -0
- package/dist/forms/normalize-config.d.ts.map +1 -0
- package/dist/forms/server.d.ts +5 -0
- package/dist/forms/server.d.ts.map +1 -1
- package/dist/forms/server.js +47 -0
- package/dist/forms/server.js.map +1 -1
- package/dist/forms/server.mjs +44 -1
- package/dist/forms/server.mjs.map +1 -1
- package/dist/forms/static-form.test.d.ts +2 -0
- package/dist/forms/static-form.test.d.ts.map +1 -0
- package/dist/forms/static.d.ts +17 -0
- package/dist/forms/static.d.ts.map +1 -0
- package/dist/forms/static.js +20 -0
- package/dist/forms/static.js.map +1 -0
- package/dist/forms/static.mjs +11 -0
- package/dist/forms/static.mjs.map +1 -0
- package/dist/forms/submitForm.d.ts +4 -0
- package/dist/forms/submitForm.d.ts.map +1 -1
- package/dist/forms/types.d.ts +19 -0
- package/dist/forms/types.d.ts.map +1 -1
- package/dist/forms/useForm.d.ts.map +1 -1
- package/dist/images/index.js +11 -11
- package/dist/images/index.mjs +4 -4
- package/dist/index.js +109 -109
- package/dist/index.mjs +9 -9
- package/dist/layout/client.js +9 -9
- package/dist/layout/client.mjs +8 -8
- package/dist/layout/index.js +11 -11
- package/dist/layout/index.mjs +9 -9
- package/dist/maps/index.js +5 -5
- package/dist/maps/index.mjs +3 -3
- package/dist/search/index.js +4 -4
- package/dist/search/index.mjs +3 -3
- package/dist/seo/client.js +5 -5
- package/dist/seo/client.mjs +4 -4
- package/dist/seo/index.js +14 -14
- package/dist/seo/index.mjs +6 -6
- package/dist/seo/server.js +5 -5
- package/dist/seo/server.mjs +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +2 -2
- package/dist/shared/build-entries.d.ts +6 -0
- package/dist/shared/build-entries.d.ts.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sync/index.js +16 -16
- package/dist/sync/index.mjs +4 -4
- package/package.json +9 -4
- package/dist/AnalyticsProvider-HZTP36TY.js +0 -31
- package/dist/AnalyticsProvider-P6J5ZGZB.mjs +0 -10
- package/dist/ChatWidget-Q4YJUQ36.mjs +0 -10
- package/dist/ChatWidget-XJFFNLTK.js +0 -19
- package/dist/EngageWidget-IMQBLBII.mjs +0 -9
- package/dist/EngageWidget-NGPAVLLE.js +0 -18
- package/dist/FormSpotlight-5YFKFZYS.mjs.map +0 -1
- package/dist/FormSpotlight-7BH6QE6T.js.map +0 -1
- package/dist/FormStage-7BVPTSSE.js.map +0 -1
- package/dist/FormStage-KB4GYL5K.mjs.map +0 -1
- package/dist/SitemapSync-5DGS2XLM.mjs +0 -8
- package/dist/SitemapSync-BG2ZWSM6.js +0 -17
- package/dist/chunk-6DJEXHZE.mjs.map +0 -1
- package/dist/chunk-BFADBU2B.js.map +0 -1
- package/dist/chunk-KN2EYZYV.mjs.map +0 -1
- package/dist/chunk-L5NLP3EW.js.map +0 -1
- package/dist/chunk-LLQEJDCA.mjs +0 -6
- package/dist/chunk-P64SKDBS.js.map +0 -1
- package/dist/chunk-T7QIXFFM.js +0 -8
- package/dist/chunk-U3OU4V56.mjs.map +0 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useDeferredActivation } from './chunk-ZVBLXXNJ.mjs';
|
|
3
|
+
import React, { lazy, useRef, useEffect, useState, Suspense } from 'react';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var InteractiveForm = lazy(
|
|
7
|
+
() => import('./ManagedForm-2SYVMJY6.mjs').then((m) => ({ default: m.ManagedForm }))
|
|
8
|
+
);
|
|
9
|
+
function FormEnhancer({
|
|
10
|
+
formId,
|
|
11
|
+
initialConfig,
|
|
12
|
+
className,
|
|
13
|
+
nativeReturnTo,
|
|
14
|
+
experience,
|
|
15
|
+
defaultValues,
|
|
16
|
+
onSuccess,
|
|
17
|
+
onError,
|
|
18
|
+
enter = "fade",
|
|
19
|
+
defer = true,
|
|
20
|
+
children
|
|
21
|
+
}) {
|
|
22
|
+
const ready = useDeferredActivation(defer);
|
|
23
|
+
const [enhanced, setEnhanced] = useState(false);
|
|
24
|
+
return /* @__PURE__ */ jsxs(
|
|
25
|
+
"div",
|
|
26
|
+
{
|
|
27
|
+
"data-sk-form-mount": enhanced ? "enhanced" : "shell",
|
|
28
|
+
"data-sk-part": "form-mount",
|
|
29
|
+
style: enter === "fade" ? FADE_HOST : void 0,
|
|
30
|
+
children: [
|
|
31
|
+
enter === "fade" && /* @__PURE__ */ jsx(EnterStyles, {}),
|
|
32
|
+
ready ? /* @__PURE__ */ jsx(Suspense, { fallback: children, children: /* @__PURE__ */ jsx(Enhanced, { onMount: () => setEnhanced(true), fallback: children, children: /* @__PURE__ */ jsx(
|
|
33
|
+
InteractiveForm,
|
|
34
|
+
{
|
|
35
|
+
formId,
|
|
36
|
+
initialConfig,
|
|
37
|
+
className,
|
|
38
|
+
nativeReturnTo,
|
|
39
|
+
experience,
|
|
40
|
+
defaultValues,
|
|
41
|
+
onSuccess,
|
|
42
|
+
onError
|
|
43
|
+
}
|
|
44
|
+
) }) }) : children
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
var Enhanced = class extends React.Component {
|
|
50
|
+
constructor() {
|
|
51
|
+
super(...arguments);
|
|
52
|
+
this.state = { failed: false };
|
|
53
|
+
}
|
|
54
|
+
static getDerivedStateFromError() {
|
|
55
|
+
return { failed: true };
|
|
56
|
+
}
|
|
57
|
+
componentDidCatch(err) {
|
|
58
|
+
console.error("[Forms] Enhancement failed; keeping the native form:", err);
|
|
59
|
+
}
|
|
60
|
+
componentDidMount() {
|
|
61
|
+
if (!this.state.failed) this.props.onMount();
|
|
62
|
+
}
|
|
63
|
+
render() {
|
|
64
|
+
if (this.state.failed) return this.props.fallback;
|
|
65
|
+
return /* @__PURE__ */ jsx(FrameTag, { children: this.props.children });
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function FrameTag({ children }) {
|
|
69
|
+
const ref = useRef(null);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
const el = ref.current;
|
|
72
|
+
if (!el) return;
|
|
73
|
+
el.setAttribute("data-sk-enter", "");
|
|
74
|
+
const id = requestAnimationFrame(() => el.removeAttribute("data-sk-enter"));
|
|
75
|
+
return () => cancelAnimationFrame(id);
|
|
76
|
+
}, []);
|
|
77
|
+
return /* @__PURE__ */ jsx("div", { ref, style: { display: "contents" }, children });
|
|
78
|
+
}
|
|
79
|
+
var FADE_HOST = {
|
|
80
|
+
transition: "opacity var(--sk-form-enter-duration, 320ms) var(--sk-form-enter-easing, cubic-bezier(.22,1,.36,1))"
|
|
81
|
+
};
|
|
82
|
+
function EnterStyles() {
|
|
83
|
+
return /* @__PURE__ */ jsx(
|
|
84
|
+
"style",
|
|
85
|
+
{
|
|
86
|
+
dangerouslySetInnerHTML: {
|
|
87
|
+
__html: `
|
|
88
|
+
[data-sk-part="form-mount"][data-sk-form-mount="shell"]{opacity:.55}
|
|
89
|
+
[data-sk-part="form-mount"][data-sk-form-mount="enhanced"]{opacity:1}
|
|
90
|
+
[data-sk-part="form-mount"] [data-sk-enter]{opacity:0;transform:translateY(var(--sk-form-enter-distance,6px))}
|
|
91
|
+
[data-sk-part="form-mount"] [data-sk-enter] *{transition:none!important}
|
|
92
|
+
@media (prefers-reduced-motion: reduce){
|
|
93
|
+
[data-sk-part="form-mount"]{transition:none!important}
|
|
94
|
+
[data-sk-part="form-mount"][data-sk-form-mount="shell"]{opacity:1}
|
|
95
|
+
[data-sk-part="form-mount"] [data-sk-enter]{opacity:1;transform:none}
|
|
96
|
+
}`
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { FormEnhancer };
|
|
103
|
+
//# sourceMappingURL=chunk-UQPUFRXF.mjs.map
|
|
104
|
+
//# sourceMappingURL=chunk-UQPUFRXF.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forms/FormEnhancer.tsx"],"names":[],"mappings":"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","file":"chunk-UQPUFRXF.mjs","sourcesContent":["'use client'\n\n/**\n * FormEnhancer — the only client code a managed form needs up front.\n *\n * Renders the server-rendered shell (<StaticForm>, passed as `children`) until\n * an idle/first-interaction gate fires, then lazy-imports the interactive form\n * and swaps it in. Everything expensive — validation, conditional logic,\n * spotlight/stage, celebration, momentum — lives behind that dynamic import,\n * so a page ships this boundary and nothing else in its initial chunk set.\n *\n * The shell is a REAL form the whole time (native action + signed token), so\n * the progression is:\n *\n * no JS at all -> shell, submits natively. Works.\n * JS, pre-idle -> shell, submits natively. Works.\n * JS, post-idle -> enhanced form, submits over JSON. Works, with delight.\n * chunk 404s -> shell stays. Works. (Never left blank.)\n *\n * That last line is the invariant to protect: the shell is only removed once\n * the enhancement has actually rendered. Do not \"hide the shell then load\" —\n * a CDN hiccup would leave a visitor staring at an empty box where the form\n * used to be.\n *\n * ── Entrance animation ──────────────────────────────────────────────────\n *\n * Above-the-fold forms upgrade while the visitor is looking at them, so the\n * swap must not pop. The wrapper carries `data-sk-form-mount=\"shell\"` and\n * flips to `\"enhanced\"`, and the enhanced form gets `data-sk-enter` for one\n * frame, so a site can style the transition entirely in CSS:\n *\n * [data-sk-form-mount] { transition: opacity .35s ease }\n * [data-sk-form-mount=\"shell\"] { opacity: .6 }\n *\n * Defaults ship as CSS variables rather than hard-coded values:\n *\n * --sk-form-enter-duration (default 320ms)\n * --sk-form-enter-easing (default cubic-bezier(.22,1,.36,1))\n * --sk-form-enter-distance (default 6px)\n *\n * `enter=\"none\"` opts out entirely; `enter=\"custom\"` emits the data\n * attributes but no site-kit styles, leaving the animation to the site.\n * Every default is collapsed by prefers-reduced-motion.\n */\n\nimport React, { lazy, Suspense, useEffect, useRef, useState } from 'react'\nimport { useDeferredActivation } from '../shared/defer'\nimport type { FormExperience, FormSubmission } from './types'\n\n/** The heavy half. Nothing else in this module may import it statically. */\nconst InteractiveForm = lazy(() =>\n import('./ManagedForm').then((m) => ({ default: m.ManagedForm })),\n)\n\nexport type FormEnterAnimation = 'fade' | 'none' | 'custom'\n\nexport interface FormEnhancerProps {\n formId: string\n /** Server-fetched raw config — hands the enhancement its fields instantly. */\n initialConfig?: Record<string, unknown> | null\n className?: string\n nativeReturnTo?: string\n experience?: FormExperience\n /** Pre-fill field values by slug. See ManagedForm.defaultValues. */\n defaultValues?: Record<string, unknown>\n onSuccess?: (submission: FormSubmission) => void\n onError?: (error: Error) => void\n /**\n * How the enhanced form arrives. 'fade' (default) crossfades and lifts it\n * into place; 'none' swaps instantly; 'custom' emits the data attributes\n * and no styles so the site owns the animation.\n */\n enter?: FormEnterAnimation\n /**\n * Set false to enhance immediately instead of waiting for idle. Only worth\n * it for a form that is the entire point of the page AND above the fold.\n */\n defer?: boolean\n /** The server-rendered <StaticForm>. Shown until the enhancement mounts. */\n children: React.ReactNode\n}\n\nexport function FormEnhancer({\n formId,\n initialConfig,\n className,\n nativeReturnTo,\n experience,\n defaultValues,\n onSuccess,\n onError,\n enter = 'fade',\n defer = true,\n children,\n}: FormEnhancerProps) {\n const ready = useDeferredActivation(defer)\n // Flipped only after the enhancement has actually committed to the DOM, so\n // the shell never disappears ahead of its replacement.\n const [enhanced, setEnhanced] = useState(false)\n\n return (\n <div\n data-sk-form-mount={enhanced ? 'enhanced' : 'shell'}\n data-sk-part=\"form-mount\"\n style={enter === 'fade' ? FADE_HOST : undefined}\n >\n {enter === 'fade' && <EnterStyles />}\n {ready ? (\n <Suspense fallback={children}>\n <Enhanced onMount={() => setEnhanced(true)} fallback={children}>\n <InteractiveForm\n formId={formId}\n initialConfig={initialConfig}\n className={className}\n nativeReturnTo={nativeReturnTo}\n experience={experience}\n defaultValues={defaultValues}\n onSuccess={onSuccess}\n onError={onError}\n />\n </Enhanced>\n </Suspense>\n ) : (\n children\n )}\n </div>\n )\n}\n\n/**\n * Reports the moment the enhancement is on screen, and keeps the shell\n * rendered if it throws. An error boundary is the difference between \"the\n * fancy version failed\" and \"there is no form on this page\".\n */\nclass Enhanced extends React.Component<\n { onMount: () => void; fallback: React.ReactNode; children: React.ReactNode },\n { failed: boolean }\n> {\n state = { failed: false }\n\n static getDerivedStateFromError() {\n return { failed: true }\n }\n\n componentDidCatch(err: unknown) {\n console.error('[Forms] Enhancement failed; keeping the native form:', err)\n }\n\n componentDidMount() {\n if (!this.state.failed) this.props.onMount()\n }\n\n render() {\n if (this.state.failed) return this.props.fallback\n return <FrameTag>{this.props.children}</FrameTag>\n }\n}\n\n/** Adds data-sk-enter for one frame so a CSS transition has something to run. */\nfunction FrameTag({ children }: { children: React.ReactNode }) {\n const ref = useRef<HTMLDivElement>(null)\n useEffect(() => {\n const el = ref.current\n if (!el) return\n el.setAttribute('data-sk-enter', '')\n const id = requestAnimationFrame(() => el.removeAttribute('data-sk-enter'))\n return () => cancelAnimationFrame(id)\n }, [])\n return (\n <div ref={ref} style={{ display: 'contents' }}>\n {children}\n </div>\n )\n}\n\nconst FADE_HOST: React.CSSProperties = {\n transition:\n 'opacity var(--sk-form-enter-duration, 320ms) var(--sk-form-enter-easing, cubic-bezier(.22,1,.36,1))',\n}\n\n/**\n * Scoped to [data-sk-part=\"form-mount\"] so it can never touch a site's own\n * markup. Emitted once per form; identical text dedupes in every browser's\n * style cache and gzips to nothing.\n */\nfunction EnterStyles() {\n return (\n <style\n // biome-ignore lint/security/noDangerouslySetInnerHtml: static string, no interpolation\n dangerouslySetInnerHTML={{\n __html: `\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"shell\"]{opacity:.55}\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"enhanced\"]{opacity:1}\n[data-sk-part=\"form-mount\"] [data-sk-enter]{opacity:0;transform:translateY(var(--sk-form-enter-distance,6px))}\n[data-sk-part=\"form-mount\"] [data-sk-enter] *{transition:none!important}\n@media (prefers-reduced-motion: reduce){\n[data-sk-part=\"form-mount\"]{transition:none!important}\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"shell\"]{opacity:1}\n[data-sk-part=\"form-mount\"] [data-sk-enter]{opacity:1;transform:none}\n}`,\n }}\n />\n )\n}\n"]}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkZRGCKWIT_js = require('./chunk-ZRGCKWIT.js');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
function HoneypotField({ name, value, onChange }) {
|
|
7
|
+
const interactive = typeof onChange === "function";
|
|
8
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9
|
+
"input",
|
|
10
|
+
{
|
|
11
|
+
type: "text",
|
|
12
|
+
name,
|
|
13
|
+
tabIndex: -1,
|
|
14
|
+
autoComplete: "new-password",
|
|
15
|
+
"aria-hidden": "true",
|
|
16
|
+
inert: true,
|
|
17
|
+
"data-sk-honeypot": "",
|
|
18
|
+
"data-1p-ignore": "",
|
|
19
|
+
"data-lpignore": "true",
|
|
20
|
+
"data-form-type": "other",
|
|
21
|
+
"data-bwignore": "",
|
|
22
|
+
style: {
|
|
23
|
+
position: "absolute",
|
|
24
|
+
left: -9999,
|
|
25
|
+
width: 1,
|
|
26
|
+
height: 1,
|
|
27
|
+
overflow: "hidden",
|
|
28
|
+
opacity: 0,
|
|
29
|
+
visibility: "hidden",
|
|
30
|
+
pointerEvents: "none"
|
|
31
|
+
},
|
|
32
|
+
...interactive ? {
|
|
33
|
+
value: value ?? "",
|
|
34
|
+
onChange: (e) => {
|
|
35
|
+
onChange(e.target.value);
|
|
36
|
+
if (e.target.value) {
|
|
37
|
+
console.warn("[Forms] Honeypot triggered");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} : { defaultValue: "" }
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function nativeEligible(config) {
|
|
45
|
+
return !!config?.native_token && !config.is_multi_step;
|
|
46
|
+
}
|
|
47
|
+
function nativeFormProps(config) {
|
|
48
|
+
if (!nativeEligible(config)) return {};
|
|
49
|
+
const { apiUrl } = chunkZRGCKWIT_js.getApiConfig();
|
|
50
|
+
return { action: `${apiUrl}/api/public/forms/submit-native`, method: "post" };
|
|
51
|
+
}
|
|
52
|
+
function NativeFallbackFields({ config, returnTo }) {
|
|
53
|
+
if (!nativeEligible(config)) return null;
|
|
54
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
55
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name: "_sk_token", value: config.native_token, readOnly: true }),
|
|
56
|
+
returnTo ? /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name: "_sk_return", value: returnTo, readOnly: true }) : null
|
|
57
|
+
] });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
exports.HoneypotField = HoneypotField;
|
|
61
|
+
exports.NativeFallbackFields = NativeFallbackFields;
|
|
62
|
+
exports.nativeFormProps = nativeFormProps;
|
|
63
|
+
//# sourceMappingURL=chunk-VLY3SFNH.js.map
|
|
64
|
+
//# sourceMappingURL=chunk-VLY3SFNH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forms/HoneypotField.tsx","../src/forms/native-fallback.tsx"],"names":["jsx","getApiConfig","jsxs","Fragment"],"mappings":";;;;;AAqCO,SAAS,aAAA,CAAc,EAAE,IAAA,EAAM,KAAA,EAAO,UAAS,EAAuB;AAC3E,EAAA,MAAM,WAAA,GAAc,OAAO,QAAA,KAAa,UAAA;AACxC,EAAA,uBACEA,cAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,MAAA;AAAA,MACL,IAAA;AAAA,MACA,QAAA,EAAU,EAAA;AAAA,MACV,YAAA,EAAa,cAAA;AAAA,MACb,aAAA,EAAY,MAAA;AAAA,MACZ,KAAA,EAAK,IAAA;AAAA,MACL,kBAAA,EAAiB,EAAA;AAAA,MAGjB,gBAAA,EAAe,EAAA;AAAA,MACf,eAAA,EAAc,MAAA;AAAA,MACd,gBAAA,EAAe,OAAA;AAAA,MACf,eAAA,EAAc,EAAA;AAAA,MACd,KAAA,EAAO;AAAA,QACL,QAAA,EAAU,UAAA;AAAA,QACV,IAAA,EAAM,KAAA;AAAA,QACN,KAAA,EAAO,CAAA;AAAA,QACP,MAAA,EAAQ,CAAA;AAAA,QACR,QAAA,EAAU,QAAA;AAAA,QACV,OAAA,EAAS,CAAA;AAAA,QACT,UAAA,EAAY,QAAA;AAAA,QACZ,aAAA,EAAe;AAAA,OACjB;AAAA,MACC,GAAI,WAAA,GACD;AAAA,QACE,OAAO,KAAA,IAAS,EAAA;AAAA,QAChB,QAAA,EAAU,CAAC,CAAA,KAA2C;AACpD,UAAA,QAAA,CAAU,CAAA,CAAE,OAAO,KAAK,CAAA;AACxB,UAAA,IAAI,CAAA,CAAE,OAAO,KAAA,EAAO;AAElB,YAAA,OAAA,CAAQ,KAAK,4BAA4B,CAAA;AAAA,UAC3C;AAAA,QACF;AAAA,OACF,GACA,EAAE,YAAA,EAAc,EAAA;AAAG;AAAA,GACzB;AAEJ;ACjDA,SAAS,eAAe,MAAA,EAAuD;AAC7E,EAAA,OAAO,CAAC,CAAC,MAAA,EAAQ,YAAA,IAAgB,CAAC,MAAA,CAAO,aAAA;AAC3C;AAGO,SAAS,gBACd,MAAA,EACsC;AACtC,EAAA,IAAI,CAAC,cAAA,CAAe,MAAM,CAAA,SAAU,EAAC;AACrC,EAAA,MAAM,EAAE,MAAA,EAAO,GAAIC,6BAAA,EAAa;AAChC,EAAA,OAAO,EAAE,MAAA,EAAQ,CAAA,EAAG,MAAM,CAAA,+BAAA,CAAA,EAAmC,QAAQ,MAAA,EAAO;AAC9E;AAaO,SAAS,oBAAA,CAAqB,EAAE,MAAA,EAAQ,QAAA,EAAS,EAA8B;AACpF,EAAA,IAAI,CAAC,cAAA,CAAe,MAAM,CAAA,EAAG,OAAO,IAAA;AACpC,EAAA,uBACEC,eAAA,CAAAC,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAH,cAAAA,CAAC,OAAA,EAAA,EAAM,IAAA,EAAK,QAAA,EAAS,IAAA,EAAK,aAAY,KAAA,EAAO,MAAA,CAAQ,YAAA,EAAc,QAAA,EAAQ,IAAA,EAAC,CAAA;AAAA,IAC3E,QAAA,mBAAWA,cAAAA,CAAC,OAAA,EAAA,EAAM,IAAA,EAAK,QAAA,EAAS,IAAA,EAAK,YAAA,EAAa,KAAA,EAAO,QAAA,EAAU,QAAA,EAAQ,IAAA,EAAC,CAAA,GAAK;AAAA,GAAA,EACpF,CAAA;AAEJ","file":"chunk-VLY3SFNH.js","sourcesContent":["/**\n * Single source of truth for the honeypot input — rendered by BOTH form\n * experiences (classic and stage) inside their <form>. The customRender path\n * deliberately gets none (documented limitation: custom renders lose the\n * honeypot, which is why alternate experiences must be render branches).\n *\n * Invariants (do not weaken any of these):\n * - `inert` blocks focus/interaction at the browser level, surviving hostile\n * site CSS that could defeat the inline styles.\n * - data-sk-honeypot gives site CSS a stable opt-OUT hook.\n * - Controlled input: bots filling via JS still fire React onChange, so the\n * value reaches submitForm's data payload.\n * - Name comes from config (`honeypot_field || DEFAULT_HONEYPOT_FIELD` from\n * the shared contract) — resolved by the caller, never forked here.\n * - The trap must be invisible to AUTOFILL as well as to people. A browser or\n * password manager filling a hidden input flags a real visitor as a bot, and\n * because the value is stripped server-side the mistake is undiagnosable\n * after the fact. `autocomplete=\"off\"` does not achieve this — it is the one\n * value Chrome deliberately ignores for contact/address autofill — so the\n * trap declares `new-password` (never offered saved contact data) plus the\n * documented per-manager opt-outs.\n */\n\nimport React from 'react'\n\nexport interface HoneypotFieldProps {\n name: string\n value?: string\n /**\n * Omit for STATIC mode — an uncontrolled trap a Server Component can render.\n * The trap's whole job is server-side (the value is read off the submission\n * and stripped), so it needs no client state to work; the controlled form is\n * only so the hydrated JSON path can read it back out of React state.\n */\n onChange?: (value: string) => void\n}\n\nexport function HoneypotField({ name, value, onChange }: HoneypotFieldProps) {\n const interactive = typeof onChange === 'function'\n return (\n <input\n type=\"text\"\n name={name}\n tabIndex={-1}\n autoComplete=\"new-password\"\n aria-hidden=\"true\"\n inert\n data-sk-honeypot=\"\"\n // Password-manager opt-outs: 1Password, LastPass, Dashlane, Bitwarden.\n // Each ignores its own attribute; none respects autocomplete alone.\n data-1p-ignore=\"\"\n data-lpignore=\"true\"\n data-form-type=\"other\"\n data-bwignore=\"\"\n style={{\n position: 'absolute',\n left: -9999,\n width: 1,\n height: 1,\n overflow: 'hidden',\n opacity: 0,\n visibility: 'hidden',\n pointerEvents: 'none',\n }}\n {...(interactive\n ? {\n value: value ?? '',\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange!(e.target.value)\n if (e.target.value) {\n // Bot detected\n console.warn('[Forms] Honeypot triggered')\n }\n },\n }\n : { defaultValue: '' })}\n />\n )\n}\n","'use client'\n\n/**\n * No-JS native submission fallback — the floor under every managed form.\n *\n * The classic form is the SSR/no-JS surface (experiences are post-hydration\n * chunks), so it alone carries a real `action`/`method` pointing at\n * sonor-api's POST /api/public/forms/submit-native. With JS running, the\n * form's onSubmit preventDefault()s and the JSON path wins; without JS the\n * browser performs an ordinary form-encoded POST and the lead still lands.\n *\n * Auth rides in the hidden `_sk_token` field: a signed, single-purpose\n * credential minted by the api-key-authenticated forms/config endpoint\n * (`native_token` in the response). No token in the config (older API, or no\n * signing secret) means no fallback — the form keeps its historical behavior\n * rather than pointing at an endpoint that will reject it.\n *\n * Multi-step forms are excluded: step navigation is JS, and a native POST of\n * step-1 fields alone fails whole-form validation server-side. Single-step\n * forms are the overwhelming lead-capture case.\n *\n * Single source of truth for the gating — the form attrs and the hidden\n * fields must always agree, so both read the same predicate.\n */\n\nimport React from 'react'\nimport type { ManagedFormConfig } from './types'\nimport { getApiConfig } from './submitForm'\n\nfunction nativeEligible(config: ManagedFormConfig | null | undefined): boolean {\n return !!config?.native_token && !config.is_multi_step\n}\n\n/** `action`/`method` for the classic <form> — empty when ineligible. */\nexport function nativeFormProps(\n config: ManagedFormConfig | null | undefined,\n): { action?: string; method?: 'post' } {\n if (!nativeEligible(config)) return {}\n const { apiUrl } = getApiConfig()\n return { action: `${apiUrl}/api/public/forms/submit-native`, method: 'post' }\n}\n\nexport interface NativeFallbackFieldsProps {\n config: ManagedFormConfig | null | undefined\n /**\n * Absolute URL the native 303 should land on (usually the page hosting the\n * form). Optional — without it the server falls back to the Referer origin,\n * which loses the path but still returns the visitor to the right site.\n */\n returnTo?: string\n}\n\n/** Hidden control fields the native endpoint reads (`_sk_*` namespace). */\nexport function NativeFallbackFields({ config, returnTo }: NativeFallbackFieldsProps) {\n if (!nativeEligible(config)) return null\n return (\n <>\n <input type=\"hidden\" name=\"_sk_token\" value={config!.native_token} readOnly />\n {returnTo ? <input type=\"hidden\" name=\"_sk_return\" value={returnTo} readOnly /> : null}\n </>\n )\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalizeSiteHost } from './chunk-NI7OY4FW.mjs';
|
|
2
|
-
import { configureSiteCredential, currentCredential } from './chunk-
|
|
2
|
+
import { configureSiteCredential, currentCredential } from './chunk-KNYK2VLX.mjs';
|
|
3
3
|
|
|
4
4
|
// src/shared/publishCredential.ts
|
|
5
5
|
function resolveSiteHost(explicitSite) {
|
|
@@ -33,5 +33,5 @@ function publishSiteCredential({
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export { publishSiteCredential, resolveSiteHost };
|
|
36
|
-
//# sourceMappingURL=chunk-
|
|
37
|
-
//# sourceMappingURL=chunk-
|
|
36
|
+
//# sourceMappingURL=chunk-VUIQLKJB.mjs.map
|
|
37
|
+
//# sourceMappingURL=chunk-VUIQLKJB.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/publishCredential.ts"],"names":[],"mappings":";;;;AAqCO,SAAS,gBAAgB,YAAA,EAA+B;AAC7D,EAAA,MAAM,aACJ,OAAO,OAAA,KAAY,WAAA,GAAc,OAAA,CAAQ,IAAI,oBAAA,GAAuB,MAAA;AAEtE,EAAA,IAAI,WAAW,YAAA,IAAgB,EAAA;AAC/B,EAAA,IAAI,CAAC,YAAY,UAAA,EAAY;AAC3B,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,IAAI,GAAA,CAAI,UAAU,CAAA,CAAE,IAAA;AAAA,IACjC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACA,EAAA,IAAI,CAAC,QAAA,IAAY,OAAO,MAAA,KAAW,WAAA,EAAa;AAC9C,IAAA,QAAA,GAAW,OAAO,QAAA,CAAS,IAAA;AAAA,EAC7B;AACA,EAAA,OAAO,iBAAA,CAAkB,QAAQ,CAAA,IAAK,EAAA;AACxC;AAkCO,SAAS,qBAAA,CAAsB;AAAA,EACpC,MAAA;AAAA,EACA,MAAA,GAAS,sBAAA;AAAA,EACT,IAAA;AAAA,EACA,KAAA,GAAQ,KAAA;AAAA,EACR;AACF,CAAA,EAAuC;AACrC,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAKnC,EAAA,uBAAA,CAAwB,EAAE,UAAA,EAAY,MAAA,EAAQ,MAAA,EAAQ,CAAA;AACrD,EAAC,OAAe,oBAAA,GAAuB,MAAA;AACvC,EAAC,MAAA,CAAe,oBAAA,GAAuB,iBAAA,CAAkB,MAAM,CAAA;AAC/D,EAAC,OAAe,kBAAA,GAAqB,KAAA;AACrC,EAAC,MAAA,CAAe,iBAAA,GAAoB,IAAA,IAAQ,eAAA,EAAgB;AAG7D,EAAA,IAAI,cAAA,EAAiB,MAAA,CAAe,uBAAA,GAA0B,cAAA;AAChE","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/shared/publishCredential.ts"],"names":[],"mappings":";;;;AAqCO,SAAS,gBAAgB,YAAA,EAA+B;AAC7D,EAAA,MAAM,aACJ,OAAO,OAAA,KAAY,WAAA,GAAc,OAAA,CAAQ,IAAI,oBAAA,GAAuB,MAAA;AAEtE,EAAA,IAAI,WAAW,YAAA,IAAgB,EAAA;AAC/B,EAAA,IAAI,CAAC,YAAY,UAAA,EAAY;AAC3B,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,IAAI,GAAA,CAAI,UAAU,CAAA,CAAE,IAAA;AAAA,IACjC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACA,EAAA,IAAI,CAAC,QAAA,IAAY,OAAO,MAAA,KAAW,WAAA,EAAa;AAC9C,IAAA,QAAA,GAAW,OAAO,QAAA,CAAS,IAAA;AAAA,EAC7B;AACA,EAAA,OAAO,iBAAA,CAAkB,QAAQ,CAAA,IAAK,EAAA;AACxC;AAkCO,SAAS,qBAAA,CAAsB;AAAA,EACpC,MAAA;AAAA,EACA,MAAA,GAAS,sBAAA;AAAA,EACT,IAAA;AAAA,EACA,KAAA,GAAQ,KAAA;AAAA,EACR;AACF,CAAA,EAAuC;AACrC,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAKnC,EAAA,uBAAA,CAAwB,EAAE,UAAA,EAAY,MAAA,EAAQ,MAAA,EAAQ,CAAA;AACrD,EAAC,OAAe,oBAAA,GAAuB,MAAA;AACvC,EAAC,MAAA,CAAe,oBAAA,GAAuB,iBAAA,CAAkB,MAAM,CAAA;AAC/D,EAAC,OAAe,kBAAA,GAAqB,KAAA;AACrC,EAAC,MAAA,CAAe,iBAAA,GAAoB,IAAA,IAAQ,eAAA,EAAgB;AAG7D,EAAA,IAAI,cAAA,EAAiB,MAAA,CAAe,uBAAA,GAA0B,cAAA;AAChE","file":"chunk-VUIQLKJB.mjs","sourcesContent":["/**\n * @sonordev/site-kit shared — Client credential + window-global publishing\n *\n * SINGLE SOURCE OF TRUTH for seeding the browser-side token manager and the\n * `window.__SITE_KIT_*` globals that every client module reads. Used by:\n *\n * - `SiteKitClientProviders` (core `SiteKitLayout`)\n * - `SiteKitCredential` (`@sonordev/site-kit/client`) — the public component\n * for layouts that are NOT core `SiteKitLayout`, e.g.\n * `@sonordev/agency-site-kit`'s `AgencySiteKitLayout`.\n *\n * Do not re-fork this. Before it existed, agency sites hand-rolled their own\n * \"set the globals on mount\" component (upforge's `UptradeSiteKitInit`), and\n * because those copies had no access to the token manager they published the\n * RAW `sonor_` key into the client bundle — the exact exposure the mint exists\n * to prevent. Any layout that puts a credential on `window` goes through here.\n *\n * Client-safe: no `server-only` guard, SSR-safe (every write is window-gated).\n * The minting half is server-only and lives in `../server/mint-site-token`.\n */\n// Leaf module, NOT '../sites/contract' — see sites/normalize.ts. Importing the\n// full contract here shipped its JSON schema to every browser that loads a\n// credential-publishing entry.\nimport { normalizeSiteHost } from '../sites/normalize'\nimport { configureSiteCredential, currentCredential } from './siteToken'\n\n/**\n * Resolve the sub-site identifier — the dimension that lets one Sonor project\n * host many sites (e.g. truepowersystems.com + ohiopowerstudies.com under one\n * TPS project). Precedence, per the platform site contract:\n * explicit `site` > NEXT_PUBLIC_SITE_URL host > window.location.host\n *\n * Normalized with the shared contract (lowercase host, no protocol/path/port)\n * so `__SITE_KIT_SITE__` matches exactly what the Sonor API stores — servers\n * re-normalize with the same rule, so this only makes the client emit the\n * canonical value. Always returns a string (possibly empty).\n */\nexport function resolveSiteHost(explicitSite?: string): string {\n const envSiteUrl =\n typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_SITE_URL : undefined\n\n let resolved = explicitSite ?? ''\n if (!resolved && envSiteUrl) {\n try {\n resolved = new URL(envSiteUrl).host\n } catch {\n /* malformed URL — fall through to client-side host */\n }\n }\n if (!resolved && typeof window !== 'undefined') {\n resolved = window.location.host\n }\n return normalizeSiteHost(resolved) ?? ''\n}\n\nexport interface PublishSiteCredentialOptions {\n /**\n * The credential the layout minted server-side. In 3.2+ this is a short-lived\n * `st1.` token that `sonorFetch` refreshes transparently. A raw `sonor_` key\n * still works (2.x kit, or the mint-failed fallback) but should never be\n * routed here from a client component — it would ship the secret to the\n * browser.\n */\n apiKey?: string\n apiUrl?: string\n /** Pre-resolved sub-site host. Omit to resolve via `resolveSiteHost`. */\n site?: string\n debug?: boolean\n /**\n * Referrer-restricted Google Maps BROWSER key for client map components.\n * Resolved server-side by SiteKitLayout (NEXT_PUBLIC_GOOGLE_MAPS_API_KEY /\n * GOOGLE_MAPS_BROWSER_KEY) because maps/api.ts runs client-side, where a bare\n * process.env read is dead code unless the app's bundler happens to inline it.\n * Never route a server secret here.\n */\n mapsBrowserKey?: string\n}\n\n/**\n * Seed the token manager and publish the `window.__SITE_KIT_*` globals.\n *\n * Called during RENDER, not in an effect: client modules read these globals in\n * their own mount effects, and effects run child-first, so an effect-based\n * publish would land after the modules that need it.\n *\n * No-op on the server.\n */\nexport function publishSiteCredential({\n apiKey,\n apiUrl = 'https://api.sonor.io',\n site,\n debug = false,\n mapsBrowserKey,\n}: PublishSiteCredentialOptions): void {\n if (typeof window === 'undefined') return\n\n // Seed the client token manager. The window global is set to the freshest\n // token held — a prior page this session may already have refreshed past the\n // seed the layout injected. In raw-key mode this is a passthrough.\n configureSiteCredential({ credential: apiKey, apiUrl })\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = currentCredential(apiKey)\n ;(window as any).__SITE_KIT_DEBUG__ = debug\n ;(window as any).__SITE_KIT_SITE__ = site ?? resolveSiteHost()\n // maps/api.ts falls back to this global when the Sonor platform hasn't\n // provisioned a browser key. Don't clobber a value another layout already set.\n if (mapsBrowserKey) (window as any).__GOOGLE_MAPS_API_KEY__ = mapsBrowserKey\n}\n"]}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var chunkHGNSJXWT_js = require('./chunk-HGNSJXWT.js');
|
|
5
|
+
var React = require('react');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
11
|
+
|
|
12
|
+
var InteractiveForm = React.lazy(
|
|
13
|
+
() => import('./ManagedForm-XWN3TVQQ.js').then((m) => ({ default: m.ManagedForm }))
|
|
14
|
+
);
|
|
15
|
+
function FormEnhancer({
|
|
16
|
+
formId,
|
|
17
|
+
initialConfig,
|
|
18
|
+
className,
|
|
19
|
+
nativeReturnTo,
|
|
20
|
+
experience,
|
|
21
|
+
defaultValues,
|
|
22
|
+
onSuccess,
|
|
23
|
+
onError,
|
|
24
|
+
enter = "fade",
|
|
25
|
+
defer = true,
|
|
26
|
+
children
|
|
27
|
+
}) {
|
|
28
|
+
const ready = chunkHGNSJXWT_js.useDeferredActivation(defer);
|
|
29
|
+
const [enhanced, setEnhanced] = React.useState(false);
|
|
30
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
31
|
+
"div",
|
|
32
|
+
{
|
|
33
|
+
"data-sk-form-mount": enhanced ? "enhanced" : "shell",
|
|
34
|
+
"data-sk-part": "form-mount",
|
|
35
|
+
style: enter === "fade" ? FADE_HOST : void 0,
|
|
36
|
+
children: [
|
|
37
|
+
enter === "fade" && /* @__PURE__ */ jsxRuntime.jsx(EnterStyles, {}),
|
|
38
|
+
ready ? /* @__PURE__ */ jsxRuntime.jsx(React.Suspense, { fallback: children, children: /* @__PURE__ */ jsxRuntime.jsx(Enhanced, { onMount: () => setEnhanced(true), fallback: children, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
39
|
+
InteractiveForm,
|
|
40
|
+
{
|
|
41
|
+
formId,
|
|
42
|
+
initialConfig,
|
|
43
|
+
className,
|
|
44
|
+
nativeReturnTo,
|
|
45
|
+
experience,
|
|
46
|
+
defaultValues,
|
|
47
|
+
onSuccess,
|
|
48
|
+
onError
|
|
49
|
+
}
|
|
50
|
+
) }) }) : children
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
var Enhanced = class extends React__default.default.Component {
|
|
56
|
+
constructor() {
|
|
57
|
+
super(...arguments);
|
|
58
|
+
this.state = { failed: false };
|
|
59
|
+
}
|
|
60
|
+
static getDerivedStateFromError() {
|
|
61
|
+
return { failed: true };
|
|
62
|
+
}
|
|
63
|
+
componentDidCatch(err) {
|
|
64
|
+
console.error("[Forms] Enhancement failed; keeping the native form:", err);
|
|
65
|
+
}
|
|
66
|
+
componentDidMount() {
|
|
67
|
+
if (!this.state.failed) this.props.onMount();
|
|
68
|
+
}
|
|
69
|
+
render() {
|
|
70
|
+
if (this.state.failed) return this.props.fallback;
|
|
71
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FrameTag, { children: this.props.children });
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
function FrameTag({ children }) {
|
|
75
|
+
const ref = React.useRef(null);
|
|
76
|
+
React.useEffect(() => {
|
|
77
|
+
const el = ref.current;
|
|
78
|
+
if (!el) return;
|
|
79
|
+
el.setAttribute("data-sk-enter", "");
|
|
80
|
+
const id = requestAnimationFrame(() => el.removeAttribute("data-sk-enter"));
|
|
81
|
+
return () => cancelAnimationFrame(id);
|
|
82
|
+
}, []);
|
|
83
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, style: { display: "contents" }, children });
|
|
84
|
+
}
|
|
85
|
+
var FADE_HOST = {
|
|
86
|
+
transition: "opacity var(--sk-form-enter-duration, 320ms) var(--sk-form-enter-easing, cubic-bezier(.22,1,.36,1))"
|
|
87
|
+
};
|
|
88
|
+
function EnterStyles() {
|
|
89
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
90
|
+
"style",
|
|
91
|
+
{
|
|
92
|
+
dangerouslySetInnerHTML: {
|
|
93
|
+
__html: `
|
|
94
|
+
[data-sk-part="form-mount"][data-sk-form-mount="shell"]{opacity:.55}
|
|
95
|
+
[data-sk-part="form-mount"][data-sk-form-mount="enhanced"]{opacity:1}
|
|
96
|
+
[data-sk-part="form-mount"] [data-sk-enter]{opacity:0;transform:translateY(var(--sk-form-enter-distance,6px))}
|
|
97
|
+
[data-sk-part="form-mount"] [data-sk-enter] *{transition:none!important}
|
|
98
|
+
@media (prefers-reduced-motion: reduce){
|
|
99
|
+
[data-sk-part="form-mount"]{transition:none!important}
|
|
100
|
+
[data-sk-part="form-mount"][data-sk-form-mount="shell"]{opacity:1}
|
|
101
|
+
[data-sk-part="form-mount"] [data-sk-enter]{opacity:1;transform:none}
|
|
102
|
+
}`
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
exports.FormEnhancer = FormEnhancer;
|
|
109
|
+
//# sourceMappingURL=chunk-WHVUSVHA.js.map
|
|
110
|
+
//# sourceMappingURL=chunk-WHVUSVHA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forms/FormEnhancer.tsx"],"names":["lazy","useDeferredActivation","useState","jsxs","jsx","Suspense","React","useRef","useEffect"],"mappings":"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","file":"chunk-WHVUSVHA.js","sourcesContent":["'use client'\n\n/**\n * FormEnhancer — the only client code a managed form needs up front.\n *\n * Renders the server-rendered shell (<StaticForm>, passed as `children`) until\n * an idle/first-interaction gate fires, then lazy-imports the interactive form\n * and swaps it in. Everything expensive — validation, conditional logic,\n * spotlight/stage, celebration, momentum — lives behind that dynamic import,\n * so a page ships this boundary and nothing else in its initial chunk set.\n *\n * The shell is a REAL form the whole time (native action + signed token), so\n * the progression is:\n *\n * no JS at all -> shell, submits natively. Works.\n * JS, pre-idle -> shell, submits natively. Works.\n * JS, post-idle -> enhanced form, submits over JSON. Works, with delight.\n * chunk 404s -> shell stays. Works. (Never left blank.)\n *\n * That last line is the invariant to protect: the shell is only removed once\n * the enhancement has actually rendered. Do not \"hide the shell then load\" —\n * a CDN hiccup would leave a visitor staring at an empty box where the form\n * used to be.\n *\n * ── Entrance animation ──────────────────────────────────────────────────\n *\n * Above-the-fold forms upgrade while the visitor is looking at them, so the\n * swap must not pop. The wrapper carries `data-sk-form-mount=\"shell\"` and\n * flips to `\"enhanced\"`, and the enhanced form gets `data-sk-enter` for one\n * frame, so a site can style the transition entirely in CSS:\n *\n * [data-sk-form-mount] { transition: opacity .35s ease }\n * [data-sk-form-mount=\"shell\"] { opacity: .6 }\n *\n * Defaults ship as CSS variables rather than hard-coded values:\n *\n * --sk-form-enter-duration (default 320ms)\n * --sk-form-enter-easing (default cubic-bezier(.22,1,.36,1))\n * --sk-form-enter-distance (default 6px)\n *\n * `enter=\"none\"` opts out entirely; `enter=\"custom\"` emits the data\n * attributes but no site-kit styles, leaving the animation to the site.\n * Every default is collapsed by prefers-reduced-motion.\n */\n\nimport React, { lazy, Suspense, useEffect, useRef, useState } from 'react'\nimport { useDeferredActivation } from '../shared/defer'\nimport type { FormExperience, FormSubmission } from './types'\n\n/** The heavy half. Nothing else in this module may import it statically. */\nconst InteractiveForm = lazy(() =>\n import('./ManagedForm').then((m) => ({ default: m.ManagedForm })),\n)\n\nexport type FormEnterAnimation = 'fade' | 'none' | 'custom'\n\nexport interface FormEnhancerProps {\n formId: string\n /** Server-fetched raw config — hands the enhancement its fields instantly. */\n initialConfig?: Record<string, unknown> | null\n className?: string\n nativeReturnTo?: string\n experience?: FormExperience\n /** Pre-fill field values by slug. See ManagedForm.defaultValues. */\n defaultValues?: Record<string, unknown>\n onSuccess?: (submission: FormSubmission) => void\n onError?: (error: Error) => void\n /**\n * How the enhanced form arrives. 'fade' (default) crossfades and lifts it\n * into place; 'none' swaps instantly; 'custom' emits the data attributes\n * and no styles so the site owns the animation.\n */\n enter?: FormEnterAnimation\n /**\n * Set false to enhance immediately instead of waiting for idle. Only worth\n * it for a form that is the entire point of the page AND above the fold.\n */\n defer?: boolean\n /** The server-rendered <StaticForm>. Shown until the enhancement mounts. */\n children: React.ReactNode\n}\n\nexport function FormEnhancer({\n formId,\n initialConfig,\n className,\n nativeReturnTo,\n experience,\n defaultValues,\n onSuccess,\n onError,\n enter = 'fade',\n defer = true,\n children,\n}: FormEnhancerProps) {\n const ready = useDeferredActivation(defer)\n // Flipped only after the enhancement has actually committed to the DOM, so\n // the shell never disappears ahead of its replacement.\n const [enhanced, setEnhanced] = useState(false)\n\n return (\n <div\n data-sk-form-mount={enhanced ? 'enhanced' : 'shell'}\n data-sk-part=\"form-mount\"\n style={enter === 'fade' ? FADE_HOST : undefined}\n >\n {enter === 'fade' && <EnterStyles />}\n {ready ? (\n <Suspense fallback={children}>\n <Enhanced onMount={() => setEnhanced(true)} fallback={children}>\n <InteractiveForm\n formId={formId}\n initialConfig={initialConfig}\n className={className}\n nativeReturnTo={nativeReturnTo}\n experience={experience}\n defaultValues={defaultValues}\n onSuccess={onSuccess}\n onError={onError}\n />\n </Enhanced>\n </Suspense>\n ) : (\n children\n )}\n </div>\n )\n}\n\n/**\n * Reports the moment the enhancement is on screen, and keeps the shell\n * rendered if it throws. An error boundary is the difference between \"the\n * fancy version failed\" and \"there is no form on this page\".\n */\nclass Enhanced extends React.Component<\n { onMount: () => void; fallback: React.ReactNode; children: React.ReactNode },\n { failed: boolean }\n> {\n state = { failed: false }\n\n static getDerivedStateFromError() {\n return { failed: true }\n }\n\n componentDidCatch(err: unknown) {\n console.error('[Forms] Enhancement failed; keeping the native form:', err)\n }\n\n componentDidMount() {\n if (!this.state.failed) this.props.onMount()\n }\n\n render() {\n if (this.state.failed) return this.props.fallback\n return <FrameTag>{this.props.children}</FrameTag>\n }\n}\n\n/** Adds data-sk-enter for one frame so a CSS transition has something to run. */\nfunction FrameTag({ children }: { children: React.ReactNode }) {\n const ref = useRef<HTMLDivElement>(null)\n useEffect(() => {\n const el = ref.current\n if (!el) return\n el.setAttribute('data-sk-enter', '')\n const id = requestAnimationFrame(() => el.removeAttribute('data-sk-enter'))\n return () => cancelAnimationFrame(id)\n }, [])\n return (\n <div ref={ref} style={{ display: 'contents' }}>\n {children}\n </div>\n )\n}\n\nconst FADE_HOST: React.CSSProperties = {\n transition:\n 'opacity var(--sk-form-enter-duration, 320ms) var(--sk-form-enter-easing, cubic-bezier(.22,1,.36,1))',\n}\n\n/**\n * Scoped to [data-sk-part=\"form-mount\"] so it can never touch a site's own\n * markup. Emitted once per form; identical text dedupes in every browser's\n * style cache and gzips to nothing.\n */\nfunction EnterStyles() {\n return (\n <style\n // biome-ignore lint/security/noDangerouslySetInnerHtml: static string, no interpolation\n dangerouslySetInnerHTML={{\n __html: `\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"shell\"]{opacity:.55}\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"enhanced\"]{opacity:1}\n[data-sk-part=\"form-mount\"] [data-sk-enter]{opacity:0;transform:translateY(var(--sk-form-enter-distance,6px))}\n[data-sk-part=\"form-mount\"] [data-sk-enter] *{transition:none!important}\n@media (prefers-reduced-motion: reduce){\n[data-sk-part=\"form-mount\"]{transition:none!important}\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"shell\"]{opacity:1}\n[data-sk-part=\"form-mount\"] [data-sk-enter]{opacity:1;transform:none}\n}`,\n }}\n />\n )\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkMRRTAJWQ_js = require('./chunk-MRRTAJWQ.js');
|
|
5
5
|
var React = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
|
|
@@ -16,8 +16,8 @@ function SignalExperiment({
|
|
|
16
16
|
trackImpression = true,
|
|
17
17
|
children
|
|
18
18
|
}) {
|
|
19
|
-
const { assignment, variant, isControl } =
|
|
20
|
-
const trackEvent =
|
|
19
|
+
const { assignment, variant, isControl } = chunkMRRTAJWQ_js.useSignalExperiment(experimentId);
|
|
20
|
+
const trackEvent = chunkMRRTAJWQ_js.useSignalEvent();
|
|
21
21
|
React.useEffect(() => {
|
|
22
22
|
if (trackImpression && variant) {
|
|
23
23
|
trackEvent({
|
|
@@ -44,7 +44,7 @@ function SignalExperiment({
|
|
|
44
44
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: variants.control || null });
|
|
45
45
|
}
|
|
46
46
|
function useExperimentVariant(experimentId) {
|
|
47
|
-
return
|
|
47
|
+
return chunkMRRTAJWQ_js.useSignalExperiment(experimentId);
|
|
48
48
|
}
|
|
49
49
|
function ExperimentConversion({
|
|
50
50
|
experimentId,
|
|
@@ -52,8 +52,8 @@ function ExperimentConversion({
|
|
|
52
52
|
value,
|
|
53
53
|
children
|
|
54
54
|
}) {
|
|
55
|
-
const trackEvent =
|
|
56
|
-
const { variant } =
|
|
55
|
+
const trackEvent = chunkMRRTAJWQ_js.useSignalEvent();
|
|
56
|
+
const { variant } = chunkMRRTAJWQ_js.useSignalExperiment(experimentId);
|
|
57
57
|
const handleInteraction = () => {
|
|
58
58
|
trackEvent({
|
|
59
59
|
event_type: "experiment",
|
|
@@ -79,5 +79,5 @@ function ExperimentConversion({
|
|
|
79
79
|
exports.ExperimentConversion = ExperimentConversion;
|
|
80
80
|
exports.SignalExperiment = SignalExperiment;
|
|
81
81
|
exports.useExperimentVariant = useExperimentVariant;
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
83
|
-
//# sourceMappingURL=chunk-
|
|
82
|
+
//# sourceMappingURL=chunk-WNNY2BCV.js.map
|
|
83
|
+
//# sourceMappingURL=chunk-WNNY2BCV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/signal/SignalExperiment.tsx"],"names":["useSignalExperiment","useSignalEvent","useEffect","jsx","Fragment","React"],"mappings":";;;;;;;;;;AAgDO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,YAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA,GAAkB,IAAA;AAAA,EAClB;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,SAAA,EAAU,GAAIA,qCAAoB,YAAY,CAAA;AAC3E,EAAA,MAAM,aAAaC,+BAAA,EAAe;AAGlC,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,mBAAmB,OAAA,EAAS;AAC9B,MAAA,UAAA,CAAW;AAAA,QACT,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY;AAAA,UACV,aAAA,EAAe,YAAA;AAAA,UACf,WAAA,EAAa;AAAA;AACf,OACD,CAAA;AAAA,IACH;AAAA,EACF,GAAG,CAAC,YAAA,EAAc,OAAA,EAAS,eAAA,EAAiB,UAAU,CAAC,CAAA;AAGvD,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBAAOC,cAAA,CAAAC,mBAAA,EAAA,EAAG,mBAAS,EAAE,OAAA,EAAS,WAAW,SAAA,EAAW,SAAA,EAAW,CAAA,EAAE,CAAA;AAAA,EACnE;AAGA,EAAA,MAAM,kBAAkB,OAAA,IAAW,SAAA;AACnC,EAAA,MAAM,OAAA,GAAU,SAAS,eAAe,CAAA;AAExC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,6DAAU,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,EACpB;AAGA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,6DAAU,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,uBAAOD,cAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,QAAA,CAAS,OAAA,IAAW,IAAA,EAAK,CAAA;AACrC;AAYO,SAAS,qBAAqB,YAAA,EAAsB;AACzD,EAAA,OAAOJ,qCAAoB,YAAY,CAAA;AACzC;AAoBO,SAAS,oBAAA,CAAqB;AAAA,EACnC,YAAA;AAAA,EACA,WAAA,GAAc,OAAA;AAAA,EACd,KAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,MAAM,aAAaC,+BAAA,EAAe;AAClC,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAID,oCAAA,CAAoB,YAAY,CAAA;AAEpD,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,UAAA,CAAW;AAAA,MACT,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY;AAAA,QACV,aAAA,EAAe,YAAA;AAAA,QACf,WAAA,EAAa,OAAA;AAAA,QACb,YAAA,EAAc,WAAA;AAAA,QACd;AAAA;AACF,KACD,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,OAAOK,sBAAA,CAAM,aAAa,QAAA,EAAU;AAAA,IAClC,OAAA,EAAS,CAAC,CAAA,KAAwB;AAChC,MAAA,iBAAA,EAAkB;AAElB,MAAA,IAAK,QAAA,CAAS,MAAsD,OAAA,EAAS;AAC3E,QAAC,QAAA,CAAS,KAAA,CAAsD,OAAA,CAAS,CAAC,CAAA;AAAA,MAC5E;AAAA,IACF;AAAA,GACD,CAAA;AACH","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/signal/SignalExperiment.tsx"],"names":["useSignalExperiment","useSignalEvent","useEffect","jsx","Fragment","React"],"mappings":";;;;;;;;;;AAgDO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,YAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA,GAAkB,IAAA;AAAA,EAClB;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,SAAA,EAAU,GAAIA,qCAAoB,YAAY,CAAA;AAC3E,EAAA,MAAM,aAAaC,+BAAA,EAAe;AAGlC,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,mBAAmB,OAAA,EAAS;AAC9B,MAAA,UAAA,CAAW;AAAA,QACT,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY;AAAA,UACV,aAAA,EAAe,YAAA;AAAA,UACf,WAAA,EAAa;AAAA;AACf,OACD,CAAA;AAAA,IACH;AAAA,EACF,GAAG,CAAC,YAAA,EAAc,OAAA,EAAS,eAAA,EAAiB,UAAU,CAAC,CAAA;AAGvD,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBAAOC,cAAA,CAAAC,mBAAA,EAAA,EAAG,mBAAS,EAAE,OAAA,EAAS,WAAW,SAAA,EAAW,SAAA,EAAW,CAAA,EAAE,CAAA;AAAA,EACnE;AAGA,EAAA,MAAM,kBAAkB,OAAA,IAAW,SAAA;AACnC,EAAA,MAAM,OAAA,GAAU,SAAS,eAAe,CAAA;AAExC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,6DAAU,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,EACpB;AAGA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,6DAAU,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,uBAAOD,cAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,QAAA,CAAS,OAAA,IAAW,IAAA,EAAK,CAAA;AACrC;AAYO,SAAS,qBAAqB,YAAA,EAAsB;AACzD,EAAA,OAAOJ,qCAAoB,YAAY,CAAA;AACzC;AAoBO,SAAS,oBAAA,CAAqB;AAAA,EACnC,YAAA;AAAA,EACA,WAAA,GAAc,OAAA;AAAA,EACd,KAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,MAAM,aAAaC,+BAAA,EAAe;AAClC,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAID,oCAAA,CAAoB,YAAY,CAAA;AAEpD,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,UAAA,CAAW;AAAA,MACT,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY;AAAA,QACV,aAAA,EAAe,YAAA;AAAA,QACf,WAAA,EAAa,OAAA;AAAA,QACb,YAAA,EAAc,WAAA;AAAA,QACd;AAAA;AACF,KACD,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,OAAOK,sBAAA,CAAM,aAAa,QAAA,EAAU;AAAA,IAClC,OAAA,EAAS,CAAC,CAAA,KAAwB;AAChC,MAAA,iBAAA,EAAkB;AAElB,MAAA,IAAK,QAAA,CAAS,MAAsD,OAAA,EAAS;AAC3E,QAAC,QAAA,CAAS,KAAA,CAAsD,OAAA,CAAS,CAAC,CAAA;AAAA,MAC5E;AAAA,IACF;AAAA,GACD,CAAA;AACH","file":"chunk-WNNY2BCV.js","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalExperiment\n * \n * A/B test component that renders different variants based on Signal assignment.\n * Uses Thompson Sampling (Bayesian bandit) for optimization.\n */\n\n'use client'\n\nimport React, { useMemo, useEffect } from 'react'\nimport { useSignalExperiment, useSignalEvent } from './SignalBridge'\n\ninterface SignalExperimentProps {\n /** Unique experiment ID */\n experimentId: string\n \n /** Variants to test - keys are variant names, values are React nodes */\n variants: Record<string, React.ReactNode>\n \n /** Fallback content if no assignment (defaults to 'control' variant) */\n fallback?: React.ReactNode\n \n /** Track impression automatically */\n trackImpression?: boolean\n \n /** Children function for more control */\n children?: (props: { variant: string; isControl: boolean }) => React.ReactNode\n}\n\n/**\n * Renders different content variants based on Signal's A/B assignment.\n * \n * @example\n * // Simple variant switching\n * <SignalExperiment experimentId=\"hero-cta\" variants={{\n * control: <Button>Get Started</Button>,\n * variant_a: <Button variant=\"primary\">Start Free Trial</Button>,\n * variant_b: <Button variant=\"secondary\">Book a Demo</Button>,\n * }} />\n * \n * @example\n * // With render prop for more control\n * <SignalExperiment experimentId=\"pricing-layout\">\n * {({ variant, isControl }) => (\n * <PricingSection layout={isControl ? 'cards' : 'table'} />\n * )}\n * </SignalExperiment>\n */\nexport function SignalExperiment({\n experimentId,\n variants,\n fallback,\n trackImpression = true,\n children,\n}: SignalExperimentProps) {\n const { assignment, variant, isControl } = useSignalExperiment(experimentId)\n const trackEvent = useSignalEvent()\n \n // Track impression when variant is rendered\n useEffect(() => {\n if (trackImpression && variant) {\n trackEvent({\n event_type: 'experiment',\n event_name: 'impression',\n event_data: {\n experiment_id: experimentId,\n variant_key: variant,\n },\n })\n }\n }, [experimentId, variant, trackImpression, trackEvent])\n \n // If using render prop\n if (children) {\n return <>{children({ variant: variant || 'control', isControl })}</>\n }\n \n // Determine what to render\n const selectedVariant = variant || 'control'\n const content = variants[selectedVariant]\n \n if (content !== undefined) {\n return <>{content}</>\n }\n \n // Fallback to provided fallback or control\n if (fallback) {\n return <>{fallback}</>\n }\n \n return <>{variants.control || null}</>\n}\n\n/**\n * Hook for conditional experiment logic\n * \n * @example\n * const { variant, isControl } = useExperimentVariant('pricing-test')\n * \n * return isControl \n * ? <OldPricing />\n * : <NewPricing showAnnual={variant === 'annual_first'} />\n */\nexport function useExperimentVariant(experimentId: string) {\n return useSignalExperiment(experimentId)\n}\n\n/**\n * Component for tracking experiment conversions\n * Wraps interactive elements to track when they convert\n * \n * @example\n * <SignalExperiment experimentId=\"signup-button\" variants={{\n * control: (\n * <ExperimentConversion experimentId=\"signup-button\" outcomeType=\"click\">\n * <Button>Sign Up</Button>\n * </ExperimentConversion>\n * ),\n * variant_a: (\n * <ExperimentConversion experimentId=\"signup-button\" outcomeType=\"click\">\n * <Button variant=\"large\">Join Now - It's Free!</Button>\n * </ExperimentConversion>\n * ),\n * }} />\n */\nexport function ExperimentConversion({\n experimentId,\n outcomeType = 'click',\n value,\n children,\n}: {\n experimentId: string\n outcomeType?: string\n value?: number\n children: React.ReactElement<{ onClick?: (e: React.MouseEvent) => void }>\n}) {\n const trackEvent = useSignalEvent()\n const { variant } = useSignalExperiment(experimentId)\n\n const handleInteraction = () => {\n trackEvent({\n event_type: 'experiment',\n event_name: 'conversion',\n event_data: {\n experiment_id: experimentId,\n variant_key: variant,\n outcome_type: outcomeType,\n value,\n },\n })\n }\n\n return React.cloneElement(children, {\n onClick: (e: React.MouseEvent) => {\n handleInteraction()\n // Call original onClick if exists\n if ((children.props as { onClick?: (e: React.MouseEvent) => void }).onClick) {\n (children.props as { onClick?: (e: React.MouseEvent) => void }).onClick!(e)\n }\n },\n })\n}\n"]}
|
|
@@ -60,6 +60,15 @@ var CSS = `
|
|
|
60
60
|
transition: grid-template-rows .42s cubic-bezier(.22,1,.36,1);
|
|
61
61
|
}
|
|
62
62
|
.sk-stage__collapse > div { overflow: hidden; min-height: 0; }
|
|
63
|
+
/* The clip only needs to work VERTICALLY (that's the collapse axis). Full
|
|
64
|
+
overflow:hidden also chops the focus aura / lock-in glow on the field
|
|
65
|
+
inside \u2014 a hard vertical edge on both sides of the input. overflow:clip
|
|
66
|
+
allows per-axis mixing without creating a scroll container, so modern
|
|
67
|
+
browsers keep the collapse clip and let the glow breathe sideways; older
|
|
68
|
+
ones keep the (harmless) clipped-glow behavior. */
|
|
69
|
+
@supports (overflow: clip) {
|
|
70
|
+
.sk-stage__collapse > div { overflow-x: visible; overflow-y: clip; }
|
|
71
|
+
}
|
|
63
72
|
.sk-stage__beat[data-sk-beat-state="active"] .sk-stage__collapse--body { grid-template-rows: 1fr; }
|
|
64
73
|
.sk-stage__beat:not([data-sk-beat-state="active"]) .sk-stage__collapse--summary { grid-template-rows: 1fr; }
|
|
65
74
|
|
|
@@ -189,5 +198,5 @@ function SummaryTick() {
|
|
|
189
198
|
}
|
|
190
199
|
|
|
191
200
|
export { StageStyles, SummaryTick };
|
|
192
|
-
//# sourceMappingURL=chunk-
|
|
193
|
-
//# sourceMappingURL=chunk-
|
|
201
|
+
//# sourceMappingURL=chunk-WSPGXSBU.mjs.map
|
|
202
|
+
//# sourceMappingURL=chunk-WSPGXSBU.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forms/experience-chrome.tsx"],"names":[],"mappings":";;;AAgBA,IAAM,QAAA,GAAW,cAAA;AAEjB,IAAM,GAAA,GAAM;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAoLL,SAAS,WAAA,GAAc;AAC5B,EAAA,uBAAO,GAAA,CAAC,WAAM,EAAA,EAAI,QAAA,EAAU,yBAAyB,EAAE,MAAA,EAAQ,KAAI,EAAG,CAAA;AACxE;AAEO,SAAS,WAAA,GAAc;AAC5B,EAAA,2BACG,MAAA,EAAA,EAAK,SAAA,EAAU,wBAAA,EAAyB,cAAA,EAAa,sBAAqB,aAAA,EAAY,MAAA,EACrF,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,OAAM,GAAA,EAAI,MAAA,EAAO,KAAI,OAAA,EAAQ,WAAA,EAAY,MAAK,MAAA,EACjD,QAAA,kBAAA,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,CAAA,EAAE,oBAAA;AAAA,MACF,MAAA,EAAO,oCAAA;AAAA,MACP,WAAA,EAAY,KAAA;AAAA,MACZ,aAAA,EAAc,OAAA;AAAA,MACd,cAAA,EAAe;AAAA;AAAA,KAEnB,CAAA,EACF,CAAA;AAEJ","file":"chunk-WSPGXSBU.mjs","sourcesContent":["'use client'\n\n/**\n * Chrome shared by the alternate form experiences (stage, spotlight): the\n * head row, the segmented progress meter, the collapse mechanics, and the\n * settled-answer check. Lives apart from either component so loading ONE\n * experience never drags the other one's markup and CSS along with it.\n *\n * Construction rules match delight.tsx: zero deps, one deduped style tag,\n * data-sk-part on everything, --sk-* theming, and every accent mixes\n * --sk-primary toward currentColor (the contrast law). Reduced motion\n * collapses animation to instant states.\n */\n\nimport React from 'react'\n\nconst STYLE_ID = 'sk-stage-css'\n\nconst CSS = `\n@keyframes sk-stage-shake { 0%, 100% { transform: translateX(0) } 18% { transform: translateX(-9px) } 40% { transform: translateX(7px) } 62% { transform: translateX(-5px) } 82% { transform: translateX(3px) } }\n@keyframes sk-stage-seg-pop { 0% { transform: scaleY(2.4) } 100% { transform: scaleY(1) } }\n@keyframes sk-stage-seg-breathe { 0%, 100% { opacity: .3 } 50% { opacity: .7 } }\n@keyframes sk-stage-ready-pop { 0% { transform: scale(.8) } 60% { transform: scale(1.15) } 100% { transform: scale(1) } }\n@keyframes sk-stage-tick-in { 0% { transform: scale(.3); opacity: 0 } 70% { transform: scale(1.2) } 100% { transform: scale(1); opacity: 1 } }\n\n.sk-stage { --sk-font-size: 1.125rem; }\n\n/* ---- Head: form name + honest time cost ---- */\n.sk-stage__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 10px; }\n.sk-stage__head-name, .sk-stage__head-meta {\n font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;\n opacity: .75; margin: 0;\n}\n.sk-stage__head-meta { font-weight: 600; opacity: .6; white-space: nowrap; }\n\n/* ---- HUD: segmented progress + counter. Neutral game-style pips — this is\n the site's chrome, not platform branding. ---- */\n.sk-stage__hud { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }\n.sk-stage__meter { flex: 1; display: flex; align-items: center; gap: 4px; }\n.sk-stage__seg {\n flex: 1; height: 5px; border-radius: 999px;\n background: color-mix(in srgb, currentColor 16%, transparent);\n transition: background-color .3s ease;\n transform-origin: center;\n}\n.sk-stage__seg[data-sk-lit=\"true\"] {\n background: color-mix(in srgb, var(--sk-primary, #2563eb) 72%, currentColor);\n animation: sk-stage-seg-pop .3s cubic-bezier(.22,1.4,.36,1) both;\n}\n.sk-stage__seg[data-sk-live=\"true\"] {\n background: color-mix(in srgb, var(--sk-primary, #2563eb) 55%, currentColor);\n animation: sk-stage-seg-breathe 1.7s ease-in-out infinite;\n}\n.sk-stage__counter {\n font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;\n opacity: .75; font-variant-numeric: tabular-nums; white-space: nowrap;\n}\n.sk-stage__counter[data-sk-ready=\"true\"] {\n opacity: 1;\n color: color-mix(in srgb, var(--sk-primary, #2563eb) 60%, currentColor);\n animation: sk-stage-ready-pop .4s cubic-bezier(.22,1.4,.36,1);\n}\n\n/* ---- The accordion of beats ----\n Each beat holds two collapsible layers (summary row / expanded body) built\n on grid-template-rows 0fr<->1fr. Handing off between beats runs FOUR of\n these morphs at once (old body closes + old summary opens + new summary\n closes + new body opens) — the \"previous field settles, next field blooms\"\n transition, in pure CSS. */\n.sk-stage__beats { margin: 6px 0 0; }\n.sk-stage__beat { border-bottom: 1px solid color-mix(in srgb, currentColor 14%, transparent); }\n.sk-stage__collapse {\n display: grid; grid-template-rows: 0fr;\n transition: grid-template-rows .42s cubic-bezier(.22,1,.36,1);\n}\n.sk-stage__collapse > div { overflow: hidden; min-height: 0; }\n/* The clip only needs to work VERTICALLY (that's the collapse axis). Full\n overflow:hidden also chops the focus aura / lock-in glow on the field\n inside — a hard vertical edge on both sides of the input. overflow:clip\n allows per-axis mixing without creating a scroll container, so modern\n browsers keep the collapse clip and let the glow breathe sideways; older\n ones keep the (harmless) clipped-glow behavior. */\n@supports (overflow: clip) {\n .sk-stage__collapse > div { overflow-x: visible; overflow-y: clip; }\n}\n.sk-stage__beat[data-sk-beat-state=\"active\"] .sk-stage__collapse--body { grid-template-rows: 1fr; }\n.sk-stage__beat:not([data-sk-beat-state=\"active\"]) .sk-stage__collapse--summary { grid-template-rows: 1fr; }\n\n/* Inner content blooms slightly after the container starts opening. */\n.sk-stage__body-inner {\n opacity: 0; transform: translateY(10px);\n transition: opacity .26s ease, transform .3s cubic-bezier(.22,1,.36,1);\n padding: 4px 2px 22px;\n}\n.sk-stage__beat[data-sk-beat-state=\"active\"] .sk-stage__body-inner {\n opacity: 1; transform: translateY(0);\n transition-delay: .1s, .1s;\n}\n.sk-stage__summary-inner {\n opacity: 0; transition: opacity .26s ease .08s;\n}\n.sk-stage__beat:not([data-sk-beat-state=\"active\"]) .sk-stage__summary-inner { opacity: 1; }\n\n/* Summary rows: the settled (filled) and waiting (upcoming) states. */\n.sk-stage__summary {\n display: flex; align-items: baseline; gap: 12px; width: 100%;\n padding: 13px 2px; text-align: left; cursor: pointer;\n background: none; border: none; color: inherit; font: inherit;\n transition: background-color .15s ease;\n}\n.sk-stage__summary:hover,\n.sk-stage__summary:focus-visible { background: color-mix(in srgb, currentColor 7%, transparent); }\n.sk-stage__summary-idx {\n font-size: 11px; font-weight: 700; letter-spacing: .06em;\n font-variant-numeric: tabular-nums; opacity: .5; flex-shrink: 0;\n}\n.sk-stage__summary-label {\n font-size: 12px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;\n opacity: .72; flex-shrink: 0;\n}\n.sk-stage__summary-value {\n margin-left: auto; font-weight: 600; text-align: right;\n display: flex; align-items: baseline; gap: 8px; min-width: 0;\n}\n/* Narrow screens: the answer takes its own line under the label — a squeezed\n flex column wraps long values one character per line (found live). */\n@media (max-width: 480px) {\n .sk-stage__summary { flex-wrap: wrap; row-gap: 2px; }\n .sk-stage__summary-value {\n margin-left: 0; flex-basis: 100%; justify-content: flex-start;\n text-align: left; padding-left: 26px;\n }\n}\n.sk-stage__summary-value--skipped { font-weight: 400; font-style: italic; opacity: .6; }\n.sk-stage__beat[data-sk-beat-filled=\"true\"] .sk-stage__summary-label { opacity: .55; }\n.sk-stage__summary-tick {\n width: 15px; height: 15px; border-radius: 50%; flex-shrink: 0; align-self: center;\n background: color-mix(in srgb, var(--sk-primary, #2563eb) 72%, currentColor);\n display: inline-flex; align-items: center; justify-content: center;\n animation: sk-stage-tick-in .28s cubic-bezier(.22,1.4,.36,1) both;\n}\n\n/* ---- Active beat body ---- */\n.sk-stage__fields { display: flex; flex-wrap: wrap; gap: 16px; }\n.sk-stage__fields > * { flex: 1 1 100%; }\n/* Solo beat: the question is the headline. */\n.sk-stage .sk-stage__label {\n font-size: clamp(1.3rem, 1rem + 1.4vw, 1.9rem);\n line-height: 1.14;\n margin-bottom: 14px !important; /* FormField inlines margin-bottom: 6 */\n}\n.sk-stage { --sk-label-weight: 700; }\n/* Grouped beat: fields share the row (like the classic grid), labels calm\n back down so the pair reads as one quick moment. */\n@media (min-width: 640px) {\n .sk-stage__question--group .sk-stage__fields > * { flex: 1 1 0; min-width: 180px; }\n}\n.sk-stage .sk-stage__question--group .sk-stage__label {\n font-size: 1.05rem;\n line-height: 1.3;\n margin-bottom: 8px !important;\n}\n.sk-stage__eyebrow {\n font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;\n opacity: .7; margin: 0 0 10px;\n}\n.sk-stage__eyebrow--greet { opacity: .9; }\n.sk-stage__beat-title {\n margin: 0 0 14px; font-size: clamp(1.2rem, 1rem + 1vw, 1.6rem);\n font-weight: 800; line-height: 1.1;\n}\n.sk-stage__actions { display: flex; align-items: center; gap: 10px; margin-top: 18px; }\n.sk-stage__hint { font-size: 11px; opacity: .6; }\n.sk-stage__hint kbd {\n font: inherit; padding: 1px 5px; border-radius: 4px;\n border: 1px solid color-mix(in srgb, currentColor 35%, transparent);\n}\n@media (pointer: coarse) { .sk-stage__hint { display: none; } }\n\n/* ---- Finale: the submit row ---- */\n.sk-stage__finale { display: flex; align-items: center; gap: 10px; margin-top: 22px; }\n.sk-stage__shake { animation: sk-stage-shake .38s ease; }\n.sk-stage__submit-error { font-size: 14px; margin-top: 12px; }\n\n@media (prefers-reduced-motion: reduce) {\n .sk-stage__collapse { transition: none }\n .sk-stage__body-inner { transition: none; opacity: 1; transform: none }\n .sk-stage__summary-inner { transition: none; opacity: 1 }\n .sk-stage__seg { transition: none }\n .sk-stage__seg[data-sk-lit=\"true\"] { animation: none }\n .sk-stage__seg[data-sk-live=\"true\"] { animation: none; opacity: .5 }\n .sk-stage__counter[data-sk-ready=\"true\"] { animation: none }\n .sk-stage__summary { transition: none }\n .sk-stage__summary-tick { animation: none }\n .sk-stage__shake { animation: none }\n}\n`\n\nexport function StageStyles() {\n return <style id={STYLE_ID} dangerouslySetInnerHTML={{ __html: CSS }} />\n}\n\nexport function SummaryTick() {\n return (\n <span className=\"sk-stage__summary-tick\" data-sk-part=\"stage-summary-tick\" aria-hidden=\"true\">\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M3.5 8.5l3 3 6-6.5\"\n stroke=\"var(--sk-form-success-check, #fff)\"\n strokeWidth=\"2.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n )\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkPGND73EV_js = require('./chunk-PGND73EV.js');
|
|
4
|
+
var chunkLYAU5PRS_js = require('./chunk-LYAU5PRS.js');
|
|
5
5
|
|
|
6
6
|
// src/shared/fetchWithRetry.ts
|
|
7
7
|
function backoffDelay(attempt, response) {
|
|
@@ -50,7 +50,7 @@ var pausedKeys = (() => {
|
|
|
50
50
|
var warnedThisPage = false;
|
|
51
51
|
function isAuthPaused(credential) {
|
|
52
52
|
if (typeof window === "undefined") return false;
|
|
53
|
-
const id =
|
|
53
|
+
const id = chunkPGND73EV_js.credentialBreakerId(credential);
|
|
54
54
|
const until = pausedKeys.get(id);
|
|
55
55
|
if (!until) return false;
|
|
56
56
|
if (Date.now() >= until) {
|
|
@@ -60,7 +60,7 @@ function isAuthPaused(credential) {
|
|
|
60
60
|
return true;
|
|
61
61
|
}
|
|
62
62
|
function tripBreaker(credential) {
|
|
63
|
-
pausedKeys.set(
|
|
63
|
+
pausedKeys.set(chunkPGND73EV_js.credentialBreakerId(credential), Date.now() + AUTH_BREAK_MS);
|
|
64
64
|
if (!warnedThisPage) {
|
|
65
65
|
warnedThisPage = true;
|
|
66
66
|
console.info(
|
|
@@ -70,13 +70,13 @@ function tripBreaker(credential) {
|
|
|
70
70
|
}
|
|
71
71
|
async function sonorFetch(url, init = {}, options = {}) {
|
|
72
72
|
let credential = options.apiKey;
|
|
73
|
-
if (credential !== void 0 ||
|
|
74
|
-
credential = await
|
|
73
|
+
if (credential !== void 0 || chunkPGND73EV_js.isTokenMode()) {
|
|
74
|
+
credential = await chunkPGND73EV_js.getFreshCredential(options.apiKey);
|
|
75
75
|
}
|
|
76
76
|
const headers = new Headers(init.headers || {});
|
|
77
|
-
headers.set("x-sitekit-version",
|
|
77
|
+
headers.set("x-sitekit-version", chunkLYAU5PRS_js.SITE_KIT_VERSION);
|
|
78
78
|
if (credential) {
|
|
79
|
-
if (
|
|
79
|
+
if (chunkPGND73EV_js.isTokenMode()) {
|
|
80
80
|
headers.set("x-api-key", credential);
|
|
81
81
|
headers.delete("authorization");
|
|
82
82
|
} else if (!headers.has("x-api-key")) {
|
|
@@ -87,11 +87,11 @@ async function sonorFetch(url, init = {}, options = {}) {
|
|
|
87
87
|
return new Response(null, { status: 401, statusText: "sonor-auth-paused" });
|
|
88
88
|
}
|
|
89
89
|
let response = await fetchWithRetry(url, { ...init, headers }, options);
|
|
90
|
-
if ((response.status === 401 || response.status === 403) && typeof window !== "undefined" &&
|
|
91
|
-
const refreshed = await
|
|
90
|
+
if ((response.status === 401 || response.status === 403) && typeof window !== "undefined" && chunkPGND73EV_js.isSiteToken(credential)) {
|
|
91
|
+
const refreshed = await chunkPGND73EV_js.refreshSiteToken();
|
|
92
92
|
if (refreshed && refreshed !== credential) {
|
|
93
93
|
const retryHeaders = new Headers(init.headers || {});
|
|
94
|
-
retryHeaders.set("x-sitekit-version",
|
|
94
|
+
retryHeaders.set("x-sitekit-version", chunkLYAU5PRS_js.SITE_KIT_VERSION);
|
|
95
95
|
retryHeaders.set("x-api-key", refreshed);
|
|
96
96
|
retryHeaders.delete("authorization");
|
|
97
97
|
credential = refreshed;
|
|
@@ -104,7 +104,7 @@ async function sonorFetch(url, init = {}, options = {}) {
|
|
|
104
104
|
return response;
|
|
105
105
|
}
|
|
106
106
|
function sonorBeacon(url, payload, apiKey) {
|
|
107
|
-
const credential =
|
|
107
|
+
const credential = chunkPGND73EV_js.currentCredential(apiKey);
|
|
108
108
|
const body = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
109
109
|
try {
|
|
110
110
|
void fetch(url, {
|
|
@@ -112,7 +112,7 @@ function sonorBeacon(url, payload, apiKey) {
|
|
|
112
112
|
keepalive: true,
|
|
113
113
|
headers: {
|
|
114
114
|
"Content-Type": "application/json",
|
|
115
|
-
"x-sitekit-version":
|
|
115
|
+
"x-sitekit-version": chunkLYAU5PRS_js.SITE_KIT_VERSION,
|
|
116
116
|
...credential ? { "x-api-key": credential } : {}
|
|
117
117
|
},
|
|
118
118
|
body
|
|
@@ -130,5 +130,5 @@ function sonorBeacon(url, payload, apiKey) {
|
|
|
130
130
|
|
|
131
131
|
exports.sonorBeacon = sonorBeacon;
|
|
132
132
|
exports.sonorFetch = sonorFetch;
|
|
133
|
-
//# sourceMappingURL=chunk-
|
|
134
|
-
//# sourceMappingURL=chunk-
|
|
133
|
+
//# sourceMappingURL=chunk-WXKEYKE6.js.map
|
|
134
|
+
//# sourceMappingURL=chunk-WXKEYKE6.js.map
|