@appfunnel-dev/sdk 2.0.0-canary.1 → 2.0.0-canary.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities-7_hy5f5G.d.cts +114 -0
- package/dist/capabilities-7_hy5f5G.d.ts +114 -0
- package/dist/checkout-7Dy6IedP.d.ts +320 -0
- package/dist/checkout-Dz8cGkB_.d.cts +320 -0
- package/dist/chunk-AKO6XKXP.js +466 -0
- package/dist/chunk-AKO6XKXP.js.map +1 -0
- package/dist/chunk-CY4VBSMX.cjs +106 -0
- package/dist/chunk-CY4VBSMX.cjs.map +1 -0
- package/dist/chunk-JSRKA375.cjs +497 -0
- package/dist/chunk-JSRKA375.cjs.map +1 -0
- package/dist/chunk-LJYLGLFS.cjs +153 -0
- package/dist/chunk-LJYLGLFS.cjs.map +1 -0
- package/dist/chunk-M6U3FNRW.js +99 -0
- package/dist/chunk-M6U3FNRW.js.map +1 -0
- package/dist/chunk-YY375F2B.js +140 -0
- package/dist/chunk-YY375F2B.js.map +1 -0
- package/dist/driver-paddle.cjs +814 -0
- package/dist/driver-paddle.cjs.map +1 -0
- package/dist/driver-paddle.d.cts +10 -0
- package/dist/driver-paddle.d.ts +10 -0
- package/dist/driver-paddle.js +811 -0
- package/dist/driver-paddle.js.map +1 -0
- package/dist/driver-stripe.cjs +2253 -0
- package/dist/driver-stripe.cjs.map +1 -0
- package/dist/driver-stripe.d.cts +8 -0
- package/dist/driver-stripe.d.ts +8 -0
- package/dist/driver-stripe.js +2247 -0
- package/dist/driver-stripe.js.map +1 -0
- package/dist/index.cjs +1962 -811
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +183 -933
- package/dist/index.d.ts +183 -933
- package/dist/index.js +1683 -653
- package/dist/index.js.map +1 -1
- package/dist/manifest-Cr2y1op6.d.cts +814 -0
- package/dist/manifest-Cr2y1op6.d.ts +814 -0
- package/dist/manifest-entry.cjs +312 -0
- package/dist/manifest-entry.cjs.map +1 -0
- package/dist/manifest-entry.d.cts +209 -0
- package/dist/manifest-entry.d.ts +209 -0
- package/dist/manifest-entry.js +198 -0
- package/dist/manifest-entry.js.map +1 -0
- package/package.json +37 -4
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
3
|
+
var chunkJSRKA375_cjs = require('./chunk-JSRKA375.cjs');
|
|
4
|
+
var chunkLJYLGLFS_cjs = require('./chunk-LJYLGLFS.cjs');
|
|
5
|
+
var React = require('react');
|
|
6
|
+
var ReactDOM = require('react-dom');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
12
|
+
var ReactDOM__default = /*#__PURE__*/_interopDefault(ReactDOM);
|
|
8
13
|
|
|
9
14
|
// src/state/variableStore.ts
|
|
10
15
|
var VariableStore = class {
|
|
@@ -258,8 +263,12 @@ function collectClickIds() {
|
|
|
258
263
|
}
|
|
259
264
|
function readCookie(name) {
|
|
260
265
|
if (typeof document === "undefined") return void 0;
|
|
261
|
-
|
|
262
|
-
|
|
266
|
+
try {
|
|
267
|
+
const m = document.cookie.match(new RegExp("(?:^|; )" + name + "=([^;]*)"));
|
|
268
|
+
return m ? decodeURIComponent(m[1]) : void 0;
|
|
269
|
+
} catch {
|
|
270
|
+
return void 0;
|
|
271
|
+
}
|
|
263
272
|
}
|
|
264
273
|
function buildAcquisition(context) {
|
|
265
274
|
return {
|
|
@@ -272,41 +281,44 @@ function buildAcquisition(context) {
|
|
|
272
281
|
}
|
|
273
282
|
function buildContext(opts = {}) {
|
|
274
283
|
const raw = detect();
|
|
275
|
-
const
|
|
284
|
+
const now2 = opts.now ?? 0;
|
|
276
285
|
const referrer = typeof document !== "undefined" ? document.referrer : "";
|
|
277
|
-
const
|
|
286
|
+
const base = {
|
|
278
287
|
device: raw.device,
|
|
279
288
|
browser: raw.browser,
|
|
280
289
|
os: raw.os,
|
|
281
290
|
locale: raw.locale,
|
|
282
291
|
utm: collectUtm(),
|
|
283
292
|
clickIds: collectClickIds(),
|
|
284
|
-
page: { key: "", slug: "", index: 0, total: 0, progressPercentage: 0, startedAt:
|
|
285
|
-
session: { id: opts.sessionId ?? null, startedAt:
|
|
293
|
+
page: { key: "", slug: "", index: 0, total: 0, progressPercentage: 0, startedAt: now2 },
|
|
294
|
+
session: { id: opts.sessionId ?? null, startedAt: now2, referrer },
|
|
286
295
|
identity: { customerId: opts.customerId ?? null, visitorId: opts.visitorId ?? null },
|
|
287
296
|
system: {
|
|
288
297
|
funnelId: opts.funnelId ?? "",
|
|
289
298
|
campaignId: opts.campaignId ?? "",
|
|
290
299
|
mode: opts.mode ?? "live",
|
|
291
|
-
now
|
|
300
|
+
now: now2
|
|
292
301
|
}
|
|
293
302
|
};
|
|
294
|
-
if (!opts.overrides) return
|
|
303
|
+
if (!opts.overrides) return base;
|
|
295
304
|
return {
|
|
296
|
-
...
|
|
305
|
+
...base,
|
|
297
306
|
...opts.overrides,
|
|
298
|
-
device: { ...
|
|
299
|
-
browser: { ...
|
|
300
|
-
os: { ...
|
|
301
|
-
locale: { ...
|
|
302
|
-
utm: { ...
|
|
303
|
-
clickIds: { ...
|
|
304
|
-
page: { ...
|
|
305
|
-
session: { ...
|
|
306
|
-
identity: { ...
|
|
307
|
-
system: { ...
|
|
307
|
+
device: { ...base.device, ...opts.overrides.device },
|
|
308
|
+
browser: { ...base.browser, ...opts.overrides.browser },
|
|
309
|
+
os: { ...base.os, ...opts.overrides.os },
|
|
310
|
+
locale: { ...base.locale, ...opts.overrides.locale },
|
|
311
|
+
utm: { ...base.utm, ...opts.overrides.utm },
|
|
312
|
+
clickIds: { ...base.clickIds, ...opts.overrides.clickIds },
|
|
313
|
+
page: { ...base.page, ...opts.overrides.page },
|
|
314
|
+
session: { ...base.session, ...opts.overrides.session },
|
|
315
|
+
identity: { ...base.identity, ...opts.overrides.identity },
|
|
316
|
+
system: { ...base.system, ...opts.overrides.system }
|
|
308
317
|
};
|
|
309
318
|
}
|
|
319
|
+
function exposurePayload(experimentId, variant, version) {
|
|
320
|
+
return { experimentId, variant, ...version !== void 0 ? { version } : {} };
|
|
321
|
+
}
|
|
310
322
|
var _eventIdCounter = 0;
|
|
311
323
|
function newEventId() {
|
|
312
324
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
@@ -323,20 +335,20 @@ function createConsoleTracker(opts = {}) {
|
|
|
323
335
|
setAcquisition: (acq) => log("acquisition", acq)
|
|
324
336
|
};
|
|
325
337
|
}
|
|
326
|
-
var TrackerContext =
|
|
338
|
+
var TrackerContext = React.createContext(null);
|
|
327
339
|
function TrackerProvider({
|
|
328
340
|
tracker,
|
|
329
341
|
children
|
|
330
342
|
}) {
|
|
331
|
-
return
|
|
343
|
+
return React.createElement(TrackerContext.Provider, { value: tracker }, children);
|
|
332
344
|
}
|
|
333
345
|
function useTrackerRef() {
|
|
334
|
-
return
|
|
346
|
+
return React.useContext(TrackerContext) ?? FALLBACK;
|
|
335
347
|
}
|
|
336
348
|
var FALLBACK = createConsoleTracker({ silent: true });
|
|
337
349
|
function useTracker() {
|
|
338
350
|
const tracker = useTrackerRef();
|
|
339
|
-
const track =
|
|
351
|
+
const track = React.useCallback(
|
|
340
352
|
(event, data, userData) => tracker.track(event, data, userData),
|
|
341
353
|
[tracker]
|
|
342
354
|
);
|
|
@@ -345,7 +357,7 @@ function useTracker() {
|
|
|
345
357
|
|
|
346
358
|
// src/tracking/bus.ts
|
|
347
359
|
var MAX_HISTORY = 250;
|
|
348
|
-
function createBus(accessors,
|
|
360
|
+
function createBus(accessors, now2 = () => Date.now()) {
|
|
349
361
|
const listeners = /* @__PURE__ */ new Map();
|
|
350
362
|
const events = [];
|
|
351
363
|
const on = (event, cb) => {
|
|
@@ -358,7 +370,7 @@ function createBus(accessors, now = () => Date.now()) {
|
|
|
358
370
|
listeners.get(event)?.delete(cb);
|
|
359
371
|
};
|
|
360
372
|
const emit = (event, data) => {
|
|
361
|
-
events.push({ event, data, ts:
|
|
373
|
+
events.push({ event, data, ts: now2() });
|
|
362
374
|
if (events.length > MAX_HISTORY) events.shift();
|
|
363
375
|
for (const cb of listeners.get(event) ?? []) {
|
|
364
376
|
try {
|
|
@@ -413,21 +425,6 @@ function attachBus(bus) {
|
|
|
413
425
|
if (window.appfunnel === api) delete window.appfunnel;
|
|
414
426
|
};
|
|
415
427
|
}
|
|
416
|
-
var RTL_LANGS = /* @__PURE__ */ new Set(["ar", "he", "fa", "ur", "ps", "sd", "dv", "yi"]);
|
|
417
|
-
function isRtl(locale) {
|
|
418
|
-
return RTL_LANGS.has(locale.split("-")[0]);
|
|
419
|
-
}
|
|
420
|
-
var base = (l) => l?.split("-")[0];
|
|
421
|
-
function resolveLocale(config, detected, override) {
|
|
422
|
-
const supported = config?.supported ?? (config?.default ? [config.default] : ["en"]);
|
|
423
|
-
const def = config?.default ?? supported[0] ?? "en";
|
|
424
|
-
const pick = (l) => {
|
|
425
|
-
if (!l) return void 0;
|
|
426
|
-
if (supported.includes(l)) return l;
|
|
427
|
-
return supported.find((s) => base(s) === base(l));
|
|
428
|
-
};
|
|
429
|
-
return pick(override) ?? pick(detected) ?? def;
|
|
430
|
-
}
|
|
431
428
|
function interpolate(str, params) {
|
|
432
429
|
if (!params) return str;
|
|
433
430
|
return str.replace(/\{\{(\w+)\}\}/g, (_, k) => k in params ? String(params[k]) : `{{${k}}}`);
|
|
@@ -447,7 +444,7 @@ function devWarn(message) {
|
|
|
447
444
|
} catch {
|
|
448
445
|
}
|
|
449
446
|
}
|
|
450
|
-
var LocaleContext =
|
|
447
|
+
var LocaleContext = React.createContext(null);
|
|
451
448
|
function LocaleProvider({
|
|
452
449
|
config,
|
|
453
450
|
catalog = {},
|
|
@@ -455,26 +452,29 @@ function LocaleProvider({
|
|
|
455
452
|
override,
|
|
456
453
|
children
|
|
457
454
|
}) {
|
|
458
|
-
const [locale, setLocale] =
|
|
459
|
-
|
|
455
|
+
const [locale, setLocale] = React.useState(() => chunkJSRKA375_cjs.resolveLocale(config, detected, override));
|
|
456
|
+
React.useEffect(() => {
|
|
457
|
+
setLocale(chunkJSRKA375_cjs.resolveLocale(config, detected, override));
|
|
458
|
+
}, [config, detected, override]);
|
|
459
|
+
const value = React.useMemo(
|
|
460
460
|
() => ({ locale, setLocale, config, catalog }),
|
|
461
461
|
[locale, config, catalog]
|
|
462
462
|
);
|
|
463
|
-
return
|
|
463
|
+
return React.createElement(LocaleContext.Provider, { value }, children);
|
|
464
464
|
}
|
|
465
465
|
function useActiveLocale() {
|
|
466
|
-
return
|
|
466
|
+
return React.useContext(LocaleContext)?.locale ?? "en";
|
|
467
467
|
}
|
|
468
468
|
function useTranslation() {
|
|
469
|
-
const ctx =
|
|
469
|
+
const ctx = React.useContext(LocaleContext);
|
|
470
470
|
if (!ctx) throw new Error("useTranslation must be used inside <FunnelProvider>");
|
|
471
471
|
const { locale, setLocale, config, catalog } = ctx;
|
|
472
|
-
const chain =
|
|
472
|
+
const chain = React.useMemo(() => {
|
|
473
473
|
const def = config?.default;
|
|
474
474
|
const fb = config?.fallback;
|
|
475
475
|
return Array.from(new Set([locale, fb, def].filter(Boolean)));
|
|
476
476
|
}, [locale, config]);
|
|
477
|
-
const t =
|
|
477
|
+
const t = React.useMemo(() => {
|
|
478
478
|
const fn = ((key, params) => {
|
|
479
479
|
const raw = lookup(catalog, chain, key);
|
|
480
480
|
if (raw === void 0) {
|
|
@@ -484,17 +484,40 @@ function useTranslation() {
|
|
|
484
484
|
return interpolate(raw, params);
|
|
485
485
|
});
|
|
486
486
|
fn.plural = (n, forms, params) => {
|
|
487
|
-
|
|
487
|
+
let rule;
|
|
488
|
+
try {
|
|
489
|
+
rule = new Intl.PluralRules(locale).select(n);
|
|
490
|
+
} catch {
|
|
491
|
+
rule = "other";
|
|
492
|
+
}
|
|
488
493
|
const form = forms[rule] ?? forms.other ?? "";
|
|
489
494
|
return interpolate(form.replace(/#/g, String(n)), params);
|
|
490
495
|
};
|
|
491
496
|
return fn;
|
|
492
497
|
}, [catalog, chain, locale]);
|
|
493
|
-
const fmt =
|
|
498
|
+
const fmt = React.useMemo(
|
|
494
499
|
() => ({
|
|
495
|
-
number: (n, opts) =>
|
|
496
|
-
|
|
497
|
-
|
|
500
|
+
number: (n, opts) => {
|
|
501
|
+
try {
|
|
502
|
+
return new Intl.NumberFormat(locale, opts).format(n);
|
|
503
|
+
} catch {
|
|
504
|
+
return String(n);
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
date: (d, opts) => {
|
|
508
|
+
try {
|
|
509
|
+
return new Intl.DateTimeFormat(locale, opts).format(d);
|
|
510
|
+
} catch {
|
|
511
|
+
return String(d instanceof Date ? d.toISOString() : d);
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
percent: (n, opts) => {
|
|
515
|
+
try {
|
|
516
|
+
return new Intl.NumberFormat(locale, { style: "percent", ...opts }).format(n);
|
|
517
|
+
} catch {
|
|
518
|
+
return `${(n * 100).toFixed(0)}%`;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
498
521
|
}),
|
|
499
522
|
[locale]
|
|
500
523
|
);
|
|
@@ -503,336 +526,41 @@ function useTranslation() {
|
|
|
503
526
|
fmt,
|
|
504
527
|
locale,
|
|
505
528
|
setLocale,
|
|
506
|
-
dir: isRtl(locale) ? "rtl" : "ltr",
|
|
529
|
+
dir: chunkJSRKA375_cjs.isRtl(locale) ? "rtl" : "ltr",
|
|
507
530
|
locales: config?.supported ?? [locale]
|
|
508
531
|
};
|
|
509
532
|
}
|
|
510
533
|
|
|
511
534
|
// src/commerce/catalog.ts
|
|
512
|
-
var
|
|
513
|
-
day: 1,
|
|
514
|
-
week: 7,
|
|
515
|
-
month: 30,
|
|
516
|
-
year: 365,
|
|
517
|
-
one_time: 0
|
|
518
|
-
};
|
|
519
|
-
function periodDays(interval, count) {
|
|
520
|
-
return PERIOD_DAYS[interval] * count;
|
|
521
|
-
}
|
|
522
|
-
function intervalLabel(interval, count) {
|
|
523
|
-
if (interval === "one_time") return { period: "one-time", periodly: "one-time" };
|
|
524
|
-
if (interval === "month" && count === 3) return { period: "quarter", periodly: "quarterly" };
|
|
525
|
-
if (interval === "month" && count === 6) return { period: "6 months", periodly: "semiannually" };
|
|
526
|
-
if (interval === "week" && count === 2) return { period: "2 weeks", periodly: "biweekly" };
|
|
527
|
-
if (count === 1) {
|
|
528
|
-
const periodly = { day: "daily", week: "weekly", month: "monthly", year: "yearly" }[interval];
|
|
529
|
-
return { period: interval, periodly };
|
|
530
|
-
}
|
|
531
|
-
return { period: `${count} ${interval}s`, periodly: `every ${count} ${interval}s` };
|
|
532
|
-
}
|
|
533
|
-
function resolveProduct(input) {
|
|
534
|
-
const interval = input.interval ?? "one_time";
|
|
535
|
-
const count = input.intervalCount ?? 1;
|
|
536
|
-
const days = periodDays(interval, count);
|
|
537
|
-
const perDayMinor = days > 0 ? input.amount / days : input.amount;
|
|
538
|
-
const label = intervalLabel(interval, count);
|
|
539
|
-
return {
|
|
540
|
-
id: input.id,
|
|
541
|
-
name: input.name ?? input.id,
|
|
542
|
-
displayName: input.displayName ?? input.name ?? input.id,
|
|
543
|
-
provider: input.provider ?? "stripe",
|
|
544
|
-
currency: input.currency,
|
|
545
|
-
priceMinor: input.amount,
|
|
546
|
-
perDayMinor,
|
|
547
|
-
perWeekMinor: perDayMinor * 7,
|
|
548
|
-
perMonthMinor: perDayMinor * 30,
|
|
549
|
-
perYearMinor: perDayMinor * 365,
|
|
550
|
-
period: label.period,
|
|
551
|
-
periodly: label.periodly,
|
|
552
|
-
hasTrial: (input.trialDays ?? 0) > 0,
|
|
553
|
-
trialDays: input.trialDays ?? 0,
|
|
554
|
-
trialMinor: input.trialAmount ?? 0
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
function buildCatalog(inputs) {
|
|
558
|
-
return new Map(inputs.map((i) => [i.id, resolveProduct(i)]));
|
|
559
|
-
}
|
|
560
|
-
function formatMoney(minor, currency, locale) {
|
|
561
|
-
const amount = minor / 100;
|
|
562
|
-
const code = currency.toUpperCase();
|
|
563
|
-
let formatted;
|
|
564
|
-
try {
|
|
565
|
-
formatted = new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(amount);
|
|
566
|
-
} catch {
|
|
567
|
-
formatted = `${code} ${amount.toFixed(2)}`;
|
|
568
|
-
}
|
|
569
|
-
return { amount, minor, currency: code, formatted };
|
|
570
|
-
}
|
|
571
|
-
function formatProduct(r, locale) {
|
|
572
|
-
const m = (minor) => formatMoney(minor, r.currency, locale);
|
|
573
|
-
return {
|
|
574
|
-
id: r.id,
|
|
575
|
-
name: r.name,
|
|
576
|
-
displayName: r.displayName,
|
|
577
|
-
provider: r.provider,
|
|
578
|
-
price: m(r.priceMinor),
|
|
579
|
-
period: r.period,
|
|
580
|
-
periodly: r.periodly,
|
|
581
|
-
perDay: m(r.perDayMinor),
|
|
582
|
-
perWeek: m(r.perWeekMinor),
|
|
583
|
-
perMonth: m(r.perMonthMinor),
|
|
584
|
-
perYear: m(r.perYearMinor),
|
|
585
|
-
hasTrial: r.hasTrial,
|
|
586
|
-
trialDays: r.trialDays,
|
|
587
|
-
trialPrice: r.hasTrial ? m(r.trialMinor) : null
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
var CatalogContext = react.createContext(null);
|
|
535
|
+
var CatalogContext = React.createContext(null);
|
|
591
536
|
function CatalogProvider({
|
|
592
537
|
catalog,
|
|
593
538
|
children
|
|
594
539
|
}) {
|
|
595
|
-
return
|
|
540
|
+
return React.createElement(CatalogContext.Provider, { value: catalog }, children);
|
|
596
541
|
}
|
|
597
542
|
function useCatalog() {
|
|
598
|
-
return
|
|
543
|
+
return React.useContext(CatalogContext) ?? EMPTY;
|
|
599
544
|
}
|
|
600
545
|
var EMPTY = /* @__PURE__ */ new Map();
|
|
601
546
|
function useProduct(id) {
|
|
602
547
|
const catalog = useCatalog();
|
|
603
548
|
const locale = useActiveLocale();
|
|
604
549
|
const resolved = id ? catalog.get(id) : void 0;
|
|
605
|
-
return
|
|
550
|
+
return React.useMemo(() => resolved ? chunkJSRKA375_cjs.formatProduct(resolved, locale) : void 0, [resolved, locale]);
|
|
606
551
|
}
|
|
607
552
|
function useProducts() {
|
|
608
553
|
const catalog = useCatalog();
|
|
609
554
|
const locale = useActiveLocale();
|
|
610
|
-
return
|
|
611
|
-
() => Array.from(catalog.values()).map((r) => formatProduct(r, locale)),
|
|
555
|
+
return React.useMemo(
|
|
556
|
+
() => Array.from(catalog.values()).map((r) => chunkJSRKA375_cjs.formatProduct(r, locale)),
|
|
612
557
|
[catalog, locale]
|
|
613
558
|
);
|
|
614
559
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
function readField(s, field) {
|
|
618
|
-
let cur = s;
|
|
619
|
-
for (const part of field.split(".")) {
|
|
620
|
-
if (cur == null) return void 0;
|
|
621
|
-
cur = cur[part];
|
|
622
|
-
}
|
|
623
|
-
return cur;
|
|
624
|
-
}
|
|
625
|
-
function evaluateCondition(cond, s) {
|
|
626
|
-
const val = readField(s, cond.field);
|
|
627
|
-
const { op, value } = cond;
|
|
628
|
-
switch (op) {
|
|
629
|
-
case "eq":
|
|
630
|
-
return val === value;
|
|
631
|
-
case "neq":
|
|
632
|
-
return val !== value;
|
|
633
|
-
case "in":
|
|
634
|
-
return Array.isArray(value) && value.includes(val);
|
|
635
|
-
case "gt":
|
|
636
|
-
return typeof val === "number" && typeof value === "number" && val > value;
|
|
637
|
-
case "gte":
|
|
638
|
-
return typeof val === "number" && typeof value === "number" && val >= value;
|
|
639
|
-
case "lt":
|
|
640
|
-
return typeof val === "number" && typeof value === "number" && val < value;
|
|
641
|
-
case "lte":
|
|
642
|
-
return typeof val === "number" && typeof value === "number" && val <= value;
|
|
643
|
-
case "contains":
|
|
644
|
-
if (typeof val === "string") return val.includes(String(value));
|
|
645
|
-
if (Array.isArray(val)) return val.includes(value);
|
|
646
|
-
return false;
|
|
647
|
-
case "exists":
|
|
648
|
-
return val !== void 0 && val !== null && val !== "";
|
|
649
|
-
case "empty":
|
|
650
|
-
return val === void 0 || val === null || val === "" || Array.isArray(val) && val.length === 0;
|
|
651
|
-
default:
|
|
652
|
-
return false;
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
function evaluateGate(gate, s) {
|
|
656
|
-
return typeof gate === "function" ? gate(s) : evaluateCondition(gate, s);
|
|
657
|
-
}
|
|
658
|
-
function resolveRoute(routes, s) {
|
|
659
|
-
if (!routes) return void 0;
|
|
660
|
-
for (const route of routes) {
|
|
661
|
-
if (!route.when || evaluateGate(route.when, s)) return route.to;
|
|
662
|
-
}
|
|
663
|
-
return void 0;
|
|
664
|
-
}
|
|
665
|
-
function pageMeta(meta) {
|
|
666
|
-
return meta;
|
|
667
|
-
}
|
|
668
|
-
var TYPE_GUARDS = {
|
|
669
|
-
paywall: { field: "user.email", op: "exists" },
|
|
670
|
-
upsell: { field: "user.email", op: "exists" }
|
|
671
|
-
};
|
|
672
|
-
function entryGuard(meta) {
|
|
673
|
-
return meta?.guard ?? (meta?.type ? TYPE_GUARDS[meta.type] : void 0);
|
|
674
|
-
}
|
|
675
|
-
function definePage(component) {
|
|
676
|
-
return component;
|
|
677
|
-
}
|
|
678
|
-
function nextPage(pages, currentKey, s) {
|
|
679
|
-
const idx = pages.findIndex((p) => p.key === currentKey);
|
|
680
|
-
if (idx === -1) return void 0;
|
|
681
|
-
const routed = resolveRoute(pages[idx].meta?.next, s);
|
|
682
|
-
if (routed) return routed;
|
|
683
|
-
return pages[idx + 1]?.key;
|
|
684
|
-
}
|
|
685
|
-
function outgoingKeys(pages, currentKey) {
|
|
686
|
-
const idx = pages.findIndex((p) => p.key === currentKey);
|
|
687
|
-
if (idx === -1) return [];
|
|
688
|
-
const out = /* @__PURE__ */ new Set();
|
|
689
|
-
for (const route of pages[idx].meta?.next ?? []) out.add(route.to);
|
|
690
|
-
const linear = pages[idx + 1]?.key;
|
|
691
|
-
if (linear) out.add(linear);
|
|
692
|
-
return [...out];
|
|
693
|
-
}
|
|
694
|
-
function expectedPathLength(pages, startKey, s) {
|
|
695
|
-
const seen = /* @__PURE__ */ new Set();
|
|
696
|
-
let key = startKey;
|
|
697
|
-
let count = 0;
|
|
698
|
-
while (key && !seen.has(key)) {
|
|
699
|
-
seen.add(key);
|
|
700
|
-
count++;
|
|
701
|
-
if (pages.find((p) => p.key === key)?.meta?.type === "finish") break;
|
|
702
|
-
key = nextPage(pages, key, s);
|
|
703
|
-
}
|
|
704
|
-
return count;
|
|
705
|
-
}
|
|
706
|
-
function defineFunnel(def) {
|
|
707
|
-
return def;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
// src/flow/experiments.ts
|
|
711
|
-
function fnv1a(input) {
|
|
712
|
-
let h = 2166136261;
|
|
713
|
-
for (let i = 0; i < input.length; i++) {
|
|
714
|
-
h ^= input.charCodeAt(i);
|
|
715
|
-
h = h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)) >>> 0;
|
|
716
|
-
}
|
|
717
|
-
return h >>> 0;
|
|
718
|
-
}
|
|
719
|
-
function hashToUnit(seed) {
|
|
720
|
-
return fnv1a(seed) / 4294967296;
|
|
721
|
-
}
|
|
722
|
-
function pickByWeight(weights, u) {
|
|
723
|
-
const entries = Object.entries(weights).filter(([, w]) => w > 0);
|
|
724
|
-
if (entries.length === 0) return Object.keys(weights)[0] ?? "";
|
|
725
|
-
const total = entries.reduce((sum, [, w]) => sum + w, 0);
|
|
726
|
-
const target = u * total;
|
|
727
|
-
let acc = 0;
|
|
728
|
-
for (const [key, w] of entries) {
|
|
729
|
-
acc += w;
|
|
730
|
-
if (target < acc) return key;
|
|
731
|
-
}
|
|
732
|
-
return entries[entries.length - 1][0];
|
|
733
|
-
}
|
|
734
|
-
function assignVariant(experimentId, seed, weights) {
|
|
735
|
-
return pickByWeight(weights, hashToUnit(`${experimentId}:${seed}`));
|
|
736
|
-
}
|
|
737
|
-
function bucketingSeed(context) {
|
|
738
|
-
return context.identity.customerId ?? context.identity.visitorId ?? null;
|
|
739
|
-
}
|
|
740
|
-
function parseSlotKey(key) {
|
|
741
|
-
const at = key.indexOf("@");
|
|
742
|
-
return at === -1 ? { slot: key } : { slot: key.slice(0, at), variant: key.slice(at + 1) };
|
|
743
|
-
}
|
|
744
|
-
function isVariantKey(key) {
|
|
745
|
-
return parseSlotKey(key).variant !== void 0;
|
|
746
|
-
}
|
|
747
|
-
function weightsOf(exp) {
|
|
748
|
-
const out = {};
|
|
749
|
-
for (const [label, v] of Object.entries(exp.variants)) out[label] = v.weight;
|
|
750
|
-
return out;
|
|
751
|
-
}
|
|
752
|
-
function resolveExperiments(pages, experiments, seed) {
|
|
753
|
-
const assignments = {};
|
|
754
|
-
const render = {};
|
|
755
|
-
const experimentOf = {};
|
|
756
|
-
for (const exp of experiments) {
|
|
757
|
-
const status = exp.status ?? "running";
|
|
758
|
-
let label;
|
|
759
|
-
if (status === "stopped" && exp.winner) label = exp.winner;
|
|
760
|
-
else if (status === "running" && seed) label = assignVariant(exp.id, seed, weightsOf(exp));
|
|
761
|
-
else continue;
|
|
762
|
-
const arm = exp.variants[label];
|
|
763
|
-
if (!arm) continue;
|
|
764
|
-
assignments[exp.id] = label;
|
|
765
|
-
experimentOf[exp.slot] = exp.id;
|
|
766
|
-
if (arm.page !== exp.slot) render[exp.slot] = arm.page;
|
|
767
|
-
}
|
|
768
|
-
const slotOf = {};
|
|
769
|
-
const activeKeys = [];
|
|
770
|
-
for (const p of pages) {
|
|
771
|
-
const { slot, variant } = parseSlotKey(p.key);
|
|
772
|
-
if (variant !== void 0) slotOf[p.key] = slot;
|
|
773
|
-
else activeKeys.push(p.key);
|
|
774
|
-
}
|
|
775
|
-
return { assignments, activeKeys, render, slotOf, experimentOf };
|
|
776
|
-
}
|
|
777
|
-
function validateExperiments(experiments, pages) {
|
|
778
|
-
const errors = [];
|
|
779
|
-
const warnings = [];
|
|
780
|
-
const pageKeys = new Set(pages.map((p) => p.key));
|
|
781
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
782
|
-
const slotOwner = /* @__PURE__ */ new Map();
|
|
783
|
-
const renderedVariantPages = /* @__PURE__ */ new Set();
|
|
784
|
-
for (const exp of experiments) {
|
|
785
|
-
const err = (code, message) => errors.push({ experimentId: exp.id, code, message });
|
|
786
|
-
const warn = (code, message) => warnings.push({ experimentId: exp.id, code, message });
|
|
787
|
-
if (seenIds.has(exp.id)) err("duplicate_id", `Experiment id "${exp.id}" is used more than once.`);
|
|
788
|
-
seenIds.add(exp.id);
|
|
789
|
-
if (!pageKeys.has(exp.slot)) err("slot_missing", `Slot "${exp.slot}" is not a page in the funnel.`);
|
|
790
|
-
if (isVariantKey(exp.slot)) err("slot_is_variant", `Slot "${exp.slot}" is a variant page; a slot must be a real flow page.`);
|
|
791
|
-
if (slotOwner.has(exp.slot)) {
|
|
792
|
-
err("slot_conflict", `Slot "${exp.slot}" is already targeted by experiment "${slotOwner.get(exp.slot)}".`);
|
|
793
|
-
} else {
|
|
794
|
-
slotOwner.set(exp.slot, exp.id);
|
|
795
|
-
}
|
|
796
|
-
const arms = Object.entries(exp.variants);
|
|
797
|
-
if (arms.length < 2) warn("single_arm", `Experiment "${exp.id}" has fewer than two variants \u2014 nothing to test.`);
|
|
798
|
-
let hasControl = false;
|
|
799
|
-
let totalWeight = 0;
|
|
800
|
-
for (const [label, arm] of arms) {
|
|
801
|
-
if (!pageKeys.has(arm.page)) {
|
|
802
|
-
err("variant_page_missing", `Variant "${label}" references page "${arm.page}", which doesn't exist.`);
|
|
803
|
-
}
|
|
804
|
-
if (arm.page === exp.slot) hasControl = true;
|
|
805
|
-
else if (isVariantKey(arm.page)) {
|
|
806
|
-
renderedVariantPages.add(arm.page);
|
|
807
|
-
if (parseSlotKey(arm.page).slot !== exp.slot) {
|
|
808
|
-
err("variant_slot_mismatch", `Variant "${label}" page "${arm.page}" belongs to a different slot than "${exp.slot}".`);
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
if (arm.weight < 0) err("negative_weight", `Variant "${label}" has a negative weight (${arm.weight}).`);
|
|
812
|
-
totalWeight += arm.weight;
|
|
813
|
-
}
|
|
814
|
-
if (!hasControl) err("no_control", `No variant of "${exp.id}" renders the slot "${exp.slot}" itself (the control/baseline).`);
|
|
815
|
-
if (totalWeight <= 0) err("no_traffic", `Experiment "${exp.id}" has no positive weight \u2014 no traffic would enter it.`);
|
|
816
|
-
if (exp.status === "stopped" && exp.winner && !exp.variants[exp.winner]) {
|
|
817
|
-
err("bad_winner", `Stopped experiment "${exp.id}" names winner "${exp.winner}", which isn't one of its variants.`);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
const running = new Set(experiments.filter((e) => (e.status ?? "running") === "running").flatMap(
|
|
821
|
-
(e) => Object.values(e.variants).map((v) => v.page)
|
|
822
|
-
));
|
|
823
|
-
for (const p of pages) {
|
|
824
|
-
if (isVariantKey(p.key) && !running.has(p.key)) {
|
|
825
|
-
warnings.push({ experimentId: "*", code: "orphan_variant", message: `Variant page "${p.key}" is rendered by no running experiment.` });
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
return { ok: errors.length === 0, errors, warnings };
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
// src/flow/flow.tsx
|
|
832
|
-
var NavContext = react.createContext(null);
|
|
833
|
-
var ExperimentContext = react.createContext({});
|
|
560
|
+
var NavContext = React.createContext(null);
|
|
561
|
+
var ExperimentContext = React.createContext({});
|
|
834
562
|
function useExperiment(id) {
|
|
835
|
-
return
|
|
563
|
+
return React.useContext(ExperimentContext)[id];
|
|
836
564
|
}
|
|
837
565
|
function pageContextFor(currentKey, slug, index, total, startedAt) {
|
|
838
566
|
const denom = Math.max(total, index + 1);
|
|
@@ -845,6 +573,39 @@ function pageContextFor(currentKey, slug, index, total, startedAt) {
|
|
|
845
573
|
startedAt
|
|
846
574
|
};
|
|
847
575
|
}
|
|
576
|
+
var now = () => typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
577
|
+
function usePageExitTimer(tracker, currentKey) {
|
|
578
|
+
const timer = React.useRef(null);
|
|
579
|
+
const emitExit = React.useCallback(() => {
|
|
580
|
+
const t = timer.current;
|
|
581
|
+
if (!t) return;
|
|
582
|
+
const at = now();
|
|
583
|
+
const hidden = t.hidden + (t.hiddenSince != null ? at - t.hiddenSince : 0);
|
|
584
|
+
const durationMs = Math.round(at - t.enteredAt);
|
|
585
|
+
tracker.track("page.exit", { pageId: t.key, durationMs, activeMs: Math.max(0, Math.round(durationMs - hidden)) });
|
|
586
|
+
}, [tracker]);
|
|
587
|
+
React.useEffect(() => {
|
|
588
|
+
if (typeof document === "undefined") return;
|
|
589
|
+
const onVis = () => {
|
|
590
|
+
const t = timer.current;
|
|
591
|
+
if (!t) return;
|
|
592
|
+
if (document.visibilityState === "hidden") t.hiddenSince = now();
|
|
593
|
+
else if (t.hiddenSince != null) {
|
|
594
|
+
t.hidden += now() - t.hiddenSince;
|
|
595
|
+
t.hiddenSince = null;
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
document.addEventListener("visibilitychange", onVis);
|
|
599
|
+
return () => document.removeEventListener("visibilitychange", onVis);
|
|
600
|
+
}, []);
|
|
601
|
+
React.useEffect(() => {
|
|
602
|
+
if (!currentKey) return;
|
|
603
|
+
if (timer.current && timer.current.key !== currentKey) emitExit();
|
|
604
|
+
const hidden = typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
605
|
+
timer.current = { key: currentKey, enteredAt: now(), hidden: 0, hiddenSince: hidden ? now() : null };
|
|
606
|
+
}, [currentKey, emitExit]);
|
|
607
|
+
React.useEffect(() => () => emitExit(), [emitExit]);
|
|
608
|
+
}
|
|
848
609
|
function FunnelView({
|
|
849
610
|
pages,
|
|
850
611
|
initialKey,
|
|
@@ -855,141 +616,118 @@ function FunnelView({
|
|
|
855
616
|
}) {
|
|
856
617
|
const funnel = useFunnel();
|
|
857
618
|
const tracker = useTrackerRef();
|
|
858
|
-
const components =
|
|
619
|
+
const components = React.useMemo(() => {
|
|
859
620
|
const map = /* @__PURE__ */ new Map();
|
|
860
621
|
for (const p of pages) {
|
|
861
622
|
if (p.Component) map.set(p.key, p.Component);
|
|
862
623
|
else if (p.load) {
|
|
863
624
|
const load = p.load;
|
|
864
|
-
map.set(p.key,
|
|
625
|
+
map.set(p.key, React.lazy(() => Promise.resolve(load()).then(
|
|
865
626
|
(m) => typeof m === "function" ? { default: m } : m
|
|
866
627
|
)));
|
|
867
628
|
}
|
|
868
629
|
}
|
|
869
630
|
return map;
|
|
870
631
|
}, [pages]);
|
|
871
|
-
const loaders =
|
|
632
|
+
const loaders = React.useMemo(
|
|
872
633
|
() => new Map(pages.filter((p) => p.load).map((p) => [p.key, p.load])),
|
|
873
634
|
[pages]
|
|
874
635
|
);
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
636
|
+
const seedRef = React.useRef(null);
|
|
637
|
+
if (seedRef.current === null) seedRef.current = chunkJSRKA375_cjs.bucketingSeed(funnel.context);
|
|
638
|
+
const seed = seedRef.current;
|
|
639
|
+
const experiments = React.useMemo(
|
|
640
|
+
() => chunkJSRKA375_cjs.resolveExperiments(pages, funnel.experiments, seed),
|
|
878
641
|
[pages, funnel.experiments, seed]
|
|
879
642
|
);
|
|
880
|
-
const
|
|
881
|
-
const
|
|
882
|
-
|
|
643
|
+
const toSlot = React.useCallback((k) => experiments.slotOf[k] ?? k, [experiments]);
|
|
644
|
+
const toRenderKey = React.useCallback((k) => experiments.render[k] ?? k, [experiments]);
|
|
645
|
+
const pageByKey = React.useMemo(() => new Map(pages.map((p) => [p.key, p])), [pages]);
|
|
646
|
+
const flowPages = React.useMemo(
|
|
647
|
+
() => experiments.activeKeys.map((k) => pageByKey.get(k)).filter((p) => p !== void 0),
|
|
883
648
|
[experiments, pageByKey]
|
|
884
649
|
);
|
|
885
|
-
const flow =
|
|
650
|
+
const flow = React.useMemo(
|
|
886
651
|
() => flowPages.map((p) => ({ key: p.key, meta: p.meta })),
|
|
887
652
|
[flowPages]
|
|
888
653
|
);
|
|
889
|
-
const [history, setHistory] =
|
|
654
|
+
const [history, setHistory] = React.useState(() => {
|
|
890
655
|
const start = flowPages[0]?.key;
|
|
891
|
-
if (!initialKey || initialKey === start) return [start]
|
|
892
|
-
const target =
|
|
656
|
+
if (!initialKey || initialKey === start) return start ? [start] : [];
|
|
657
|
+
const target = toSlot(initialKey);
|
|
893
658
|
const page2 = flowPages.find((p) => p.key === target);
|
|
894
|
-
const guard = entryGuard(page2?.meta);
|
|
895
|
-
const ok = page2 && (!guard || evaluateGate(guard, funnel.snapshot()));
|
|
896
|
-
|
|
659
|
+
const guard = chunkJSRKA375_cjs.entryGuard(page2?.meta);
|
|
660
|
+
const ok = page2 && (!guard || chunkJSRKA375_cjs.evaluateGate(guard, funnel.snapshot()));
|
|
661
|
+
const first = ok ? target : start;
|
|
662
|
+
return first ? [first] : [];
|
|
897
663
|
});
|
|
898
664
|
const currentKey = history[history.length - 1];
|
|
899
665
|
const index = history.length - 1;
|
|
900
666
|
const startKey = history[0];
|
|
901
|
-
const total =
|
|
902
|
-
() => expectedPathLength(flow, startKey, funnel.snapshot()),
|
|
667
|
+
const total = React.useMemo(
|
|
668
|
+
() => chunkJSRKA375_cjs.expectedPathLength(flow, startKey, funnel.snapshot()),
|
|
903
669
|
// currentKey in deps: re-trace as each step's answers settle the branch.
|
|
904
670
|
[flow, startKey, currentKey, funnel]
|
|
905
671
|
);
|
|
906
672
|
const slug = pageByKey.get(currentKey)?.meta?.slug ?? currentKey;
|
|
907
|
-
const page =
|
|
673
|
+
const page = React.useMemo(
|
|
908
674
|
() => pageContextFor(currentKey, slug, index, total, funnel.context.system.now),
|
|
909
675
|
[currentKey, slug, index, total, funnel.context.system.now]
|
|
910
676
|
);
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
677
|
+
React.useEffect(() => {
|
|
678
|
+
funnel.context.page = page;
|
|
679
|
+
}, [funnel, page]);
|
|
680
|
+
const started = React.useRef(false);
|
|
681
|
+
React.useEffect(() => {
|
|
914
682
|
if (started.current) return;
|
|
915
683
|
started.current = true;
|
|
916
684
|
tracker.track("funnel.start", {});
|
|
917
685
|
}, [tracker]);
|
|
918
|
-
|
|
686
|
+
React.useEffect(() => {
|
|
919
687
|
if (!currentKey) return;
|
|
920
688
|
tracker.track("page.view", { pageId: currentKey, pageKey: currentKey, isInitial: index === 0, eventId: newEventId() });
|
|
921
689
|
}, [tracker, currentKey, index]);
|
|
922
|
-
|
|
690
|
+
React.useEffect(() => {
|
|
923
691
|
if (currentKey && onNavigate) onNavigate(currentKey, slug);
|
|
924
692
|
}, [onNavigate, currentKey, slug]);
|
|
925
|
-
const exposed =
|
|
926
|
-
|
|
693
|
+
const exposed = React.useRef(/* @__PURE__ */ new Set());
|
|
694
|
+
React.useEffect(() => {
|
|
927
695
|
const expId = experiments.experimentOf[currentKey];
|
|
928
696
|
if (!expId || exposed.current.has(expId)) return;
|
|
929
697
|
exposed.current.add(expId);
|
|
930
|
-
tracker.track("experiment.exposure",
|
|
698
|
+
tracker.track("experiment.exposure", exposurePayload(expId, experiments.assignments[expId], experiments.versionOf[expId]));
|
|
931
699
|
}, [tracker, currentKey, experiments]);
|
|
932
|
-
|
|
933
|
-
const
|
|
934
|
-
const
|
|
935
|
-
const
|
|
936
|
-
|
|
937
|
-
const at = now();
|
|
938
|
-
const hidden = t.hidden + (t.hiddenSince != null ? at - t.hiddenSince : 0);
|
|
939
|
-
const durationMs = Math.round(at - t.enteredAt);
|
|
940
|
-
tracker.track("page.exit", { pageId: t.key, durationMs, activeMs: Math.max(0, Math.round(durationMs - hidden)) });
|
|
941
|
-
}, [tracker]);
|
|
942
|
-
react.useEffect(() => {
|
|
943
|
-
if (typeof document === "undefined") return;
|
|
944
|
-
const onVis = () => {
|
|
945
|
-
const t = timer.current;
|
|
946
|
-
if (!t) return;
|
|
947
|
-
if (document.visibilityState === "hidden") t.hiddenSince = now();
|
|
948
|
-
else if (t.hiddenSince != null) {
|
|
949
|
-
t.hidden += now() - t.hiddenSince;
|
|
950
|
-
t.hiddenSince = null;
|
|
951
|
-
}
|
|
952
|
-
};
|
|
953
|
-
document.addEventListener("visibilitychange", onVis);
|
|
954
|
-
return () => document.removeEventListener("visibilitychange", onVis);
|
|
955
|
-
}, []);
|
|
956
|
-
react.useEffect(() => {
|
|
957
|
-
if (!currentKey) return;
|
|
958
|
-
if (timer.current && timer.current.key !== currentKey) emitExit();
|
|
959
|
-
const hidden = typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
960
|
-
timer.current = { key: currentKey, enteredAt: now(), hidden: 0, hiddenSince: hidden ? now() : null };
|
|
961
|
-
}, [currentKey, emitExit]);
|
|
962
|
-
react.useEffect(() => () => emitExit(), [emitExit]);
|
|
963
|
-
const [isNavigating, startNav] = react.useTransition();
|
|
964
|
-
const next = react.useCallback(() => {
|
|
965
|
-
const target = nextPage(flow, currentKey, funnel.snapshot());
|
|
966
|
-
const resolved = target ? experiments.slotOf[target] ?? target : target;
|
|
700
|
+
usePageExitTimer(tracker, currentKey);
|
|
701
|
+
const [isNavigating, startNav] = React.useTransition();
|
|
702
|
+
const next = React.useCallback(() => {
|
|
703
|
+
const target = chunkJSRKA375_cjs.nextPage(flow, currentKey, funnel.snapshot());
|
|
704
|
+
const resolved = target ? toSlot(target) : target;
|
|
967
705
|
if (resolved) startNav(() => setHistory((h) => [...h, resolved]));
|
|
968
|
-
}, [flow, currentKey, funnel,
|
|
969
|
-
const back =
|
|
706
|
+
}, [flow, currentKey, funnel, toSlot]);
|
|
707
|
+
const back = React.useCallback(
|
|
970
708
|
() => startNav(() => setHistory((h) => h.length > 1 ? h.slice(0, -1) : h)),
|
|
971
709
|
[]
|
|
972
710
|
);
|
|
973
|
-
const go =
|
|
974
|
-
(key) => startNav(() => setHistory((h) => [...h,
|
|
975
|
-
[
|
|
711
|
+
const go = React.useCallback(
|
|
712
|
+
(key) => startNav(() => setHistory((h) => [...h, toSlot(key)])),
|
|
713
|
+
[toSlot]
|
|
976
714
|
);
|
|
977
|
-
const prefetched =
|
|
978
|
-
const prefetch =
|
|
715
|
+
const prefetched = React.useRef(/* @__PURE__ */ new Set());
|
|
716
|
+
const prefetch = React.useCallback(
|
|
979
717
|
(key) => {
|
|
980
|
-
const target =
|
|
718
|
+
const target = toRenderKey(key);
|
|
981
719
|
const load = loaders.get(target);
|
|
982
720
|
if (!load || prefetched.current.has(target)) return;
|
|
983
721
|
prefetched.current.add(target);
|
|
984
722
|
load().catch(() => prefetched.current.delete(target));
|
|
985
723
|
},
|
|
986
|
-
[loaders,
|
|
724
|
+
[loaders, toRenderKey]
|
|
987
725
|
);
|
|
988
|
-
const nextCandidates =
|
|
989
|
-
() => [...new Set(outgoingKeys(flow, currentKey).map(
|
|
990
|
-
[flow, currentKey,
|
|
726
|
+
const nextCandidates = React.useMemo(
|
|
727
|
+
() => [...new Set(chunkJSRKA375_cjs.outgoingKeys(flow, currentKey).map(toRenderKey))],
|
|
728
|
+
[flow, currentKey, toRenderKey]
|
|
991
729
|
);
|
|
992
|
-
|
|
730
|
+
React.useEffect(() => {
|
|
993
731
|
if (prefetchMode !== "auto") return;
|
|
994
732
|
for (const key of nextCandidates) prefetch(key);
|
|
995
733
|
}, [prefetchMode, nextCandidates, prefetch]);
|
|
@@ -1003,18 +741,18 @@ function FunnelView({
|
|
|
1003
741
|
canGoBack: history.length > 1,
|
|
1004
742
|
isNavigating
|
|
1005
743
|
};
|
|
1006
|
-
const renderKey =
|
|
744
|
+
const renderKey = toRenderKey(currentKey);
|
|
1007
745
|
const Current = components.get(renderKey);
|
|
1008
|
-
const pageEl =
|
|
1009
|
-
const content = layout ?
|
|
1010
|
-
return
|
|
746
|
+
const pageEl = React.createElement(React.Suspense, { fallback: fallback ?? null }, Current ? React.createElement(Current) : null);
|
|
747
|
+
const content = layout ? React.createElement(layout, null, pageEl) : pageEl;
|
|
748
|
+
return React.createElement(
|
|
1011
749
|
ExperimentContext.Provider,
|
|
1012
750
|
{ value: experiments.assignments },
|
|
1013
|
-
|
|
751
|
+
React.createElement(NavContext.Provider, { value }, content)
|
|
1014
752
|
);
|
|
1015
753
|
}
|
|
1016
754
|
function useNavigation() {
|
|
1017
|
-
const ctx =
|
|
755
|
+
const ctx = React.useContext(NavContext);
|
|
1018
756
|
if (!ctx) throw new Error("useNavigation must be used inside <FunnelView>");
|
|
1019
757
|
return ctx;
|
|
1020
758
|
}
|
|
@@ -1023,16 +761,22 @@ function usePage() {
|
|
|
1023
761
|
}
|
|
1024
762
|
var symModalId = /* @__PURE__ */ Symbol("AppFunnelModalId");
|
|
1025
763
|
var initialState = {};
|
|
1026
|
-
var ModalStateContext =
|
|
1027
|
-
var ModalIdContext =
|
|
764
|
+
var ModalStateContext = React.createContext(initialState);
|
|
765
|
+
var ModalIdContext = React.createContext(null);
|
|
766
|
+
var ModalDispatchContext = React.createContext(null);
|
|
1028
767
|
var REGISTRY = {};
|
|
1029
768
|
var ALREADY_MOUNTED = {};
|
|
1030
769
|
var modalCallbacks = {};
|
|
1031
770
|
var hideCallbacks = {};
|
|
1032
771
|
var uid = 0;
|
|
1033
772
|
var getUid = () => `_af_modal_${uid++}`;
|
|
1034
|
-
var
|
|
1035
|
-
|
|
773
|
+
var runtimeStack = [];
|
|
774
|
+
var dispatch = (action) => {
|
|
775
|
+
const top = runtimeStack[runtimeStack.length - 1];
|
|
776
|
+
if (!top) {
|
|
777
|
+
throw new Error("No modal dispatch \u2014 render inside <FunnelProvider> (which mounts the modal runtime).");
|
|
778
|
+
}
|
|
779
|
+
top(action);
|
|
1036
780
|
};
|
|
1037
781
|
var modalReducer = (state = initialState, action) => {
|
|
1038
782
|
const { modalId, args, flags } = action.payload;
|
|
@@ -1075,10 +819,10 @@ function registerModal(id, comp, props) {
|
|
|
1075
819
|
function unregisterModal(id) {
|
|
1076
820
|
delete REGISTRY[id];
|
|
1077
821
|
}
|
|
1078
|
-
function
|
|
822
|
+
function showModalVia(d, modal, args) {
|
|
1079
823
|
const id = idOf(modal);
|
|
1080
824
|
if (typeof modal !== "string" && !REGISTRY[id]) registerModal(id, modal);
|
|
1081
|
-
|
|
825
|
+
d({ type: "show", payload: { modalId: id, args } });
|
|
1082
826
|
if (!modalCallbacks[id]) {
|
|
1083
827
|
let res;
|
|
1084
828
|
let rej;
|
|
@@ -1090,9 +834,12 @@ function showModal(modal, args) {
|
|
|
1090
834
|
}
|
|
1091
835
|
return modalCallbacks[id].promise;
|
|
1092
836
|
}
|
|
1093
|
-
function
|
|
837
|
+
function showModal(modal, args) {
|
|
838
|
+
return showModalVia(dispatch, modal, args);
|
|
839
|
+
}
|
|
840
|
+
function hideModalVia(d, modal) {
|
|
1094
841
|
const id = idOf(modal);
|
|
1095
|
-
|
|
842
|
+
d({ type: "hide", payload: { modalId: id } });
|
|
1096
843
|
delete modalCallbacks[id];
|
|
1097
844
|
if (!hideCallbacks[id]) {
|
|
1098
845
|
let res;
|
|
@@ -1105,41 +852,48 @@ function hideModal(modal) {
|
|
|
1105
852
|
}
|
|
1106
853
|
return hideCallbacks[id].promise;
|
|
1107
854
|
}
|
|
1108
|
-
function
|
|
855
|
+
function hideModal(modal) {
|
|
856
|
+
return hideModalVia(dispatch, modal);
|
|
857
|
+
}
|
|
858
|
+
function removeModalVia(d, modal) {
|
|
1109
859
|
const id = idOf(modal);
|
|
1110
|
-
|
|
860
|
+
d({ type: "remove", payload: { modalId: id } });
|
|
1111
861
|
delete modalCallbacks[id];
|
|
1112
862
|
delete hideCallbacks[id];
|
|
1113
863
|
}
|
|
1114
|
-
function
|
|
1115
|
-
dispatch
|
|
864
|
+
function removeModal(modal) {
|
|
865
|
+
removeModalVia(dispatch, modal);
|
|
866
|
+
}
|
|
867
|
+
function setFlags(d, id, flags) {
|
|
868
|
+
d({ type: "set-flags", payload: { modalId: id, flags } });
|
|
1116
869
|
}
|
|
1117
870
|
function useModal(modal, args) {
|
|
1118
|
-
const modals =
|
|
1119
|
-
const contextId =
|
|
871
|
+
const modals = React.useContext(ModalStateContext);
|
|
872
|
+
const contextId = React.useContext(ModalIdContext);
|
|
873
|
+
const d = React.useContext(ModalDispatchContext) ?? dispatch;
|
|
1120
874
|
const isComponent = !!modal && typeof modal !== "string";
|
|
1121
875
|
const id = modal ? idOf(modal) : contextId;
|
|
1122
876
|
if (!id) throw new Error("useModal: no modal id (call inside a defineModal component, or pass an id/component).");
|
|
1123
|
-
|
|
877
|
+
React.useEffect(() => {
|
|
1124
878
|
if (isComponent && !REGISTRY[id]) registerModal(id, modal, args);
|
|
1125
879
|
}, [isComponent, id, modal, args]);
|
|
1126
880
|
const info = modals[id];
|
|
1127
|
-
const show =
|
|
1128
|
-
const hide =
|
|
1129
|
-
const remove =
|
|
1130
|
-
const resolve =
|
|
881
|
+
const show = React.useCallback((a) => showModalVia(d, id, a), [d, id]);
|
|
882
|
+
const hide = React.useCallback(() => hideModalVia(d, id), [d, id]);
|
|
883
|
+
const remove = React.useCallback(() => removeModalVia(d, id), [d, id]);
|
|
884
|
+
const resolve = React.useCallback((v) => {
|
|
1131
885
|
modalCallbacks[id]?.resolve(v);
|
|
1132
886
|
delete modalCallbacks[id];
|
|
1133
887
|
}, [id]);
|
|
1134
|
-
const reject =
|
|
888
|
+
const reject = React.useCallback((v) => {
|
|
1135
889
|
modalCallbacks[id]?.reject(v);
|
|
1136
890
|
delete modalCallbacks[id];
|
|
1137
891
|
}, [id]);
|
|
1138
|
-
const resolveHide =
|
|
892
|
+
const resolveHide = React.useCallback((v) => {
|
|
1139
893
|
hideCallbacks[id]?.resolve(v);
|
|
1140
894
|
delete hideCallbacks[id];
|
|
1141
895
|
}, [id]);
|
|
1142
|
-
return
|
|
896
|
+
return React.useMemo(
|
|
1143
897
|
() => ({
|
|
1144
898
|
id,
|
|
1145
899
|
args: info?.args,
|
|
@@ -1158,47 +912,66 @@ function useModal(modal, args) {
|
|
|
1158
912
|
function defineModal(Comp) {
|
|
1159
913
|
return function Wrapped({ id, defaultVisible, keepMounted, ...props }) {
|
|
1160
914
|
const { args, show } = useModal(id);
|
|
1161
|
-
const modals =
|
|
915
|
+
const modals = React.useContext(ModalStateContext);
|
|
916
|
+
const d = React.useContext(ModalDispatchContext) ?? dispatch;
|
|
1162
917
|
const shouldMount = !!modals[id];
|
|
1163
|
-
|
|
918
|
+
React.useEffect(() => {
|
|
1164
919
|
if (defaultVisible) show();
|
|
1165
920
|
ALREADY_MOUNTED[id] = true;
|
|
1166
921
|
return () => {
|
|
1167
922
|
delete ALREADY_MOUNTED[id];
|
|
1168
923
|
};
|
|
1169
924
|
}, [id, show, defaultVisible]);
|
|
1170
|
-
|
|
1171
|
-
if (keepMounted) setFlags(id, { keepMounted: true });
|
|
1172
|
-
}, [id, keepMounted]);
|
|
925
|
+
React.useEffect(() => {
|
|
926
|
+
if (keepMounted) setFlags(d, id, { keepMounted: true });
|
|
927
|
+
}, [d, id, keepMounted]);
|
|
1173
928
|
const delayVisible = modals[id]?.delayVisible;
|
|
1174
|
-
|
|
929
|
+
React.useEffect(() => {
|
|
1175
930
|
if (delayVisible) show(args);
|
|
1176
931
|
}, [delayVisible, args, show]);
|
|
1177
932
|
if (!shouldMount) return null;
|
|
1178
|
-
return
|
|
933
|
+
return React.createElement(
|
|
1179
934
|
ModalIdContext.Provider,
|
|
1180
935
|
{ value: id },
|
|
1181
|
-
|
|
936
|
+
React.createElement(Comp, { ...props, ...args })
|
|
1182
937
|
);
|
|
1183
938
|
};
|
|
1184
939
|
}
|
|
1185
940
|
function ModalRoot() {
|
|
1186
|
-
const modals =
|
|
941
|
+
const modals = React.useContext(ModalStateContext);
|
|
1187
942
|
const toRender = Object.keys(modals).filter((id) => REGISTRY[id]).map((id) => ({ id, ...REGISTRY[id] }));
|
|
1188
|
-
return
|
|
943
|
+
return React.createElement(
|
|
1189
944
|
"div",
|
|
1190
945
|
{ "data-appfunnel-modal-root": "" },
|
|
1191
|
-
...toRender.map((t) =>
|
|
946
|
+
...toRender.map((t) => React.createElement(t.comp, { key: t.id, id: t.id, ...t.props }))
|
|
1192
947
|
);
|
|
1193
948
|
}
|
|
1194
949
|
function ModalRuntime({ children }) {
|
|
1195
|
-
const [state, localDispatch] =
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
950
|
+
const [state, localDispatch] = React.useReducer(modalReducer, initialState);
|
|
951
|
+
React.useEffect(() => {
|
|
952
|
+
runtimeStack.push(localDispatch);
|
|
953
|
+
if (runtimeStack.length > 1) {
|
|
954
|
+
try {
|
|
955
|
+
console.warn(
|
|
956
|
+
`[appfunnel] ${runtimeStack.length} modal runtimes are mounted \u2014 the imperative showModal()/hideModal() API binds to the most recent one. Use the useModal() hook inside each tree instead.`
|
|
957
|
+
);
|
|
958
|
+
} catch {
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
return () => {
|
|
962
|
+
const i = runtimeStack.indexOf(localDispatch);
|
|
963
|
+
if (i !== -1) runtimeStack.splice(i, 1);
|
|
964
|
+
};
|
|
965
|
+
}, []);
|
|
966
|
+
return React.createElement(
|
|
967
|
+
ModalDispatchContext.Provider,
|
|
968
|
+
{ value: localDispatch },
|
|
969
|
+
React.createElement(
|
|
970
|
+
ModalStateContext.Provider,
|
|
971
|
+
{ value: state },
|
|
972
|
+
children,
|
|
973
|
+
React.createElement(ModalRoot, null)
|
|
974
|
+
)
|
|
1202
975
|
);
|
|
1203
976
|
}
|
|
1204
977
|
|
|
@@ -1225,7 +998,7 @@ function OverlayShell({
|
|
|
1225
998
|
panel,
|
|
1226
999
|
children
|
|
1227
1000
|
}) {
|
|
1228
|
-
|
|
1001
|
+
React.useEffect(() => {
|
|
1229
1002
|
if (!open || typeof document === "undefined") return;
|
|
1230
1003
|
const onKey = (e) => {
|
|
1231
1004
|
if (e.key === "Escape") onClose();
|
|
@@ -1239,7 +1012,7 @@ function OverlayShell({
|
|
|
1239
1012
|
};
|
|
1240
1013
|
}, [open, onClose]);
|
|
1241
1014
|
if (!open || typeof document === "undefined") return null;
|
|
1242
|
-
const overlay =
|
|
1015
|
+
const overlay = React.createElement(
|
|
1243
1016
|
"div",
|
|
1244
1017
|
{
|
|
1245
1018
|
role: "dialog",
|
|
@@ -1248,19 +1021,19 @@ function OverlayShell({
|
|
|
1248
1021
|
"data-appfunnel-overlay": "",
|
|
1249
1022
|
style: { position: "fixed", inset: 0, zIndex: 1e3, display: "flex", ...container }
|
|
1250
1023
|
},
|
|
1251
|
-
|
|
1024
|
+
React.createElement("div", {
|
|
1252
1025
|
"data-appfunnel-overlay-backdrop": "",
|
|
1253
1026
|
className: backdropClassName,
|
|
1254
1027
|
onClick: dismissOnBackdrop ? onClose : void 0,
|
|
1255
1028
|
style: { position: "absolute", inset: 0, background: "rgba(0,0,0,0.5)" }
|
|
1256
1029
|
}),
|
|
1257
|
-
|
|
1030
|
+
React.createElement(
|
|
1258
1031
|
"div",
|
|
1259
1032
|
{ "data-appfunnel-overlay-panel": "", className, style: { position: "relative", background: "#fff", ...panel } },
|
|
1260
1033
|
children
|
|
1261
1034
|
)
|
|
1262
1035
|
);
|
|
1263
|
-
return
|
|
1036
|
+
return ReactDOM.createPortal(overlay, document.body);
|
|
1264
1037
|
}
|
|
1265
1038
|
var SHEET_LAYOUT = {
|
|
1266
1039
|
bottom: { container: { justifyContent: "flex-end", alignItems: "stretch" }, panel: { borderTopLeftRadius: 16, borderTopRightRadius: 16, padding: 16, maxHeight: "90vh", overflow: "auto" } },
|
|
@@ -1271,7 +1044,7 @@ var SHEET_LAYOUT = {
|
|
|
1271
1044
|
function Sheet(props) {
|
|
1272
1045
|
const control = useModalControl();
|
|
1273
1046
|
const layout = SHEET_LAYOUT[props.side ?? "bottom"];
|
|
1274
|
-
return
|
|
1047
|
+
return React.createElement(OverlayShell, {
|
|
1275
1048
|
...control,
|
|
1276
1049
|
className: props.className,
|
|
1277
1050
|
backdropClassName: props.backdropClassName,
|
|
@@ -1284,7 +1057,7 @@ function Sheet(props) {
|
|
|
1284
1057
|
}
|
|
1285
1058
|
function Modal(props) {
|
|
1286
1059
|
const control = useModalControl();
|
|
1287
|
-
return
|
|
1060
|
+
return React.createElement(OverlayShell, {
|
|
1288
1061
|
...control,
|
|
1289
1062
|
className: props.className,
|
|
1290
1063
|
backdropClassName: props.backdropClassName,
|
|
@@ -1297,144 +1070,74 @@ function Modal(props) {
|
|
|
1297
1070
|
}
|
|
1298
1071
|
|
|
1299
1072
|
// src/commerce/checkout.tsx
|
|
1300
|
-
var INLINE_SURFACES = /* @__PURE__ */ new Set([
|
|
1301
|
-
"express",
|
|
1302
|
-
"element",
|
|
1303
|
-
"embedded"
|
|
1304
|
-
]);
|
|
1305
|
-
function isInlineSurface(surface) {
|
|
1306
|
-
return INLINE_SURFACES.has(surface);
|
|
1307
|
-
}
|
|
1308
|
-
var ON = { purchase: true, wallets: true, offSession: "reliable" };
|
|
1309
|
-
var MANAGED = { purchase: true, wallets: true, offSession: "conditional" };
|
|
1310
|
-
var ALL_UPSELLS = ["subscription", "one-time", "upgrade"];
|
|
1311
|
-
var PROVIDER_PROFILES = {
|
|
1312
|
-
// PSP; you hold the PaymentMethod and fire your own off-session PaymentIntent on
|
|
1313
|
-
// the Elements surfaces (reliable). **Managed** Checkout (`embedded`/`redirect`)
|
|
1314
|
-
// upsells too, but as a direct charge against Stripe's vaulted card → conditional.
|
|
1315
|
-
// No provider "popup" surface.
|
|
1316
|
-
stripe: {
|
|
1317
|
-
isMoR: false,
|
|
1318
|
-
offSessionUpsells: ALL_UPSELLS,
|
|
1319
|
-
tokenModel: "merchant",
|
|
1320
|
-
orchestrator: false,
|
|
1321
|
-
surfaces: { express: ON, element: ON, sheet: ON, embedded: MANAGED, redirect: MANAGED }
|
|
1322
|
-
},
|
|
1323
|
-
// Merchant-of-Record; card entry is always Paddle's frame → no own element/sheet/
|
|
1324
|
-
// express. Off-session via subscription one-time charge / collection_mode, but
|
|
1325
|
-
// **no 2nd concurrent subscription** (upgrade + one-time only), provider-initiated.
|
|
1326
|
-
paddle: {
|
|
1327
|
-
isMoR: true,
|
|
1328
|
-
offSessionUpsells: ["one-time", "upgrade"],
|
|
1329
|
-
tokenModel: "provider",
|
|
1330
|
-
orchestrator: false,
|
|
1331
|
-
surfaces: { embedded: ON, popup: ON, redirect: ON }
|
|
1332
|
-
},
|
|
1333
|
-
// Merchant-of-Record; iframe-only (no raw card field). Off-session works
|
|
1334
|
-
// (provider-initiated, async via webhooks). `sheet` = our chrome hosting their embed.
|
|
1335
|
-
whop: {
|
|
1336
|
-
isMoR: true,
|
|
1337
|
-
offSessionUpsells: ALL_UPSELLS,
|
|
1338
|
-
tokenModel: "provider",
|
|
1339
|
-
orchestrator: false,
|
|
1340
|
-
surfaces: { embedded: ON, redirect: ON, sheet: ON }
|
|
1341
|
-
},
|
|
1342
|
-
// Pure orchestrator (PSP-side); Headless renders express/element/sheet/embedded.
|
|
1343
|
-
// No hosted redirect page, no popup checkout. Off-session is PSP-conditional.
|
|
1344
|
-
primer: {
|
|
1345
|
-
isMoR: false,
|
|
1346
|
-
offSessionUpsells: ALL_UPSELLS,
|
|
1347
|
-
tokenModel: "merchant",
|
|
1348
|
-
orchestrator: true,
|
|
1349
|
-
surfaces: { express: ON, element: ON, sheet: ON, embedded: ON }
|
|
1350
|
-
},
|
|
1351
|
-
// PSP **and** orchestrator (own acquiring + connectors routing across Stripe/Adyen/
|
|
1352
|
-
// PayPal). One Payment Form (element/sheet/embedded) + hosted page + wallet button.
|
|
1353
|
-
// Strong native off-session (Recurring API). No popup.
|
|
1354
|
-
solidgate: {
|
|
1355
|
-
isMoR: false,
|
|
1356
|
-
offSessionUpsells: ALL_UPSELLS,
|
|
1357
|
-
tokenModel: "merchant",
|
|
1358
|
-
orchestrator: true,
|
|
1359
|
-
surfaces: { express: ON, element: ON, sheet: ON, embedded: ON, redirect: ON }
|
|
1360
|
-
}
|
|
1361
|
-
};
|
|
1362
|
-
function surfacesFor(provider) {
|
|
1363
|
-
return Object.keys(PROVIDER_PROFILES[provider]?.surfaces ?? {});
|
|
1364
|
-
}
|
|
1365
|
-
function isMerchantOfRecord(provider) {
|
|
1366
|
-
return PROVIDER_PROFILES[provider]?.isMoR ?? false;
|
|
1367
|
-
}
|
|
1368
|
-
function isOrchestrator(provider) {
|
|
1369
|
-
return PROVIDER_PROFILES[provider]?.orchestrator ?? false;
|
|
1370
|
-
}
|
|
1371
|
-
function validateCheckout(provider, surface) {
|
|
1372
|
-
const cap = PROVIDER_PROFILES[provider]?.surfaces[surface];
|
|
1373
|
-
if (!cap) return { ok: false, reason: `${provider} has no '${surface}' surface` };
|
|
1374
|
-
return cap.purchase ? { ok: true } : { ok: false, reason: `'${surface}' can't take a purchase on ${provider}` };
|
|
1375
|
-
}
|
|
1376
|
-
function validateUpsell(provider, paywallSurface, kind = "subscription") {
|
|
1377
|
-
const profile = PROVIDER_PROFILES[provider];
|
|
1378
|
-
if (!profile) return { ok: false, reason: `unknown provider '${provider}'` };
|
|
1379
|
-
if (!profile.offSessionUpsells.includes(kind)) {
|
|
1380
|
-
const can = profile.offSessionUpsells.length ? ` (it supports: ${profile.offSessionUpsells.join(", ")})` : "";
|
|
1381
|
-
return { ok: false, reason: `${provider} can't charge a '${kind}' upsell off-session${can}` };
|
|
1382
|
-
}
|
|
1383
|
-
const cap = profile.surfaces[paywallSurface];
|
|
1384
|
-
if (!cap) return { ok: false, reason: `${provider} has no '${paywallSurface}' surface to upsell after` };
|
|
1385
|
-
if (cap.offSession === "none") {
|
|
1386
|
-
return { ok: false, reason: `a purchase on '${paywallSurface}' retains no chargeable method for an upsell` };
|
|
1387
|
-
}
|
|
1388
|
-
if (cap.offSession === "conditional") {
|
|
1389
|
-
return { ok: true, note: `off-session upsell after ${provider} '${paywallSurface}' (managed checkout) may decline \u2014 prefer element/sheet/express` };
|
|
1390
|
-
}
|
|
1391
|
-
return { ok: true };
|
|
1392
|
-
}
|
|
1393
|
-
function checkoutError(category, message, extra = {}) {
|
|
1394
|
-
const retryable = extra.retryable ?? (category === "authentication_required" || category === "requires_payment_method" || category === "processing_error");
|
|
1395
|
-
return { category, message, declineCode: extra.declineCode, retryable };
|
|
1396
|
-
}
|
|
1397
1073
|
function createMockDriver(provider = "stripe", options = {}) {
|
|
1398
1074
|
const success = options.result ?? { ok: true, amountMinor: 0, currency: "USD" };
|
|
1399
|
-
const offError = typeof options.failOffSession === "object" ? options.failOffSession : checkoutError("authentication_required", "off-session charge declined (mock)");
|
|
1075
|
+
const offError = typeof options.failOffSession === "object" ? options.failOffSession : chunkLJYLGLFS_cjs.checkoutError("authentication_required", "off-session charge declined (mock)");
|
|
1400
1076
|
return {
|
|
1401
1077
|
provider,
|
|
1402
1078
|
start: (req) => {
|
|
1403
1079
|
if (options.failOffSession && !req.surface) return Promise.resolve({ ok: false, error: offError });
|
|
1404
1080
|
return Promise.resolve(success);
|
|
1405
1081
|
},
|
|
1406
|
-
renderInline: (req, cb) =>
|
|
1082
|
+
renderInline: (req, cb) => React.createElement(
|
|
1407
1083
|
"button",
|
|
1408
1084
|
{
|
|
1409
1085
|
type: "button",
|
|
1410
1086
|
"data-mock-surface": req.surface,
|
|
1411
|
-
onClick: () =>
|
|
1087
|
+
onClick: () => {
|
|
1088
|
+
cb.onStart?.();
|
|
1089
|
+
if (success.ok) cb.onSuccess(success);
|
|
1090
|
+
else cb.onError(success.error ?? chunkLJYLGLFS_cjs.checkoutError("processing_error", "failed (mock)"));
|
|
1091
|
+
}
|
|
1412
1092
|
},
|
|
1413
1093
|
`Pay (mock ${req.surface})`
|
|
1414
|
-
)
|
|
1094
|
+
),
|
|
1095
|
+
resume: () => Promise.resolve(success)
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
function driverWithEmail(driver, getEmail) {
|
|
1099
|
+
const enrich = (req) => req.email !== void 0 ? req : { ...req, email: getEmail() };
|
|
1100
|
+
return {
|
|
1101
|
+
...driver,
|
|
1102
|
+
start: (req) => driver.start(enrich(req)),
|
|
1103
|
+
renderInline: driver.renderInline ? (req, cb) => driver.renderInline(enrich(req), cb) : void 0
|
|
1415
1104
|
};
|
|
1416
1105
|
}
|
|
1417
|
-
|
|
1106
|
+
function driverWithCatalog(driver, catalog) {
|
|
1107
|
+
const enrich = (req) => req.catalogKey !== void 0 ? req : { ...req, catalogKey: catalog.get(req.product)?.catalogKey };
|
|
1108
|
+
return {
|
|
1109
|
+
...driver,
|
|
1110
|
+
start: (req) => driver.start(enrich(req)),
|
|
1111
|
+
renderInline: driver.renderInline ? (req, cb) => driver.renderInline(enrich(req), cb) : void 0
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
var DriverContext = React.createContext(null);
|
|
1418
1115
|
function CheckoutDriverProvider({
|
|
1419
1116
|
driver,
|
|
1420
1117
|
children
|
|
1421
1118
|
}) {
|
|
1422
|
-
return
|
|
1119
|
+
return React.createElement(DriverContext.Provider, { value: driver }, children);
|
|
1423
1120
|
}
|
|
1424
1121
|
function useDriver() {
|
|
1425
|
-
return
|
|
1122
|
+
return React.useContext(DriverContext) ?? FALLBACK_DRIVER;
|
|
1426
1123
|
}
|
|
1427
1124
|
var FALLBACK_DRIVER = createMockDriver();
|
|
1428
1125
|
function useCheckout(opts = {}) {
|
|
1429
1126
|
const driver = useDriver();
|
|
1430
1127
|
const tracker = useTrackerRef();
|
|
1431
1128
|
const nav = useNavigation();
|
|
1432
|
-
const [status, setStatus] =
|
|
1433
|
-
const [error, setError] =
|
|
1129
|
+
const [status, setStatus] = React.useState("idle");
|
|
1130
|
+
const [error, setError] = React.useState(null);
|
|
1434
1131
|
const intent = opts.intent ?? "purchase";
|
|
1435
1132
|
const kind = opts.kind;
|
|
1436
1133
|
const advance = opts.advanceOnSuccess ?? true;
|
|
1437
|
-
const
|
|
1134
|
+
const recovering = React.useRef(false);
|
|
1135
|
+
const failRef = React.useRef(() => {
|
|
1136
|
+
});
|
|
1137
|
+
const attemptRef = React.useRef(
|
|
1138
|
+
async () => ({ ok: false })
|
|
1139
|
+
);
|
|
1140
|
+
const succeed = React.useCallback(
|
|
1438
1141
|
(result) => {
|
|
1439
1142
|
setStatus("success");
|
|
1440
1143
|
tracker.track("purchase.complete", {
|
|
@@ -1448,21 +1151,9 @@ function useCheckout(opts = {}) {
|
|
|
1448
1151
|
},
|
|
1449
1152
|
[tracker, nav, advance, opts]
|
|
1450
1153
|
);
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
setError(err);
|
|
1455
|
-
tracker.track("checkout.failed", {
|
|
1456
|
-
category: err.category,
|
|
1457
|
-
declineCode: err.declineCode,
|
|
1458
|
-
productId: product,
|
|
1459
|
-
intent
|
|
1460
|
-
});
|
|
1461
|
-
opts.onError?.(err);
|
|
1462
|
-
},
|
|
1463
|
-
[tracker, intent, opts]
|
|
1464
|
-
);
|
|
1465
|
-
const begin = react.useCallback(
|
|
1154
|
+
const succeedRef = React.useRef(succeed);
|
|
1155
|
+
succeedRef.current = succeed;
|
|
1156
|
+
const begin = React.useCallback(
|
|
1466
1157
|
(product, surface) => {
|
|
1467
1158
|
setStatus("loading");
|
|
1468
1159
|
setError(null);
|
|
@@ -1470,64 +1161,157 @@ function useCheckout(opts = {}) {
|
|
|
1470
1161
|
},
|
|
1471
1162
|
[tracker]
|
|
1472
1163
|
);
|
|
1473
|
-
const paymentAdded =
|
|
1474
|
-
const
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1164
|
+
const paymentAdded = React.useCallback(() => tracker.track("checkout.payment_added", {}), [tracker]);
|
|
1165
|
+
const hostInSheet = (surface) => surface === "sheet" || chunkLJYLGLFS_cjs.isInlineSurface(surface) && !!chunkLJYLGLFS_cjs.PROVIDER_PROFILES[driver.provider]?.surfaces.sheet;
|
|
1166
|
+
const startRecovery = (product, surface) => {
|
|
1167
|
+
recovering.current = true;
|
|
1168
|
+
if (hostInSheet(surface)) {
|
|
1169
|
+
begin(product, "sheet");
|
|
1170
|
+
void showModal(CheckoutSheet, {
|
|
1171
|
+
product,
|
|
1172
|
+
surface: "sheet",
|
|
1173
|
+
intent,
|
|
1174
|
+
kind,
|
|
1175
|
+
onSuccess: (r) => succeedRef.current(r),
|
|
1176
|
+
onError: (e) => failRef.current(e, product),
|
|
1177
|
+
onPaymentAdded: () => paymentAdded()
|
|
1178
|
+
});
|
|
1179
|
+
} else {
|
|
1180
|
+
void attemptRef.current(product, surface);
|
|
1181
|
+
}
|
|
1182
|
+
};
|
|
1183
|
+
failRef.current = (err, product) => {
|
|
1184
|
+
setStatus(err.category === "authentication_required" ? "requires_action" : "error");
|
|
1185
|
+
setError(err);
|
|
1186
|
+
tracker.track("checkout.failed", {
|
|
1187
|
+
category: err.category,
|
|
1188
|
+
declineCode: err.declineCode,
|
|
1189
|
+
productId: product,
|
|
1190
|
+
intent
|
|
1191
|
+
});
|
|
1192
|
+
opts.onError?.(err);
|
|
1193
|
+
if (err.category === "canceled" && !opts.onFailed?.canceled) return;
|
|
1194
|
+
if (product && !recovering.current && opts.recoverySurface && err.category !== "canceled") {
|
|
1195
|
+
startRecovery(product, opts.recoverySurface);
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
let route = opts.onFailed?.[err.category] ?? (err.category === "canceled" ? void 0 : opts.onFailed?.default);
|
|
1199
|
+
if (route && typeof route === "object" && "fallback" in route && recovering.current) {
|
|
1200
|
+
const dflt = opts.onFailed?.default;
|
|
1201
|
+
route = dflt && dflt !== route && !(typeof dflt === "object" && "fallback" in dflt) ? dflt : void 0;
|
|
1202
|
+
}
|
|
1203
|
+
if (!route) return;
|
|
1204
|
+
if (typeof route === "function") route(err);
|
|
1205
|
+
else if ("go" in route) nav.go(route.go);
|
|
1206
|
+
else if ("modal" in route) {
|
|
1207
|
+
const props = {
|
|
1208
|
+
error: err,
|
|
1209
|
+
product,
|
|
1210
|
+
go: (pageKey) => nav.go(pageKey),
|
|
1211
|
+
retry: (surface) => {
|
|
1212
|
+
if (!product) return;
|
|
1213
|
+
recovering.current = true;
|
|
1214
|
+
if (!surface) {
|
|
1215
|
+
if (intent === "upsell") void attemptRef.current(product);
|
|
1216
|
+
else startRecovery(product, chunkLJYLGLFS_cjs.PROVIDER_PROFILES[driver.provider]?.surfaces.sheet ? "sheet" : "popup");
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
startRecovery(product, surface);
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
void showModal(route.modal, props);
|
|
1223
|
+
} else if ("fallback" in route) {
|
|
1224
|
+
if (product && !recovering.current) startRecovery(product, route.fallback);
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
attemptRef.current = async (product, surface) => {
|
|
1228
|
+
begin(product, surface);
|
|
1229
|
+
try {
|
|
1230
|
+
const result = await driver.start({ product, intent, surface, kind });
|
|
1231
|
+
if (result.ok) succeedRef.current(result);
|
|
1232
|
+
else failRef.current(result.error ?? chunkLJYLGLFS_cjs.checkoutError("unknown", "Checkout failed"), product);
|
|
1233
|
+
return result;
|
|
1234
|
+
} catch (e) {
|
|
1235
|
+
const err = chunkLJYLGLFS_cjs.checkoutError("processing_error", e instanceof Error ? e.message : "Checkout failed");
|
|
1236
|
+
failRef.current(err, product);
|
|
1237
|
+
return { ok: false, error: err };
|
|
1238
|
+
}
|
|
1239
|
+
};
|
|
1240
|
+
const open = React.useCallback(async (product, surface) => {
|
|
1241
|
+
recovering.current = false;
|
|
1242
|
+
return attemptRef.current(product, surface);
|
|
1243
|
+
}, []);
|
|
1244
|
+
const callbacksFor = React.useCallback(
|
|
1491
1245
|
(product, surface) => ({
|
|
1492
|
-
onStart: () =>
|
|
1493
|
-
|
|
1494
|
-
|
|
1246
|
+
onStart: () => {
|
|
1247
|
+
recovering.current = false;
|
|
1248
|
+
begin(product, surface);
|
|
1249
|
+
},
|
|
1250
|
+
onSuccess: (result) => succeedRef.current(result),
|
|
1251
|
+
onError: (err) => failRef.current(err, product),
|
|
1495
1252
|
onPaymentAdded: () => paymentAdded()
|
|
1496
1253
|
}),
|
|
1497
|
-
[begin,
|
|
1254
|
+
[begin, paymentAdded]
|
|
1498
1255
|
);
|
|
1499
|
-
const reset =
|
|
1256
|
+
const reset = React.useCallback(() => {
|
|
1257
|
+
recovering.current = false;
|
|
1500
1258
|
setStatus("idle");
|
|
1501
1259
|
setError(null);
|
|
1502
1260
|
}, []);
|
|
1503
1261
|
return { open, status, error, isLoading: status === "loading", reset, callbacksFor };
|
|
1504
1262
|
}
|
|
1505
|
-
var CheckoutSheet = defineModal(({ product, surface, intent, onSuccess, onError }) => {
|
|
1263
|
+
var CheckoutSheet = defineModal(({ product, surface, intent, kind, onSuccess, onError, onPaymentAdded }) => {
|
|
1506
1264
|
const driver = useDriver();
|
|
1507
1265
|
const modal = useModal();
|
|
1266
|
+
const resolved = React.useRef(false);
|
|
1267
|
+
const onErrorRef = React.useRef(onError);
|
|
1268
|
+
onErrorRef.current = onError;
|
|
1269
|
+
const hostable = !!driver.renderInline;
|
|
1270
|
+
React.useEffect(() => {
|
|
1271
|
+
if (!hostable) {
|
|
1272
|
+
resolved.current = true;
|
|
1273
|
+
onErrorRef.current(
|
|
1274
|
+
chunkLJYLGLFS_cjs.checkoutError("processing_error", "This checkout driver has no inline surface to host in the sheet")
|
|
1275
|
+
);
|
|
1276
|
+
void modal.hide();
|
|
1277
|
+
modal.remove();
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
return () => {
|
|
1281
|
+
if (!resolved.current) {
|
|
1282
|
+
onErrorRef.current(chunkLJYLGLFS_cjs.checkoutError("canceled", "Checkout was dismissed before completing"));
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
}, []);
|
|
1508
1286
|
if (!driver.renderInline) return null;
|
|
1509
|
-
|
|
1287
|
+
const close = () => {
|
|
1288
|
+
resolved.current = true;
|
|
1289
|
+
void modal.hide();
|
|
1290
|
+
modal.remove();
|
|
1291
|
+
};
|
|
1292
|
+
return React.createElement(Sheet, {
|
|
1510
1293
|
children: driver.renderInline(
|
|
1511
|
-
{ product, intent, surface },
|
|
1294
|
+
{ product, intent, surface, kind },
|
|
1512
1295
|
{
|
|
1513
1296
|
onSuccess: (r) => {
|
|
1514
|
-
|
|
1297
|
+
close();
|
|
1515
1298
|
onSuccess(r);
|
|
1516
1299
|
},
|
|
1517
1300
|
onError: (e) => {
|
|
1518
|
-
|
|
1301
|
+
close();
|
|
1519
1302
|
onError(e);
|
|
1520
|
-
}
|
|
1303
|
+
},
|
|
1304
|
+
onPaymentAdded
|
|
1521
1305
|
}
|
|
1522
1306
|
)
|
|
1523
1307
|
});
|
|
1524
1308
|
});
|
|
1525
1309
|
function trigger(onClick, { asChild, children, className, disabled }) {
|
|
1526
|
-
if (asChild &&
|
|
1310
|
+
if (asChild && React.isValidElement(children)) {
|
|
1527
1311
|
const child = children;
|
|
1528
|
-
return
|
|
1312
|
+
return React.cloneElement(child, { onClick });
|
|
1529
1313
|
}
|
|
1530
|
-
return
|
|
1314
|
+
return React.createElement("button", { type: "button", className, disabled, onClick }, children ?? "Continue");
|
|
1531
1315
|
}
|
|
1532
1316
|
function Checkout({
|
|
1533
1317
|
product,
|
|
@@ -1540,8 +1324,8 @@ function Checkout({
|
|
|
1540
1324
|
const driver = useDriver();
|
|
1541
1325
|
const checkout = useCheckout(options);
|
|
1542
1326
|
const intent = options.intent ?? "purchase";
|
|
1543
|
-
if (isInlineSurface(surface)) {
|
|
1544
|
-
return driver.renderInline ?
|
|
1327
|
+
if (chunkLJYLGLFS_cjs.isInlineSurface(surface)) {
|
|
1328
|
+
return driver.renderInline ? React.createElement(
|
|
1545
1329
|
"div",
|
|
1546
1330
|
{ key: product, className },
|
|
1547
1331
|
driver.renderInline({ product, intent, surface }, checkout.callbacksFor(product, surface))
|
|
@@ -1551,7 +1335,15 @@ function Checkout({
|
|
|
1551
1335
|
const cb = checkout.callbacksFor(product, surface);
|
|
1552
1336
|
const open = () => {
|
|
1553
1337
|
cb.onStart();
|
|
1554
|
-
showModal(CheckoutSheet, {
|
|
1338
|
+
showModal(CheckoutSheet, {
|
|
1339
|
+
product,
|
|
1340
|
+
surface,
|
|
1341
|
+
intent,
|
|
1342
|
+
kind: options.kind,
|
|
1343
|
+
onSuccess: cb.onSuccess,
|
|
1344
|
+
onError: cb.onError,
|
|
1345
|
+
onPaymentAdded: cb.onPaymentAdded
|
|
1346
|
+
});
|
|
1555
1347
|
};
|
|
1556
1348
|
return trigger(open, { asChild, children, className, disabled: checkout.isLoading });
|
|
1557
1349
|
}
|
|
@@ -1563,31 +1355,1129 @@ function Checkout({
|
|
|
1563
1355
|
});
|
|
1564
1356
|
}
|
|
1565
1357
|
function Upsell({ product, fallback, asChild, children, className, ...options }) {
|
|
1566
|
-
const checkout = useCheckout({
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
cb.onStart();
|
|
1573
|
-
showModal(CheckoutSheet, { product, surface: "sheet", intent: "upsell", onSuccess: cb.onSuccess, onError: cb.onError });
|
|
1574
|
-
} else {
|
|
1575
|
-
await checkout.open(product, fallback);
|
|
1576
|
-
}
|
|
1577
|
-
};
|
|
1578
|
-
return trigger(start, {
|
|
1358
|
+
const checkout = useCheckout({
|
|
1359
|
+
...options,
|
|
1360
|
+
intent: "upsell",
|
|
1361
|
+
recoverySurface: fallback ?? options.recoverySurface
|
|
1362
|
+
});
|
|
1363
|
+
return trigger(() => void checkout.open(product), {
|
|
1579
1364
|
asChild,
|
|
1580
1365
|
children: children ?? "Add to my plan",
|
|
1581
1366
|
className,
|
|
1582
1367
|
disabled: checkout.isLoading
|
|
1583
1368
|
});
|
|
1584
1369
|
}
|
|
1370
|
+
var consumedResumes = /* @__PURE__ */ new Set();
|
|
1371
|
+
function CheckoutResume(options = {}) {
|
|
1372
|
+
const driver = useDriver();
|
|
1373
|
+
const checkout = useCheckout(options);
|
|
1374
|
+
const callbacksRef = React.useRef(checkout.callbacksFor);
|
|
1375
|
+
callbacksRef.current = checkout.callbacksFor;
|
|
1376
|
+
React.useEffect(() => {
|
|
1377
|
+
if (typeof window === "undefined" || !driver.resume) return;
|
|
1378
|
+
const url = new URL(window.location.href);
|
|
1379
|
+
const correlationId = url.searchParams.get("af_checkout");
|
|
1380
|
+
if (!correlationId || consumedResumes.has(correlationId)) return;
|
|
1381
|
+
consumedResumes.add(correlationId);
|
|
1382
|
+
void driver.resume(correlationId).then((result) => {
|
|
1383
|
+
const cb = callbacksRef.current();
|
|
1384
|
+
if (result.ok) {
|
|
1385
|
+
url.searchParams.delete("af_checkout");
|
|
1386
|
+
window.history.replaceState(window.history.state, "", url.toString());
|
|
1387
|
+
cb.onSuccess(result);
|
|
1388
|
+
} else {
|
|
1389
|
+
cb.onError(result.error ?? chunkLJYLGLFS_cjs.checkoutError("unknown", "The checkout could not be verified"));
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
}, []);
|
|
1393
|
+
return null;
|
|
1394
|
+
}
|
|
1395
|
+
function __insertCSS(code) {
|
|
1396
|
+
if (typeof document == "undefined") return;
|
|
1397
|
+
let head = document.head || document.getElementsByTagName("head")[0];
|
|
1398
|
+
let style = document.createElement("style");
|
|
1399
|
+
style.type = "text/css";
|
|
1400
|
+
head.appendChild(style);
|
|
1401
|
+
style.styleSheet ? style.styleSheet.cssText = code : style.appendChild(document.createTextNode(code));
|
|
1402
|
+
}
|
|
1403
|
+
var getAsset = (type) => {
|
|
1404
|
+
switch (type) {
|
|
1405
|
+
case "success":
|
|
1406
|
+
return SuccessIcon;
|
|
1407
|
+
case "info":
|
|
1408
|
+
return InfoIcon;
|
|
1409
|
+
case "warning":
|
|
1410
|
+
return WarningIcon;
|
|
1411
|
+
case "error":
|
|
1412
|
+
return ErrorIcon;
|
|
1413
|
+
default:
|
|
1414
|
+
return null;
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
var bars = Array(12).fill(0);
|
|
1418
|
+
var Loader = ({ visible, className }) => {
|
|
1419
|
+
return /* @__PURE__ */ React__default.default.createElement("div", {
|
|
1420
|
+
className: [
|
|
1421
|
+
"sonner-loading-wrapper",
|
|
1422
|
+
className
|
|
1423
|
+
].filter(Boolean).join(" "),
|
|
1424
|
+
"data-visible": visible
|
|
1425
|
+
}, /* @__PURE__ */ React__default.default.createElement("div", {
|
|
1426
|
+
className: "sonner-spinner"
|
|
1427
|
+
}, bars.map((_, i) => /* @__PURE__ */ React__default.default.createElement("div", {
|
|
1428
|
+
className: "sonner-loading-bar",
|
|
1429
|
+
key: `spinner-bar-${i}`
|
|
1430
|
+
}))));
|
|
1431
|
+
};
|
|
1432
|
+
var SuccessIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1433
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1434
|
+
viewBox: "0 0 20 20",
|
|
1435
|
+
fill: "currentColor",
|
|
1436
|
+
height: "20",
|
|
1437
|
+
width: "20"
|
|
1438
|
+
}, /* @__PURE__ */ React__default.default.createElement("path", {
|
|
1439
|
+
fillRule: "evenodd",
|
|
1440
|
+
d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",
|
|
1441
|
+
clipRule: "evenodd"
|
|
1442
|
+
}));
|
|
1443
|
+
var WarningIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1444
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1445
|
+
viewBox: "0 0 24 24",
|
|
1446
|
+
fill: "currentColor",
|
|
1447
|
+
height: "20",
|
|
1448
|
+
width: "20"
|
|
1449
|
+
}, /* @__PURE__ */ React__default.default.createElement("path", {
|
|
1450
|
+
fillRule: "evenodd",
|
|
1451
|
+
d: "M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z",
|
|
1452
|
+
clipRule: "evenodd"
|
|
1453
|
+
}));
|
|
1454
|
+
var InfoIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1455
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1456
|
+
viewBox: "0 0 20 20",
|
|
1457
|
+
fill: "currentColor",
|
|
1458
|
+
height: "20",
|
|
1459
|
+
width: "20"
|
|
1460
|
+
}, /* @__PURE__ */ React__default.default.createElement("path", {
|
|
1461
|
+
fillRule: "evenodd",
|
|
1462
|
+
d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z",
|
|
1463
|
+
clipRule: "evenodd"
|
|
1464
|
+
}));
|
|
1465
|
+
var ErrorIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1466
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1467
|
+
viewBox: "0 0 20 20",
|
|
1468
|
+
fill: "currentColor",
|
|
1469
|
+
height: "20",
|
|
1470
|
+
width: "20"
|
|
1471
|
+
}, /* @__PURE__ */ React__default.default.createElement("path", {
|
|
1472
|
+
fillRule: "evenodd",
|
|
1473
|
+
d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",
|
|
1474
|
+
clipRule: "evenodd"
|
|
1475
|
+
}));
|
|
1476
|
+
var CloseIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1477
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1478
|
+
width: "12",
|
|
1479
|
+
height: "12",
|
|
1480
|
+
viewBox: "0 0 24 24",
|
|
1481
|
+
fill: "none",
|
|
1482
|
+
stroke: "currentColor",
|
|
1483
|
+
strokeWidth: "1.5",
|
|
1484
|
+
strokeLinecap: "round",
|
|
1485
|
+
strokeLinejoin: "round"
|
|
1486
|
+
}, /* @__PURE__ */ React__default.default.createElement("line", {
|
|
1487
|
+
x1: "18",
|
|
1488
|
+
y1: "6",
|
|
1489
|
+
x2: "6",
|
|
1490
|
+
y2: "18"
|
|
1491
|
+
}), /* @__PURE__ */ React__default.default.createElement("line", {
|
|
1492
|
+
x1: "6",
|
|
1493
|
+
y1: "6",
|
|
1494
|
+
x2: "18",
|
|
1495
|
+
y2: "18"
|
|
1496
|
+
}));
|
|
1497
|
+
var useIsDocumentHidden = () => {
|
|
1498
|
+
const [isDocumentHidden, setIsDocumentHidden] = React__default.default.useState(document.hidden);
|
|
1499
|
+
React__default.default.useEffect(() => {
|
|
1500
|
+
const callback = () => {
|
|
1501
|
+
setIsDocumentHidden(document.hidden);
|
|
1502
|
+
};
|
|
1503
|
+
document.addEventListener("visibilitychange", callback);
|
|
1504
|
+
return () => window.removeEventListener("visibilitychange", callback);
|
|
1505
|
+
}, []);
|
|
1506
|
+
return isDocumentHidden;
|
|
1507
|
+
};
|
|
1508
|
+
var toastsCounter = 1;
|
|
1509
|
+
var Observer = class {
|
|
1510
|
+
constructor() {
|
|
1511
|
+
this.subscribe = (subscriber) => {
|
|
1512
|
+
this.subscribers.push(subscriber);
|
|
1513
|
+
return () => {
|
|
1514
|
+
const index = this.subscribers.indexOf(subscriber);
|
|
1515
|
+
this.subscribers.splice(index, 1);
|
|
1516
|
+
};
|
|
1517
|
+
};
|
|
1518
|
+
this.publish = (data) => {
|
|
1519
|
+
this.subscribers.forEach((subscriber) => subscriber(data));
|
|
1520
|
+
};
|
|
1521
|
+
this.addToast = (data) => {
|
|
1522
|
+
this.publish(data);
|
|
1523
|
+
this.toasts = [
|
|
1524
|
+
...this.toasts,
|
|
1525
|
+
data
|
|
1526
|
+
];
|
|
1527
|
+
};
|
|
1528
|
+
this.create = (data) => {
|
|
1529
|
+
var _data_id;
|
|
1530
|
+
const { message, ...rest } = data;
|
|
1531
|
+
const id = typeof (data == null ? void 0 : data.id) === "number" || ((_data_id = data.id) == null ? void 0 : _data_id.length) > 0 ? data.id : toastsCounter++;
|
|
1532
|
+
const alreadyExists = this.toasts.find((toast2) => {
|
|
1533
|
+
return toast2.id === id;
|
|
1534
|
+
});
|
|
1535
|
+
const dismissible = data.dismissible === void 0 ? true : data.dismissible;
|
|
1536
|
+
if (this.dismissedToasts.has(id)) {
|
|
1537
|
+
this.dismissedToasts.delete(id);
|
|
1538
|
+
}
|
|
1539
|
+
if (alreadyExists) {
|
|
1540
|
+
this.toasts = this.toasts.map((toast2) => {
|
|
1541
|
+
if (toast2.id === id) {
|
|
1542
|
+
this.publish({
|
|
1543
|
+
...toast2,
|
|
1544
|
+
...data,
|
|
1545
|
+
id,
|
|
1546
|
+
title: message
|
|
1547
|
+
});
|
|
1548
|
+
return {
|
|
1549
|
+
...toast2,
|
|
1550
|
+
...data,
|
|
1551
|
+
id,
|
|
1552
|
+
dismissible,
|
|
1553
|
+
title: message
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
return toast2;
|
|
1557
|
+
});
|
|
1558
|
+
} else {
|
|
1559
|
+
this.addToast({
|
|
1560
|
+
title: message,
|
|
1561
|
+
...rest,
|
|
1562
|
+
dismissible,
|
|
1563
|
+
id
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
return id;
|
|
1567
|
+
};
|
|
1568
|
+
this.dismiss = (id) => {
|
|
1569
|
+
if (id) {
|
|
1570
|
+
this.dismissedToasts.add(id);
|
|
1571
|
+
requestAnimationFrame(() => this.subscribers.forEach((subscriber) => subscriber({
|
|
1572
|
+
id,
|
|
1573
|
+
dismiss: true
|
|
1574
|
+
})));
|
|
1575
|
+
} else {
|
|
1576
|
+
this.toasts.forEach((toast2) => {
|
|
1577
|
+
this.subscribers.forEach((subscriber) => subscriber({
|
|
1578
|
+
id: toast2.id,
|
|
1579
|
+
dismiss: true
|
|
1580
|
+
}));
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
return id;
|
|
1584
|
+
};
|
|
1585
|
+
this.message = (message, data) => {
|
|
1586
|
+
return this.create({
|
|
1587
|
+
...data,
|
|
1588
|
+
message
|
|
1589
|
+
});
|
|
1590
|
+
};
|
|
1591
|
+
this.error = (message, data) => {
|
|
1592
|
+
return this.create({
|
|
1593
|
+
...data,
|
|
1594
|
+
message,
|
|
1595
|
+
type: "error"
|
|
1596
|
+
});
|
|
1597
|
+
};
|
|
1598
|
+
this.success = (message, data) => {
|
|
1599
|
+
return this.create({
|
|
1600
|
+
...data,
|
|
1601
|
+
type: "success",
|
|
1602
|
+
message
|
|
1603
|
+
});
|
|
1604
|
+
};
|
|
1605
|
+
this.info = (message, data) => {
|
|
1606
|
+
return this.create({
|
|
1607
|
+
...data,
|
|
1608
|
+
type: "info",
|
|
1609
|
+
message
|
|
1610
|
+
});
|
|
1611
|
+
};
|
|
1612
|
+
this.warning = (message, data) => {
|
|
1613
|
+
return this.create({
|
|
1614
|
+
...data,
|
|
1615
|
+
type: "warning",
|
|
1616
|
+
message
|
|
1617
|
+
});
|
|
1618
|
+
};
|
|
1619
|
+
this.loading = (message, data) => {
|
|
1620
|
+
return this.create({
|
|
1621
|
+
...data,
|
|
1622
|
+
type: "loading",
|
|
1623
|
+
message
|
|
1624
|
+
});
|
|
1625
|
+
};
|
|
1626
|
+
this.promise = (promise, data) => {
|
|
1627
|
+
if (!data) {
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
let id = void 0;
|
|
1631
|
+
if (data.loading !== void 0) {
|
|
1632
|
+
id = this.create({
|
|
1633
|
+
...data,
|
|
1634
|
+
promise,
|
|
1635
|
+
type: "loading",
|
|
1636
|
+
message: data.loading,
|
|
1637
|
+
description: typeof data.description !== "function" ? data.description : void 0
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
const p = Promise.resolve(promise instanceof Function ? promise() : promise);
|
|
1641
|
+
let shouldDismiss = id !== void 0;
|
|
1642
|
+
let result;
|
|
1643
|
+
const originalPromise = p.then(async (response) => {
|
|
1644
|
+
result = [
|
|
1645
|
+
"resolve",
|
|
1646
|
+
response
|
|
1647
|
+
];
|
|
1648
|
+
const isReactElementResponse = React__default.default.isValidElement(response);
|
|
1649
|
+
if (isReactElementResponse) {
|
|
1650
|
+
shouldDismiss = false;
|
|
1651
|
+
this.create({
|
|
1652
|
+
id,
|
|
1653
|
+
type: "default",
|
|
1654
|
+
message: response
|
|
1655
|
+
});
|
|
1656
|
+
} else if (isHttpResponse(response) && !response.ok) {
|
|
1657
|
+
shouldDismiss = false;
|
|
1658
|
+
const promiseData = typeof data.error === "function" ? await data.error(`HTTP error! status: ${response.status}`) : data.error;
|
|
1659
|
+
const description = typeof data.description === "function" ? await data.description(`HTTP error! status: ${response.status}`) : data.description;
|
|
1660
|
+
const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
|
|
1661
|
+
const toastSettings = isExtendedResult ? promiseData : {
|
|
1662
|
+
message: promiseData
|
|
1663
|
+
};
|
|
1664
|
+
this.create({
|
|
1665
|
+
id,
|
|
1666
|
+
type: "error",
|
|
1667
|
+
description,
|
|
1668
|
+
...toastSettings
|
|
1669
|
+
});
|
|
1670
|
+
} else if (response instanceof Error) {
|
|
1671
|
+
shouldDismiss = false;
|
|
1672
|
+
const promiseData = typeof data.error === "function" ? await data.error(response) : data.error;
|
|
1673
|
+
const description = typeof data.description === "function" ? await data.description(response) : data.description;
|
|
1674
|
+
const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
|
|
1675
|
+
const toastSettings = isExtendedResult ? promiseData : {
|
|
1676
|
+
message: promiseData
|
|
1677
|
+
};
|
|
1678
|
+
this.create({
|
|
1679
|
+
id,
|
|
1680
|
+
type: "error",
|
|
1681
|
+
description,
|
|
1682
|
+
...toastSettings
|
|
1683
|
+
});
|
|
1684
|
+
} else if (data.success !== void 0) {
|
|
1685
|
+
shouldDismiss = false;
|
|
1686
|
+
const promiseData = typeof data.success === "function" ? await data.success(response) : data.success;
|
|
1687
|
+
const description = typeof data.description === "function" ? await data.description(response) : data.description;
|
|
1688
|
+
const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
|
|
1689
|
+
const toastSettings = isExtendedResult ? promiseData : {
|
|
1690
|
+
message: promiseData
|
|
1691
|
+
};
|
|
1692
|
+
this.create({
|
|
1693
|
+
id,
|
|
1694
|
+
type: "success",
|
|
1695
|
+
description,
|
|
1696
|
+
...toastSettings
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
}).catch(async (error) => {
|
|
1700
|
+
result = [
|
|
1701
|
+
"reject",
|
|
1702
|
+
error
|
|
1703
|
+
];
|
|
1704
|
+
if (data.error !== void 0) {
|
|
1705
|
+
shouldDismiss = false;
|
|
1706
|
+
const promiseData = typeof data.error === "function" ? await data.error(error) : data.error;
|
|
1707
|
+
const description = typeof data.description === "function" ? await data.description(error) : data.description;
|
|
1708
|
+
const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
|
|
1709
|
+
const toastSettings = isExtendedResult ? promiseData : {
|
|
1710
|
+
message: promiseData
|
|
1711
|
+
};
|
|
1712
|
+
this.create({
|
|
1713
|
+
id,
|
|
1714
|
+
type: "error",
|
|
1715
|
+
description,
|
|
1716
|
+
...toastSettings
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
}).finally(() => {
|
|
1720
|
+
if (shouldDismiss) {
|
|
1721
|
+
this.dismiss(id);
|
|
1722
|
+
id = void 0;
|
|
1723
|
+
}
|
|
1724
|
+
data.finally == null ? void 0 : data.finally.call(data);
|
|
1725
|
+
});
|
|
1726
|
+
const unwrap = () => new Promise((resolve, reject) => originalPromise.then(() => result[0] === "reject" ? reject(result[1]) : resolve(result[1])).catch(reject));
|
|
1727
|
+
if (typeof id !== "string" && typeof id !== "number") {
|
|
1728
|
+
return {
|
|
1729
|
+
unwrap
|
|
1730
|
+
};
|
|
1731
|
+
} else {
|
|
1732
|
+
return Object.assign(id, {
|
|
1733
|
+
unwrap
|
|
1734
|
+
});
|
|
1735
|
+
}
|
|
1736
|
+
};
|
|
1737
|
+
this.custom = (jsx2, data) => {
|
|
1738
|
+
const id = (data == null ? void 0 : data.id) || toastsCounter++;
|
|
1739
|
+
this.create({
|
|
1740
|
+
jsx: jsx2(id),
|
|
1741
|
+
id,
|
|
1742
|
+
...data
|
|
1743
|
+
});
|
|
1744
|
+
return id;
|
|
1745
|
+
};
|
|
1746
|
+
this.getActiveToasts = () => {
|
|
1747
|
+
return this.toasts.filter((toast2) => !this.dismissedToasts.has(toast2.id));
|
|
1748
|
+
};
|
|
1749
|
+
this.subscribers = [];
|
|
1750
|
+
this.toasts = [];
|
|
1751
|
+
this.dismissedToasts = /* @__PURE__ */ new Set();
|
|
1752
|
+
}
|
|
1753
|
+
};
|
|
1754
|
+
var ToastState = new Observer();
|
|
1755
|
+
var toastFunction = (message, data) => {
|
|
1756
|
+
const id = (data == null ? void 0 : data.id) || toastsCounter++;
|
|
1757
|
+
ToastState.addToast({
|
|
1758
|
+
title: message,
|
|
1759
|
+
...data,
|
|
1760
|
+
id
|
|
1761
|
+
});
|
|
1762
|
+
return id;
|
|
1763
|
+
};
|
|
1764
|
+
var isHttpResponse = (data) => {
|
|
1765
|
+
return data && typeof data === "object" && "ok" in data && typeof data.ok === "boolean" && "status" in data && typeof data.status === "number";
|
|
1766
|
+
};
|
|
1767
|
+
var basicToast = toastFunction;
|
|
1768
|
+
var getHistory = () => ToastState.toasts;
|
|
1769
|
+
var getToasts = () => ToastState.getActiveToasts();
|
|
1770
|
+
var toast = Object.assign(basicToast, {
|
|
1771
|
+
success: ToastState.success,
|
|
1772
|
+
info: ToastState.info,
|
|
1773
|
+
warning: ToastState.warning,
|
|
1774
|
+
error: ToastState.error,
|
|
1775
|
+
custom: ToastState.custom,
|
|
1776
|
+
message: ToastState.message,
|
|
1777
|
+
promise: ToastState.promise,
|
|
1778
|
+
dismiss: ToastState.dismiss,
|
|
1779
|
+
loading: ToastState.loading
|
|
1780
|
+
}, {
|
|
1781
|
+
getHistory,
|
|
1782
|
+
getToasts
|
|
1783
|
+
});
|
|
1784
|
+
__insertCSS("[data-sonner-toaster][dir=ltr],html[dir=ltr]{--toast-icon-margin-start:-3px;--toast-icon-margin-end:4px;--toast-svg-margin-start:-1px;--toast-svg-margin-end:0px;--toast-button-margin-start:auto;--toast-button-margin-end:0;--toast-close-button-start:0;--toast-close-button-end:unset;--toast-close-button-transform:translate(-35%, -35%)}[data-sonner-toaster][dir=rtl],html[dir=rtl]{--toast-icon-margin-start:4px;--toast-icon-margin-end:-3px;--toast-svg-margin-start:0px;--toast-svg-margin-end:-1px;--toast-button-margin-start:0;--toast-button-margin-end:auto;--toast-close-button-start:unset;--toast-close-button-end:0;--toast-close-button-transform:translate(35%, -35%)}[data-sonner-toaster]{position:fixed;width:var(--width);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--gray1:hsl(0, 0%, 99%);--gray2:hsl(0, 0%, 97.3%);--gray3:hsl(0, 0%, 95.1%);--gray4:hsl(0, 0%, 93%);--gray5:hsl(0, 0%, 90.9%);--gray6:hsl(0, 0%, 88.7%);--gray7:hsl(0, 0%, 85.8%);--gray8:hsl(0, 0%, 78%);--gray9:hsl(0, 0%, 56.1%);--gray10:hsl(0, 0%, 52.3%);--gray11:hsl(0, 0%, 43.5%);--gray12:hsl(0, 0%, 9%);--border-radius:8px;box-sizing:border-box;padding:0;margin:0;list-style:none;outline:0;z-index:999999999;transition:transform .4s ease}@media (hover:none) and (pointer:coarse){[data-sonner-toaster][data-lifted=true]{transform:none}}[data-sonner-toaster][data-x-position=right]{right:var(--offset-right)}[data-sonner-toaster][data-x-position=left]{left:var(--offset-left)}[data-sonner-toaster][data-x-position=center]{left:50%;transform:translateX(-50%)}[data-sonner-toaster][data-y-position=top]{top:var(--offset-top)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--offset-bottom)}[data-sonner-toast]{--y:translateY(100%);--lift-amount:calc(var(--lift) * var(--gap));z-index:var(--z-index);position:absolute;opacity:0;transform:var(--y);touch-action:none;transition:transform .4s,opacity .4s,height .4s,box-shadow .2s;box-sizing:border-box;outline:0;overflow-wrap:anywhere}[data-sonner-toast][data-styled=true]{padding:16px;background:var(--normal-bg);border:1px solid var(--normal-border);color:var(--normal-text);border-radius:var(--border-radius);box-shadow:0 4px 12px rgba(0,0,0,.1);width:var(--width);font-size:13px;display:flex;align-items:center;gap:6px}[data-sonner-toast]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-y-position=top]{top:0;--y:translateY(-100%);--lift:1;--lift-amount:calc(1 * var(--gap))}[data-sonner-toast][data-y-position=bottom]{bottom:0;--y:translateY(100%);--lift:-1;--lift-amount:calc(var(--lift) * var(--gap))}[data-sonner-toast][data-styled=true] [data-description]{font-weight:400;line-height:1.4;color:#3f3f3f}[data-rich-colors=true][data-sonner-toast][data-styled=true] [data-description]{color:inherit}[data-sonner-toaster][data-sonner-theme=dark] [data-description]{color:#e8e8e8}[data-sonner-toast][data-styled=true] [data-title]{font-weight:500;line-height:1.5;color:inherit}[data-sonner-toast][data-styled=true] [data-icon]{display:flex;height:16px;width:16px;position:relative;justify-content:flex-start;align-items:center;flex-shrink:0;margin-left:var(--toast-icon-margin-start);margin-right:var(--toast-icon-margin-end)}[data-sonner-toast][data-promise=true] [data-icon]>svg{opacity:0;transform:scale(.8);transform-origin:center;animation:sonner-fade-in .3s ease forwards}[data-sonner-toast][data-styled=true] [data-icon]>*{flex-shrink:0}[data-sonner-toast][data-styled=true] [data-icon] svg{margin-left:var(--toast-svg-margin-start);margin-right:var(--toast-svg-margin-end)}[data-sonner-toast][data-styled=true] [data-content]{display:flex;flex-direction:column;gap:2px}[data-sonner-toast][data-styled=true] [data-button]{border-radius:4px;padding-left:8px;padding-right:8px;height:24px;font-size:12px;color:var(--normal-bg);background:var(--normal-text);margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end);border:none;font-weight:500;cursor:pointer;outline:0;display:flex;align-items:center;flex-shrink:0;transition:opacity .4s,box-shadow .2s}[data-sonner-toast][data-styled=true] [data-button]:focus-visible{box-shadow:0 0 0 2px rgba(0,0,0,.4)}[data-sonner-toast][data-styled=true] [data-button]:first-of-type{margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end)}[data-sonner-toast][data-styled=true] [data-cancel]{color:var(--normal-text);background:rgba(0,0,0,.08)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-styled=true] [data-cancel]{background:rgba(255,255,255,.3)}[data-sonner-toast][data-styled=true] [data-close-button]{position:absolute;left:var(--toast-close-button-start);right:var(--toast-close-button-end);top:0;height:20px;width:20px;display:flex;justify-content:center;align-items:center;padding:0;color:var(--gray12);background:var(--normal-bg);border:1px solid var(--gray4);transform:var(--toast-close-button-transform);border-radius:50%;cursor:pointer;z-index:1;transition:opacity .1s,background .2s,border-color .2s}[data-sonner-toast][data-styled=true] [data-close-button]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-styled=true] [data-disabled=true]{cursor:not-allowed}[data-sonner-toast][data-styled=true]:hover [data-close-button]:hover{background:var(--gray2);border-color:var(--gray5)}[data-sonner-toast][data-swiping=true]::before{content:'';position:absolute;left:-100%;right:-100%;height:100%;z-index:-1}[data-sonner-toast][data-y-position=top][data-swiping=true]::before{bottom:50%;transform:scaleY(3) translateY(50%)}[data-sonner-toast][data-y-position=bottom][data-swiping=true]::before{top:50%;transform:scaleY(3) translateY(-50%)}[data-sonner-toast][data-swiping=false][data-removed=true]::before{content:'';position:absolute;inset:0;transform:scaleY(2)}[data-sonner-toast][data-expanded=true]::after{content:'';position:absolute;left:0;height:calc(var(--gap) + 1px);bottom:100%;width:100%}[data-sonner-toast][data-mounted=true]{--y:translateY(0);opacity:1}[data-sonner-toast][data-expanded=false][data-front=false]{--scale:var(--toasts-before) * 0.05 + 1;--y:translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale)));height:var(--front-toast-height)}[data-sonner-toast]>*{transition:opacity .4s}[data-sonner-toast][data-x-position=right]{right:0}[data-sonner-toast][data-x-position=left]{left:0}[data-sonner-toast][data-expanded=false][data-front=false][data-styled=true]>*{opacity:0}[data-sonner-toast][data-visible=false]{opacity:0;pointer-events:none}[data-sonner-toast][data-mounted=true][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset)));height:var(--initial-height)}[data-sonner-toast][data-removed=true][data-front=true][data-swipe-out=false]{--y:translateY(calc(var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset) + var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=false]{--y:translateY(40%);opacity:0;transition:transform .5s,opacity .2s}[data-sonner-toast][data-removed=true][data-front=false]::before{height:calc(var(--initial-height) + 20%)}[data-sonner-toast][data-swiping=true]{transform:var(--y) translateY(var(--swipe-amount-y,0)) translateX(var(--swipe-amount-x,0));transition:none}[data-sonner-toast][data-swiped=true]{user-select:none}[data-sonner-toast][data-swipe-out=true][data-y-position=bottom],[data-sonner-toast][data-swipe-out=true][data-y-position=top]{animation-duration:.2s;animation-timing-function:ease-out;animation-fill-mode:forwards}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=left]{animation-name:swipe-out-left}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=right]{animation-name:swipe-out-right}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=up]{animation-name:swipe-out-up}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=down]{animation-name:swipe-out-down}@keyframes swipe-out-left{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) - 100%));opacity:0}}@keyframes swipe-out-right{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) + 100%));opacity:0}}@keyframes swipe-out-up{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) - 100%));opacity:0}}@keyframes swipe-out-down{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) + 100%));opacity:0}}@media (max-width:600px){[data-sonner-toaster]{position:fixed;right:var(--mobile-offset-right);left:var(--mobile-offset-left);width:100%}[data-sonner-toaster][dir=rtl]{left:calc(var(--mobile-offset-left) * -1)}[data-sonner-toaster] [data-sonner-toast]{left:0;right:0;width:calc(100% - var(--mobile-offset-left) * 2)}[data-sonner-toaster][data-x-position=left]{left:var(--mobile-offset-left)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--mobile-offset-bottom)}[data-sonner-toaster][data-y-position=top]{top:var(--mobile-offset-top)}[data-sonner-toaster][data-x-position=center]{left:var(--mobile-offset-left);right:var(--mobile-offset-right);transform:none}}[data-sonner-toaster][data-sonner-theme=light]{--normal-bg:#fff;--normal-border:var(--gray4);--normal-text:var(--gray12);--success-bg:hsl(143, 85%, 96%);--success-border:hsl(145, 92%, 87%);--success-text:hsl(140, 100%, 27%);--info-bg:hsl(208, 100%, 97%);--info-border:hsl(221, 91%, 93%);--info-text:hsl(210, 92%, 45%);--warning-bg:hsl(49, 100%, 97%);--warning-border:hsl(49, 91%, 84%);--warning-text:hsl(31, 92%, 45%);--error-bg:hsl(359, 100%, 97%);--error-border:hsl(359, 100%, 94%);--error-text:hsl(360, 100%, 45%)}[data-sonner-toaster][data-sonner-theme=light] [data-sonner-toast][data-invert=true]{--normal-bg:#000;--normal-border:hsl(0, 0%, 20%);--normal-text:var(--gray1)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-invert=true]{--normal-bg:#fff;--normal-border:var(--gray3);--normal-text:var(--gray12)}[data-sonner-toaster][data-sonner-theme=dark]{--normal-bg:#000;--normal-bg-hover:hsl(0, 0%, 12%);--normal-border:hsl(0, 0%, 20%);--normal-border-hover:hsl(0, 0%, 25%);--normal-text:var(--gray1);--success-bg:hsl(150, 100%, 6%);--success-border:hsl(147, 100%, 12%);--success-text:hsl(150, 86%, 65%);--info-bg:hsl(215, 100%, 6%);--info-border:hsl(223, 43%, 17%);--info-text:hsl(216, 87%, 65%);--warning-bg:hsl(64, 100%, 6%);--warning-border:hsl(60, 100%, 9%);--warning-text:hsl(46, 87%, 65%);--error-bg:hsl(358, 76%, 10%);--error-border:hsl(357, 89%, 16%);--error-text:hsl(358, 100%, 81%)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]{background:var(--normal-bg);border-color:var(--normal-border);color:var(--normal-text)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]:hover{background:var(--normal-bg-hover);border-color:var(--normal-border-hover)}[data-rich-colors=true][data-sonner-toast][data-type=success]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=success] [data-close-button]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=info]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=info] [data-close-button]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning] [data-close-button]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=error]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}[data-rich-colors=true][data-sonner-toast][data-type=error] [data-close-button]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}.sonner-loading-wrapper{--size:16px;height:var(--size);width:var(--size);position:absolute;inset:0;z-index:10}.sonner-loading-wrapper[data-visible=false]{transform-origin:center;animation:sonner-fade-out .2s ease forwards}.sonner-spinner{position:relative;top:50%;left:50%;height:var(--size);width:var(--size)}.sonner-loading-bar{animation:sonner-spin 1.2s linear infinite;background:var(--gray11);border-radius:6px;height:8%;left:-10%;position:absolute;top:-3.9%;width:24%}.sonner-loading-bar:first-child{animation-delay:-1.2s;transform:rotate(.0001deg) translate(146%)}.sonner-loading-bar:nth-child(2){animation-delay:-1.1s;transform:rotate(30deg) translate(146%)}.sonner-loading-bar:nth-child(3){animation-delay:-1s;transform:rotate(60deg) translate(146%)}.sonner-loading-bar:nth-child(4){animation-delay:-.9s;transform:rotate(90deg) translate(146%)}.sonner-loading-bar:nth-child(5){animation-delay:-.8s;transform:rotate(120deg) translate(146%)}.sonner-loading-bar:nth-child(6){animation-delay:-.7s;transform:rotate(150deg) translate(146%)}.sonner-loading-bar:nth-child(7){animation-delay:-.6s;transform:rotate(180deg) translate(146%)}.sonner-loading-bar:nth-child(8){animation-delay:-.5s;transform:rotate(210deg) translate(146%)}.sonner-loading-bar:nth-child(9){animation-delay:-.4s;transform:rotate(240deg) translate(146%)}.sonner-loading-bar:nth-child(10){animation-delay:-.3s;transform:rotate(270deg) translate(146%)}.sonner-loading-bar:nth-child(11){animation-delay:-.2s;transform:rotate(300deg) translate(146%)}.sonner-loading-bar:nth-child(12){animation-delay:-.1s;transform:rotate(330deg) translate(146%)}@keyframes sonner-fade-in{0%{opacity:0;transform:scale(.8)}100%{opacity:1;transform:scale(1)}}@keyframes sonner-fade-out{0%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(.8)}}@keyframes sonner-spin{0%{opacity:1}100%{opacity:.15}}@media (prefers-reduced-motion){.sonner-loading-bar,[data-sonner-toast],[data-sonner-toast]>*{transition:none!important;animation:none!important}}.sonner-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);transform-origin:center;transition:opacity .2s,transform .2s}.sonner-loader[data-visible=false]{opacity:0;transform:scale(.8) translate(-50%,-50%)}");
|
|
1785
|
+
function isAction(action) {
|
|
1786
|
+
return action.label !== void 0;
|
|
1787
|
+
}
|
|
1788
|
+
var VISIBLE_TOASTS_AMOUNT = 3;
|
|
1789
|
+
var VIEWPORT_OFFSET = "24px";
|
|
1790
|
+
var MOBILE_VIEWPORT_OFFSET = "16px";
|
|
1791
|
+
var TOAST_LIFETIME = 4e3;
|
|
1792
|
+
var TOAST_WIDTH = 356;
|
|
1793
|
+
var GAP = 14;
|
|
1794
|
+
var SWIPE_THRESHOLD = 45;
|
|
1795
|
+
var TIME_BEFORE_UNMOUNT = 200;
|
|
1796
|
+
function cn(...classes) {
|
|
1797
|
+
return classes.filter(Boolean).join(" ");
|
|
1798
|
+
}
|
|
1799
|
+
function getDefaultSwipeDirections(position) {
|
|
1800
|
+
const [y, x] = position.split("-");
|
|
1801
|
+
const directions = [];
|
|
1802
|
+
if (y) {
|
|
1803
|
+
directions.push(y);
|
|
1804
|
+
}
|
|
1805
|
+
if (x) {
|
|
1806
|
+
directions.push(x);
|
|
1807
|
+
}
|
|
1808
|
+
return directions;
|
|
1809
|
+
}
|
|
1810
|
+
var Toast = (props) => {
|
|
1811
|
+
var _toast_classNames, _toast_classNames1, _toast_classNames2, _toast_classNames3, _toast_classNames4, _toast_classNames5, _toast_classNames6, _toast_classNames7, _toast_classNames8;
|
|
1812
|
+
const { invert: ToasterInvert, toast: toast2, unstyled, interacting, setHeights, visibleToasts, heights, index, toasts, expanded, removeToast, defaultRichColors, closeButton: closeButtonFromToaster, style, cancelButtonStyle, actionButtonStyle, className = "", descriptionClassName = "", duration: durationFromToaster, position, gap, expandByDefault, classNames, icons, closeButtonAriaLabel = "Close toast" } = props;
|
|
1813
|
+
const [swipeDirection, setSwipeDirection] = React__default.default.useState(null);
|
|
1814
|
+
const [swipeOutDirection, setSwipeOutDirection] = React__default.default.useState(null);
|
|
1815
|
+
const [mounted, setMounted] = React__default.default.useState(false);
|
|
1816
|
+
const [removed, setRemoved] = React__default.default.useState(false);
|
|
1817
|
+
const [swiping, setSwiping] = React__default.default.useState(false);
|
|
1818
|
+
const [swipeOut, setSwipeOut] = React__default.default.useState(false);
|
|
1819
|
+
const [isSwiped, setIsSwiped] = React__default.default.useState(false);
|
|
1820
|
+
const [offsetBeforeRemove, setOffsetBeforeRemove] = React__default.default.useState(0);
|
|
1821
|
+
const [initialHeight, setInitialHeight] = React__default.default.useState(0);
|
|
1822
|
+
const remainingTime = React__default.default.useRef(toast2.duration || durationFromToaster || TOAST_LIFETIME);
|
|
1823
|
+
const dragStartTime = React__default.default.useRef(null);
|
|
1824
|
+
const toastRef = React__default.default.useRef(null);
|
|
1825
|
+
const isFront = index === 0;
|
|
1826
|
+
const isVisible = index + 1 <= visibleToasts;
|
|
1827
|
+
const toastType = toast2.type;
|
|
1828
|
+
const dismissible = toast2.dismissible !== false;
|
|
1829
|
+
const toastClassname = toast2.className || "";
|
|
1830
|
+
const toastDescriptionClassname = toast2.descriptionClassName || "";
|
|
1831
|
+
const heightIndex = React__default.default.useMemo(() => heights.findIndex((height) => height.toastId === toast2.id) || 0, [
|
|
1832
|
+
heights,
|
|
1833
|
+
toast2.id
|
|
1834
|
+
]);
|
|
1835
|
+
const closeButton = React__default.default.useMemo(() => {
|
|
1836
|
+
var _toast_closeButton;
|
|
1837
|
+
return (_toast_closeButton = toast2.closeButton) != null ? _toast_closeButton : closeButtonFromToaster;
|
|
1838
|
+
}, [
|
|
1839
|
+
toast2.closeButton,
|
|
1840
|
+
closeButtonFromToaster
|
|
1841
|
+
]);
|
|
1842
|
+
const duration = React__default.default.useMemo(() => toast2.duration || durationFromToaster || TOAST_LIFETIME, [
|
|
1843
|
+
toast2.duration,
|
|
1844
|
+
durationFromToaster
|
|
1845
|
+
]);
|
|
1846
|
+
const closeTimerStartTimeRef = React__default.default.useRef(0);
|
|
1847
|
+
const offset = React__default.default.useRef(0);
|
|
1848
|
+
const lastCloseTimerStartTimeRef = React__default.default.useRef(0);
|
|
1849
|
+
const pointerStartRef = React__default.default.useRef(null);
|
|
1850
|
+
const [y, x] = position.split("-");
|
|
1851
|
+
const toastsHeightBefore = React__default.default.useMemo(() => {
|
|
1852
|
+
return heights.reduce((prev, curr, reducerIndex) => {
|
|
1853
|
+
if (reducerIndex >= heightIndex) {
|
|
1854
|
+
return prev;
|
|
1855
|
+
}
|
|
1856
|
+
return prev + curr.height;
|
|
1857
|
+
}, 0);
|
|
1858
|
+
}, [
|
|
1859
|
+
heights,
|
|
1860
|
+
heightIndex
|
|
1861
|
+
]);
|
|
1862
|
+
const isDocumentHidden = useIsDocumentHidden();
|
|
1863
|
+
const invert = toast2.invert || ToasterInvert;
|
|
1864
|
+
const disabled = toastType === "loading";
|
|
1865
|
+
offset.current = React__default.default.useMemo(() => heightIndex * gap + toastsHeightBefore, [
|
|
1866
|
+
heightIndex,
|
|
1867
|
+
toastsHeightBefore
|
|
1868
|
+
]);
|
|
1869
|
+
React__default.default.useEffect(() => {
|
|
1870
|
+
remainingTime.current = duration;
|
|
1871
|
+
}, [
|
|
1872
|
+
duration
|
|
1873
|
+
]);
|
|
1874
|
+
React__default.default.useEffect(() => {
|
|
1875
|
+
setMounted(true);
|
|
1876
|
+
}, []);
|
|
1877
|
+
React__default.default.useEffect(() => {
|
|
1878
|
+
const toastNode = toastRef.current;
|
|
1879
|
+
if (toastNode) {
|
|
1880
|
+
const height = toastNode.getBoundingClientRect().height;
|
|
1881
|
+
setInitialHeight(height);
|
|
1882
|
+
setHeights((h) => [
|
|
1883
|
+
{
|
|
1884
|
+
toastId: toast2.id,
|
|
1885
|
+
height,
|
|
1886
|
+
position: toast2.position
|
|
1887
|
+
},
|
|
1888
|
+
...h
|
|
1889
|
+
]);
|
|
1890
|
+
return () => setHeights((h) => h.filter((height2) => height2.toastId !== toast2.id));
|
|
1891
|
+
}
|
|
1892
|
+
}, [
|
|
1893
|
+
setHeights,
|
|
1894
|
+
toast2.id
|
|
1895
|
+
]);
|
|
1896
|
+
React__default.default.useLayoutEffect(() => {
|
|
1897
|
+
if (!mounted) return;
|
|
1898
|
+
const toastNode = toastRef.current;
|
|
1899
|
+
const originalHeight = toastNode.style.height;
|
|
1900
|
+
toastNode.style.height = "auto";
|
|
1901
|
+
const newHeight = toastNode.getBoundingClientRect().height;
|
|
1902
|
+
toastNode.style.height = originalHeight;
|
|
1903
|
+
setInitialHeight(newHeight);
|
|
1904
|
+
setHeights((heights2) => {
|
|
1905
|
+
const alreadyExists = heights2.find((height) => height.toastId === toast2.id);
|
|
1906
|
+
if (!alreadyExists) {
|
|
1907
|
+
return [
|
|
1908
|
+
{
|
|
1909
|
+
toastId: toast2.id,
|
|
1910
|
+
height: newHeight,
|
|
1911
|
+
position: toast2.position
|
|
1912
|
+
},
|
|
1913
|
+
...heights2
|
|
1914
|
+
];
|
|
1915
|
+
} else {
|
|
1916
|
+
return heights2.map((height) => height.toastId === toast2.id ? {
|
|
1917
|
+
...height,
|
|
1918
|
+
height: newHeight
|
|
1919
|
+
} : height);
|
|
1920
|
+
}
|
|
1921
|
+
});
|
|
1922
|
+
}, [
|
|
1923
|
+
mounted,
|
|
1924
|
+
toast2.title,
|
|
1925
|
+
toast2.description,
|
|
1926
|
+
setHeights,
|
|
1927
|
+
toast2.id,
|
|
1928
|
+
toast2.jsx,
|
|
1929
|
+
toast2.action,
|
|
1930
|
+
toast2.cancel
|
|
1931
|
+
]);
|
|
1932
|
+
const deleteToast = React__default.default.useCallback(() => {
|
|
1933
|
+
setRemoved(true);
|
|
1934
|
+
setOffsetBeforeRemove(offset.current);
|
|
1935
|
+
setHeights((h) => h.filter((height) => height.toastId !== toast2.id));
|
|
1936
|
+
setTimeout(() => {
|
|
1937
|
+
removeToast(toast2);
|
|
1938
|
+
}, TIME_BEFORE_UNMOUNT);
|
|
1939
|
+
}, [
|
|
1940
|
+
toast2,
|
|
1941
|
+
removeToast,
|
|
1942
|
+
setHeights,
|
|
1943
|
+
offset
|
|
1944
|
+
]);
|
|
1945
|
+
React__default.default.useEffect(() => {
|
|
1946
|
+
if (toast2.promise && toastType === "loading" || toast2.duration === Infinity || toast2.type === "loading") return;
|
|
1947
|
+
let timeoutId;
|
|
1948
|
+
const pauseTimer = () => {
|
|
1949
|
+
if (lastCloseTimerStartTimeRef.current < closeTimerStartTimeRef.current) {
|
|
1950
|
+
const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - closeTimerStartTimeRef.current;
|
|
1951
|
+
remainingTime.current = remainingTime.current - elapsedTime;
|
|
1952
|
+
}
|
|
1953
|
+
lastCloseTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime();
|
|
1954
|
+
};
|
|
1955
|
+
const startTimer = () => {
|
|
1956
|
+
if (remainingTime.current === Infinity) return;
|
|
1957
|
+
closeTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime();
|
|
1958
|
+
timeoutId = setTimeout(() => {
|
|
1959
|
+
toast2.onAutoClose == null ? void 0 : toast2.onAutoClose.call(toast2, toast2);
|
|
1960
|
+
deleteToast();
|
|
1961
|
+
}, remainingTime.current);
|
|
1962
|
+
};
|
|
1963
|
+
if (expanded || interacting || isDocumentHidden) {
|
|
1964
|
+
pauseTimer();
|
|
1965
|
+
} else {
|
|
1966
|
+
startTimer();
|
|
1967
|
+
}
|
|
1968
|
+
return () => clearTimeout(timeoutId);
|
|
1969
|
+
}, [
|
|
1970
|
+
expanded,
|
|
1971
|
+
interacting,
|
|
1972
|
+
toast2,
|
|
1973
|
+
toastType,
|
|
1974
|
+
isDocumentHidden,
|
|
1975
|
+
deleteToast
|
|
1976
|
+
]);
|
|
1977
|
+
React__default.default.useEffect(() => {
|
|
1978
|
+
if (toast2.delete) {
|
|
1979
|
+
deleteToast();
|
|
1980
|
+
toast2.onDismiss == null ? void 0 : toast2.onDismiss.call(toast2, toast2);
|
|
1981
|
+
}
|
|
1982
|
+
}, [
|
|
1983
|
+
deleteToast,
|
|
1984
|
+
toast2.delete
|
|
1985
|
+
]);
|
|
1986
|
+
function getLoadingIcon() {
|
|
1987
|
+
var _toast_classNames9;
|
|
1988
|
+
if (icons == null ? void 0 : icons.loading) {
|
|
1989
|
+
var _toast_classNames12;
|
|
1990
|
+
return /* @__PURE__ */ React__default.default.createElement("div", {
|
|
1991
|
+
className: cn(classNames == null ? void 0 : classNames.loader, toast2 == null ? void 0 : (_toast_classNames12 = toast2.classNames) == null ? void 0 : _toast_classNames12.loader, "sonner-loader"),
|
|
1992
|
+
"data-visible": toastType === "loading"
|
|
1993
|
+
}, icons.loading);
|
|
1994
|
+
}
|
|
1995
|
+
return /* @__PURE__ */ React__default.default.createElement(Loader, {
|
|
1996
|
+
className: cn(classNames == null ? void 0 : classNames.loader, toast2 == null ? void 0 : (_toast_classNames9 = toast2.classNames) == null ? void 0 : _toast_classNames9.loader),
|
|
1997
|
+
visible: toastType === "loading"
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
const icon = toast2.icon || (icons == null ? void 0 : icons[toastType]) || getAsset(toastType);
|
|
2001
|
+
var _toast_richColors, _icons_close;
|
|
2002
|
+
return /* @__PURE__ */ React__default.default.createElement("li", {
|
|
2003
|
+
tabIndex: 0,
|
|
2004
|
+
ref: toastRef,
|
|
2005
|
+
className: cn(className, toastClassname, classNames == null ? void 0 : classNames.toast, toast2 == null ? void 0 : (_toast_classNames = toast2.classNames) == null ? void 0 : _toast_classNames.toast, classNames == null ? void 0 : classNames.default, classNames == null ? void 0 : classNames[toastType], toast2 == null ? void 0 : (_toast_classNames1 = toast2.classNames) == null ? void 0 : _toast_classNames1[toastType]),
|
|
2006
|
+
"data-sonner-toast": "",
|
|
2007
|
+
"data-rich-colors": (_toast_richColors = toast2.richColors) != null ? _toast_richColors : defaultRichColors,
|
|
2008
|
+
"data-styled": !Boolean(toast2.jsx || toast2.unstyled || unstyled),
|
|
2009
|
+
"data-mounted": mounted,
|
|
2010
|
+
"data-promise": Boolean(toast2.promise),
|
|
2011
|
+
"data-swiped": isSwiped,
|
|
2012
|
+
"data-removed": removed,
|
|
2013
|
+
"data-visible": isVisible,
|
|
2014
|
+
"data-y-position": y,
|
|
2015
|
+
"data-x-position": x,
|
|
2016
|
+
"data-index": index,
|
|
2017
|
+
"data-front": isFront,
|
|
2018
|
+
"data-swiping": swiping,
|
|
2019
|
+
"data-dismissible": dismissible,
|
|
2020
|
+
"data-type": toastType,
|
|
2021
|
+
"data-invert": invert,
|
|
2022
|
+
"data-swipe-out": swipeOut,
|
|
2023
|
+
"data-swipe-direction": swipeOutDirection,
|
|
2024
|
+
"data-expanded": Boolean(expanded || expandByDefault && mounted),
|
|
2025
|
+
"data-testid": toast2.testId,
|
|
2026
|
+
style: {
|
|
2027
|
+
"--index": index,
|
|
2028
|
+
"--toasts-before": index,
|
|
2029
|
+
"--z-index": toasts.length - index,
|
|
2030
|
+
"--offset": `${removed ? offsetBeforeRemove : offset.current}px`,
|
|
2031
|
+
"--initial-height": expandByDefault ? "auto" : `${initialHeight}px`,
|
|
2032
|
+
...style,
|
|
2033
|
+
...toast2.style
|
|
2034
|
+
},
|
|
2035
|
+
onDragEnd: () => {
|
|
2036
|
+
setSwiping(false);
|
|
2037
|
+
setSwipeDirection(null);
|
|
2038
|
+
pointerStartRef.current = null;
|
|
2039
|
+
},
|
|
2040
|
+
onPointerDown: (event) => {
|
|
2041
|
+
if (event.button === 2) return;
|
|
2042
|
+
if (disabled || !dismissible) return;
|
|
2043
|
+
dragStartTime.current = /* @__PURE__ */ new Date();
|
|
2044
|
+
setOffsetBeforeRemove(offset.current);
|
|
2045
|
+
event.target.setPointerCapture(event.pointerId);
|
|
2046
|
+
if (event.target.tagName === "BUTTON") return;
|
|
2047
|
+
setSwiping(true);
|
|
2048
|
+
pointerStartRef.current = {
|
|
2049
|
+
x: event.clientX,
|
|
2050
|
+
y: event.clientY
|
|
2051
|
+
};
|
|
2052
|
+
},
|
|
2053
|
+
onPointerUp: () => {
|
|
2054
|
+
var _toastRef_current, _toastRef_current1, _dragStartTime_current;
|
|
2055
|
+
if (swipeOut || !dismissible) return;
|
|
2056
|
+
pointerStartRef.current = null;
|
|
2057
|
+
const swipeAmountX = Number(((_toastRef_current = toastRef.current) == null ? void 0 : _toastRef_current.style.getPropertyValue("--swipe-amount-x").replace("px", "")) || 0);
|
|
2058
|
+
const swipeAmountY = Number(((_toastRef_current1 = toastRef.current) == null ? void 0 : _toastRef_current1.style.getPropertyValue("--swipe-amount-y").replace("px", "")) || 0);
|
|
2059
|
+
const timeTaken = (/* @__PURE__ */ new Date()).getTime() - ((_dragStartTime_current = dragStartTime.current) == null ? void 0 : _dragStartTime_current.getTime());
|
|
2060
|
+
const swipeAmount = swipeDirection === "x" ? swipeAmountX : swipeAmountY;
|
|
2061
|
+
const velocity = Math.abs(swipeAmount) / timeTaken;
|
|
2062
|
+
if (Math.abs(swipeAmount) >= SWIPE_THRESHOLD || velocity > 0.11) {
|
|
2063
|
+
setOffsetBeforeRemove(offset.current);
|
|
2064
|
+
toast2.onDismiss == null ? void 0 : toast2.onDismiss.call(toast2, toast2);
|
|
2065
|
+
if (swipeDirection === "x") {
|
|
2066
|
+
setSwipeOutDirection(swipeAmountX > 0 ? "right" : "left");
|
|
2067
|
+
} else {
|
|
2068
|
+
setSwipeOutDirection(swipeAmountY > 0 ? "down" : "up");
|
|
2069
|
+
}
|
|
2070
|
+
deleteToast();
|
|
2071
|
+
setSwipeOut(true);
|
|
2072
|
+
return;
|
|
2073
|
+
} else {
|
|
2074
|
+
var _toastRef_current2, _toastRef_current3;
|
|
2075
|
+
(_toastRef_current2 = toastRef.current) == null ? void 0 : _toastRef_current2.style.setProperty("--swipe-amount-x", `0px`);
|
|
2076
|
+
(_toastRef_current3 = toastRef.current) == null ? void 0 : _toastRef_current3.style.setProperty("--swipe-amount-y", `0px`);
|
|
2077
|
+
}
|
|
2078
|
+
setIsSwiped(false);
|
|
2079
|
+
setSwiping(false);
|
|
2080
|
+
setSwipeDirection(null);
|
|
2081
|
+
},
|
|
2082
|
+
onPointerMove: (event) => {
|
|
2083
|
+
var _window_getSelection, _toastRef_current, _toastRef_current1;
|
|
2084
|
+
if (!pointerStartRef.current || !dismissible) return;
|
|
2085
|
+
const isHighlighted = ((_window_getSelection = window.getSelection()) == null ? void 0 : _window_getSelection.toString().length) > 0;
|
|
2086
|
+
if (isHighlighted) return;
|
|
2087
|
+
const yDelta = event.clientY - pointerStartRef.current.y;
|
|
2088
|
+
const xDelta = event.clientX - pointerStartRef.current.x;
|
|
2089
|
+
var _props_swipeDirections;
|
|
2090
|
+
const swipeDirections = (_props_swipeDirections = props.swipeDirections) != null ? _props_swipeDirections : getDefaultSwipeDirections(position);
|
|
2091
|
+
if (!swipeDirection && (Math.abs(xDelta) > 1 || Math.abs(yDelta) > 1)) {
|
|
2092
|
+
setSwipeDirection(Math.abs(xDelta) > Math.abs(yDelta) ? "x" : "y");
|
|
2093
|
+
}
|
|
2094
|
+
let swipeAmount = {
|
|
2095
|
+
x: 0,
|
|
2096
|
+
y: 0
|
|
2097
|
+
};
|
|
2098
|
+
const getDampening = (delta) => {
|
|
2099
|
+
const factor = Math.abs(delta) / 20;
|
|
2100
|
+
return 1 / (1.5 + factor);
|
|
2101
|
+
};
|
|
2102
|
+
if (swipeDirection === "y") {
|
|
2103
|
+
if (swipeDirections.includes("top") || swipeDirections.includes("bottom")) {
|
|
2104
|
+
if (swipeDirections.includes("top") && yDelta < 0 || swipeDirections.includes("bottom") && yDelta > 0) {
|
|
2105
|
+
swipeAmount.y = yDelta;
|
|
2106
|
+
} else {
|
|
2107
|
+
const dampenedDelta = yDelta * getDampening(yDelta);
|
|
2108
|
+
swipeAmount.y = Math.abs(dampenedDelta) < Math.abs(yDelta) ? dampenedDelta : yDelta;
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
} else if (swipeDirection === "x") {
|
|
2112
|
+
if (swipeDirections.includes("left") || swipeDirections.includes("right")) {
|
|
2113
|
+
if (swipeDirections.includes("left") && xDelta < 0 || swipeDirections.includes("right") && xDelta > 0) {
|
|
2114
|
+
swipeAmount.x = xDelta;
|
|
2115
|
+
} else {
|
|
2116
|
+
const dampenedDelta = xDelta * getDampening(xDelta);
|
|
2117
|
+
swipeAmount.x = Math.abs(dampenedDelta) < Math.abs(xDelta) ? dampenedDelta : xDelta;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
if (Math.abs(swipeAmount.x) > 0 || Math.abs(swipeAmount.y) > 0) {
|
|
2122
|
+
setIsSwiped(true);
|
|
2123
|
+
}
|
|
2124
|
+
(_toastRef_current = toastRef.current) == null ? void 0 : _toastRef_current.style.setProperty("--swipe-amount-x", `${swipeAmount.x}px`);
|
|
2125
|
+
(_toastRef_current1 = toastRef.current) == null ? void 0 : _toastRef_current1.style.setProperty("--swipe-amount-y", `${swipeAmount.y}px`);
|
|
2126
|
+
}
|
|
2127
|
+
}, closeButton && !toast2.jsx && toastType !== "loading" ? /* @__PURE__ */ React__default.default.createElement("button", {
|
|
2128
|
+
"aria-label": closeButtonAriaLabel,
|
|
2129
|
+
"data-disabled": disabled,
|
|
2130
|
+
"data-close-button": true,
|
|
2131
|
+
onClick: disabled || !dismissible ? () => {
|
|
2132
|
+
} : () => {
|
|
2133
|
+
deleteToast();
|
|
2134
|
+
toast2.onDismiss == null ? void 0 : toast2.onDismiss.call(toast2, toast2);
|
|
2135
|
+
},
|
|
2136
|
+
className: cn(classNames == null ? void 0 : classNames.closeButton, toast2 == null ? void 0 : (_toast_classNames2 = toast2.classNames) == null ? void 0 : _toast_classNames2.closeButton)
|
|
2137
|
+
}, (_icons_close = icons == null ? void 0 : icons.close) != null ? _icons_close : CloseIcon) : null, (toastType || toast2.icon || toast2.promise) && toast2.icon !== null && ((icons == null ? void 0 : icons[toastType]) !== null || toast2.icon) ? /* @__PURE__ */ React__default.default.createElement("div", {
|
|
2138
|
+
"data-icon": "",
|
|
2139
|
+
className: cn(classNames == null ? void 0 : classNames.icon, toast2 == null ? void 0 : (_toast_classNames3 = toast2.classNames) == null ? void 0 : _toast_classNames3.icon)
|
|
2140
|
+
}, toast2.promise || toast2.type === "loading" && !toast2.icon ? toast2.icon || getLoadingIcon() : null, toast2.type !== "loading" ? icon : null) : null, /* @__PURE__ */ React__default.default.createElement("div", {
|
|
2141
|
+
"data-content": "",
|
|
2142
|
+
className: cn(classNames == null ? void 0 : classNames.content, toast2 == null ? void 0 : (_toast_classNames4 = toast2.classNames) == null ? void 0 : _toast_classNames4.content)
|
|
2143
|
+
}, /* @__PURE__ */ React__default.default.createElement("div", {
|
|
2144
|
+
"data-title": "",
|
|
2145
|
+
className: cn(classNames == null ? void 0 : classNames.title, toast2 == null ? void 0 : (_toast_classNames5 = toast2.classNames) == null ? void 0 : _toast_classNames5.title)
|
|
2146
|
+
}, toast2.jsx ? toast2.jsx : typeof toast2.title === "function" ? toast2.title() : toast2.title), toast2.description ? /* @__PURE__ */ React__default.default.createElement("div", {
|
|
2147
|
+
"data-description": "",
|
|
2148
|
+
className: cn(descriptionClassName, toastDescriptionClassname, classNames == null ? void 0 : classNames.description, toast2 == null ? void 0 : (_toast_classNames6 = toast2.classNames) == null ? void 0 : _toast_classNames6.description)
|
|
2149
|
+
}, typeof toast2.description === "function" ? toast2.description() : toast2.description) : null), /* @__PURE__ */ React__default.default.isValidElement(toast2.cancel) ? toast2.cancel : toast2.cancel && isAction(toast2.cancel) ? /* @__PURE__ */ React__default.default.createElement("button", {
|
|
2150
|
+
"data-button": true,
|
|
2151
|
+
"data-cancel": true,
|
|
2152
|
+
style: toast2.cancelButtonStyle || cancelButtonStyle,
|
|
2153
|
+
onClick: (event) => {
|
|
2154
|
+
if (!isAction(toast2.cancel)) return;
|
|
2155
|
+
if (!dismissible) return;
|
|
2156
|
+
toast2.cancel.onClick == null ? void 0 : toast2.cancel.onClick.call(toast2.cancel, event);
|
|
2157
|
+
deleteToast();
|
|
2158
|
+
},
|
|
2159
|
+
className: cn(classNames == null ? void 0 : classNames.cancelButton, toast2 == null ? void 0 : (_toast_classNames7 = toast2.classNames) == null ? void 0 : _toast_classNames7.cancelButton)
|
|
2160
|
+
}, toast2.cancel.label) : null, /* @__PURE__ */ React__default.default.isValidElement(toast2.action) ? toast2.action : toast2.action && isAction(toast2.action) ? /* @__PURE__ */ React__default.default.createElement("button", {
|
|
2161
|
+
"data-button": true,
|
|
2162
|
+
"data-action": true,
|
|
2163
|
+
style: toast2.actionButtonStyle || actionButtonStyle,
|
|
2164
|
+
onClick: (event) => {
|
|
2165
|
+
if (!isAction(toast2.action)) return;
|
|
2166
|
+
toast2.action.onClick == null ? void 0 : toast2.action.onClick.call(toast2.action, event);
|
|
2167
|
+
if (event.defaultPrevented) return;
|
|
2168
|
+
deleteToast();
|
|
2169
|
+
},
|
|
2170
|
+
className: cn(classNames == null ? void 0 : classNames.actionButton, toast2 == null ? void 0 : (_toast_classNames8 = toast2.classNames) == null ? void 0 : _toast_classNames8.actionButton)
|
|
2171
|
+
}, toast2.action.label) : null);
|
|
2172
|
+
};
|
|
2173
|
+
function getDocumentDirection() {
|
|
2174
|
+
if (typeof window === "undefined") return "ltr";
|
|
2175
|
+
if (typeof document === "undefined") return "ltr";
|
|
2176
|
+
const dirAttribute = document.documentElement.getAttribute("dir");
|
|
2177
|
+
if (dirAttribute === "auto" || !dirAttribute) {
|
|
2178
|
+
return window.getComputedStyle(document.documentElement).direction;
|
|
2179
|
+
}
|
|
2180
|
+
return dirAttribute;
|
|
2181
|
+
}
|
|
2182
|
+
function assignOffset(defaultOffset, mobileOffset) {
|
|
2183
|
+
const styles = {};
|
|
2184
|
+
[
|
|
2185
|
+
defaultOffset,
|
|
2186
|
+
mobileOffset
|
|
2187
|
+
].forEach((offset, index) => {
|
|
2188
|
+
const isMobile = index === 1;
|
|
2189
|
+
const prefix = isMobile ? "--mobile-offset" : "--offset";
|
|
2190
|
+
const defaultValue = isMobile ? MOBILE_VIEWPORT_OFFSET : VIEWPORT_OFFSET;
|
|
2191
|
+
function assignAll(offset2) {
|
|
2192
|
+
[
|
|
2193
|
+
"top",
|
|
2194
|
+
"right",
|
|
2195
|
+
"bottom",
|
|
2196
|
+
"left"
|
|
2197
|
+
].forEach((key) => {
|
|
2198
|
+
styles[`${prefix}-${key}`] = typeof offset2 === "number" ? `${offset2}px` : offset2;
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
2201
|
+
if (typeof offset === "number" || typeof offset === "string") {
|
|
2202
|
+
assignAll(offset);
|
|
2203
|
+
} else if (typeof offset === "object") {
|
|
2204
|
+
[
|
|
2205
|
+
"top",
|
|
2206
|
+
"right",
|
|
2207
|
+
"bottom",
|
|
2208
|
+
"left"
|
|
2209
|
+
].forEach((key) => {
|
|
2210
|
+
if (offset[key] === void 0) {
|
|
2211
|
+
styles[`${prefix}-${key}`] = defaultValue;
|
|
2212
|
+
} else {
|
|
2213
|
+
styles[`${prefix}-${key}`] = typeof offset[key] === "number" ? `${offset[key]}px` : offset[key];
|
|
2214
|
+
}
|
|
2215
|
+
});
|
|
2216
|
+
} else {
|
|
2217
|
+
assignAll(defaultValue);
|
|
2218
|
+
}
|
|
2219
|
+
});
|
|
2220
|
+
return styles;
|
|
2221
|
+
}
|
|
2222
|
+
var Toaster = /* @__PURE__ */ React__default.default.forwardRef(function Toaster2(props, ref) {
|
|
2223
|
+
const { id, invert, position = "bottom-right", hotkey = [
|
|
2224
|
+
"altKey",
|
|
2225
|
+
"KeyT"
|
|
2226
|
+
], expand, closeButton, className, offset, mobileOffset, theme = "light", richColors, duration, style, visibleToasts = VISIBLE_TOASTS_AMOUNT, toastOptions, dir = getDocumentDirection(), gap = GAP, icons, containerAriaLabel = "Notifications" } = props;
|
|
2227
|
+
const [toasts, setToasts] = React__default.default.useState([]);
|
|
2228
|
+
const filteredToasts = React__default.default.useMemo(() => {
|
|
2229
|
+
if (id) {
|
|
2230
|
+
return toasts.filter((toast2) => toast2.toasterId === id);
|
|
2231
|
+
}
|
|
2232
|
+
return toasts.filter((toast2) => !toast2.toasterId);
|
|
2233
|
+
}, [
|
|
2234
|
+
toasts,
|
|
2235
|
+
id
|
|
2236
|
+
]);
|
|
2237
|
+
const possiblePositions = React__default.default.useMemo(() => {
|
|
2238
|
+
return Array.from(new Set([
|
|
2239
|
+
position
|
|
2240
|
+
].concat(filteredToasts.filter((toast2) => toast2.position).map((toast2) => toast2.position))));
|
|
2241
|
+
}, [
|
|
2242
|
+
filteredToasts,
|
|
2243
|
+
position
|
|
2244
|
+
]);
|
|
2245
|
+
const [heights, setHeights] = React__default.default.useState([]);
|
|
2246
|
+
const [expanded, setExpanded] = React__default.default.useState(false);
|
|
2247
|
+
const [interacting, setInteracting] = React__default.default.useState(false);
|
|
2248
|
+
const [actualTheme, setActualTheme] = React__default.default.useState(theme !== "system" ? theme : typeof window !== "undefined" ? window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : "light");
|
|
2249
|
+
const listRef = React__default.default.useRef(null);
|
|
2250
|
+
const hotkeyLabel = hotkey.join("+").replace(/Key/g, "").replace(/Digit/g, "");
|
|
2251
|
+
const lastFocusedElementRef = React__default.default.useRef(null);
|
|
2252
|
+
const isFocusWithinRef = React__default.default.useRef(false);
|
|
2253
|
+
const removeToast = React__default.default.useCallback((toastToRemove) => {
|
|
2254
|
+
setToasts((toasts2) => {
|
|
2255
|
+
var _toasts_find;
|
|
2256
|
+
if (!((_toasts_find = toasts2.find((toast2) => toast2.id === toastToRemove.id)) == null ? void 0 : _toasts_find.delete)) {
|
|
2257
|
+
ToastState.dismiss(toastToRemove.id);
|
|
2258
|
+
}
|
|
2259
|
+
return toasts2.filter(({ id: id2 }) => id2 !== toastToRemove.id);
|
|
2260
|
+
});
|
|
2261
|
+
}, []);
|
|
2262
|
+
React__default.default.useEffect(() => {
|
|
2263
|
+
return ToastState.subscribe((toast2) => {
|
|
2264
|
+
if (toast2.dismiss) {
|
|
2265
|
+
requestAnimationFrame(() => {
|
|
2266
|
+
setToasts((toasts2) => toasts2.map((t) => t.id === toast2.id ? {
|
|
2267
|
+
...t,
|
|
2268
|
+
delete: true
|
|
2269
|
+
} : t));
|
|
2270
|
+
});
|
|
2271
|
+
return;
|
|
2272
|
+
}
|
|
2273
|
+
setTimeout(() => {
|
|
2274
|
+
ReactDOM__default.default.flushSync(() => {
|
|
2275
|
+
setToasts((toasts2) => {
|
|
2276
|
+
const indexOfExistingToast = toasts2.findIndex((t) => t.id === toast2.id);
|
|
2277
|
+
if (indexOfExistingToast !== -1) {
|
|
2278
|
+
return [
|
|
2279
|
+
...toasts2.slice(0, indexOfExistingToast),
|
|
2280
|
+
{
|
|
2281
|
+
...toasts2[indexOfExistingToast],
|
|
2282
|
+
...toast2
|
|
2283
|
+
},
|
|
2284
|
+
...toasts2.slice(indexOfExistingToast + 1)
|
|
2285
|
+
];
|
|
2286
|
+
}
|
|
2287
|
+
return [
|
|
2288
|
+
toast2,
|
|
2289
|
+
...toasts2
|
|
2290
|
+
];
|
|
2291
|
+
});
|
|
2292
|
+
});
|
|
2293
|
+
});
|
|
2294
|
+
});
|
|
2295
|
+
}, [
|
|
2296
|
+
toasts
|
|
2297
|
+
]);
|
|
2298
|
+
React__default.default.useEffect(() => {
|
|
2299
|
+
if (theme !== "system") {
|
|
2300
|
+
setActualTheme(theme);
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
if (theme === "system") {
|
|
2304
|
+
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
2305
|
+
setActualTheme("dark");
|
|
2306
|
+
} else {
|
|
2307
|
+
setActualTheme("light");
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
if (typeof window === "undefined") return;
|
|
2311
|
+
const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
2312
|
+
try {
|
|
2313
|
+
darkMediaQuery.addEventListener("change", ({ matches }) => {
|
|
2314
|
+
if (matches) {
|
|
2315
|
+
setActualTheme("dark");
|
|
2316
|
+
} else {
|
|
2317
|
+
setActualTheme("light");
|
|
2318
|
+
}
|
|
2319
|
+
});
|
|
2320
|
+
} catch (error) {
|
|
2321
|
+
darkMediaQuery.addListener(({ matches }) => {
|
|
2322
|
+
try {
|
|
2323
|
+
if (matches) {
|
|
2324
|
+
setActualTheme("dark");
|
|
2325
|
+
} else {
|
|
2326
|
+
setActualTheme("light");
|
|
2327
|
+
}
|
|
2328
|
+
} catch (e) {
|
|
2329
|
+
console.error(e);
|
|
2330
|
+
}
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2333
|
+
}, [
|
|
2334
|
+
theme
|
|
2335
|
+
]);
|
|
2336
|
+
React__default.default.useEffect(() => {
|
|
2337
|
+
if (toasts.length <= 1) {
|
|
2338
|
+
setExpanded(false);
|
|
2339
|
+
}
|
|
2340
|
+
}, [
|
|
2341
|
+
toasts
|
|
2342
|
+
]);
|
|
2343
|
+
React__default.default.useEffect(() => {
|
|
2344
|
+
const handleKeyDown = (event) => {
|
|
2345
|
+
var _listRef_current;
|
|
2346
|
+
const isHotkeyPressed = hotkey.every((key) => event[key] || event.code === key);
|
|
2347
|
+
if (isHotkeyPressed) {
|
|
2348
|
+
var _listRef_current1;
|
|
2349
|
+
setExpanded(true);
|
|
2350
|
+
(_listRef_current1 = listRef.current) == null ? void 0 : _listRef_current1.focus();
|
|
2351
|
+
}
|
|
2352
|
+
if (event.code === "Escape" && (document.activeElement === listRef.current || ((_listRef_current = listRef.current) == null ? void 0 : _listRef_current.contains(document.activeElement)))) {
|
|
2353
|
+
setExpanded(false);
|
|
2354
|
+
}
|
|
2355
|
+
};
|
|
2356
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2357
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
2358
|
+
}, [
|
|
2359
|
+
hotkey
|
|
2360
|
+
]);
|
|
2361
|
+
React__default.default.useEffect(() => {
|
|
2362
|
+
if (listRef.current) {
|
|
2363
|
+
return () => {
|
|
2364
|
+
if (lastFocusedElementRef.current) {
|
|
2365
|
+
lastFocusedElementRef.current.focus({
|
|
2366
|
+
preventScroll: true
|
|
2367
|
+
});
|
|
2368
|
+
lastFocusedElementRef.current = null;
|
|
2369
|
+
isFocusWithinRef.current = false;
|
|
2370
|
+
}
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
}, [
|
|
2374
|
+
listRef.current
|
|
2375
|
+
]);
|
|
2376
|
+
return (
|
|
2377
|
+
// Remove item from normal navigation flow, only available via hotkey
|
|
2378
|
+
/* @__PURE__ */ React__default.default.createElement("section", {
|
|
2379
|
+
ref,
|
|
2380
|
+
"aria-label": `${containerAriaLabel} ${hotkeyLabel}`,
|
|
2381
|
+
tabIndex: -1,
|
|
2382
|
+
"aria-live": "polite",
|
|
2383
|
+
"aria-relevant": "additions text",
|
|
2384
|
+
"aria-atomic": "false",
|
|
2385
|
+
suppressHydrationWarning: true
|
|
2386
|
+
}, possiblePositions.map((position2, index) => {
|
|
2387
|
+
var _heights_;
|
|
2388
|
+
const [y, x] = position2.split("-");
|
|
2389
|
+
if (!filteredToasts.length) return null;
|
|
2390
|
+
return /* @__PURE__ */ React__default.default.createElement("ol", {
|
|
2391
|
+
key: position2,
|
|
2392
|
+
dir: dir === "auto" ? getDocumentDirection() : dir,
|
|
2393
|
+
tabIndex: -1,
|
|
2394
|
+
ref: listRef,
|
|
2395
|
+
className,
|
|
2396
|
+
"data-sonner-toaster": true,
|
|
2397
|
+
"data-sonner-theme": actualTheme,
|
|
2398
|
+
"data-y-position": y,
|
|
2399
|
+
"data-x-position": x,
|
|
2400
|
+
style: {
|
|
2401
|
+
"--front-toast-height": `${((_heights_ = heights[0]) == null ? void 0 : _heights_.height) || 0}px`,
|
|
2402
|
+
"--width": `${TOAST_WIDTH}px`,
|
|
2403
|
+
"--gap": `${gap}px`,
|
|
2404
|
+
...style,
|
|
2405
|
+
...assignOffset(offset, mobileOffset)
|
|
2406
|
+
},
|
|
2407
|
+
onBlur: (event) => {
|
|
2408
|
+
if (isFocusWithinRef.current && !event.currentTarget.contains(event.relatedTarget)) {
|
|
2409
|
+
isFocusWithinRef.current = false;
|
|
2410
|
+
if (lastFocusedElementRef.current) {
|
|
2411
|
+
lastFocusedElementRef.current.focus({
|
|
2412
|
+
preventScroll: true
|
|
2413
|
+
});
|
|
2414
|
+
lastFocusedElementRef.current = null;
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
},
|
|
2418
|
+
onFocus: (event) => {
|
|
2419
|
+
const isNotDismissible = event.target instanceof HTMLElement && event.target.dataset.dismissible === "false";
|
|
2420
|
+
if (isNotDismissible) return;
|
|
2421
|
+
if (!isFocusWithinRef.current) {
|
|
2422
|
+
isFocusWithinRef.current = true;
|
|
2423
|
+
lastFocusedElementRef.current = event.relatedTarget;
|
|
2424
|
+
}
|
|
2425
|
+
},
|
|
2426
|
+
onMouseEnter: () => setExpanded(true),
|
|
2427
|
+
onMouseMove: () => setExpanded(true),
|
|
2428
|
+
onMouseLeave: () => {
|
|
2429
|
+
if (!interacting) {
|
|
2430
|
+
setExpanded(false);
|
|
2431
|
+
}
|
|
2432
|
+
},
|
|
2433
|
+
onDragEnd: () => setExpanded(false),
|
|
2434
|
+
onPointerDown: (event) => {
|
|
2435
|
+
const isNotDismissible = event.target instanceof HTMLElement && event.target.dataset.dismissible === "false";
|
|
2436
|
+
if (isNotDismissible) return;
|
|
2437
|
+
setInteracting(true);
|
|
2438
|
+
},
|
|
2439
|
+
onPointerUp: () => setInteracting(false)
|
|
2440
|
+
}, filteredToasts.filter((toast2) => !toast2.position && index === 0 || toast2.position === position2).map((toast2, index2) => {
|
|
2441
|
+
var _toastOptions_duration, _toastOptions_closeButton;
|
|
2442
|
+
return /* @__PURE__ */ React__default.default.createElement(Toast, {
|
|
2443
|
+
key: toast2.id,
|
|
2444
|
+
icons,
|
|
2445
|
+
index: index2,
|
|
2446
|
+
toast: toast2,
|
|
2447
|
+
defaultRichColors: richColors,
|
|
2448
|
+
duration: (_toastOptions_duration = toastOptions == null ? void 0 : toastOptions.duration) != null ? _toastOptions_duration : duration,
|
|
2449
|
+
className: toastOptions == null ? void 0 : toastOptions.className,
|
|
2450
|
+
descriptionClassName: toastOptions == null ? void 0 : toastOptions.descriptionClassName,
|
|
2451
|
+
invert,
|
|
2452
|
+
visibleToasts,
|
|
2453
|
+
closeButton: (_toastOptions_closeButton = toastOptions == null ? void 0 : toastOptions.closeButton) != null ? _toastOptions_closeButton : closeButton,
|
|
2454
|
+
interacting,
|
|
2455
|
+
position: position2,
|
|
2456
|
+
style: toastOptions == null ? void 0 : toastOptions.style,
|
|
2457
|
+
unstyled: toastOptions == null ? void 0 : toastOptions.unstyled,
|
|
2458
|
+
classNames: toastOptions == null ? void 0 : toastOptions.classNames,
|
|
2459
|
+
cancelButtonStyle: toastOptions == null ? void 0 : toastOptions.cancelButtonStyle,
|
|
2460
|
+
actionButtonStyle: toastOptions == null ? void 0 : toastOptions.actionButtonStyle,
|
|
2461
|
+
closeButtonAriaLabel: toastOptions == null ? void 0 : toastOptions.closeButtonAriaLabel,
|
|
2462
|
+
removeToast,
|
|
2463
|
+
toasts: filteredToasts.filter((t) => t.position == toast2.position),
|
|
2464
|
+
heights: heights.filter((h) => h.position == toast2.position),
|
|
2465
|
+
setHeights,
|
|
2466
|
+
expandByDefault: expand,
|
|
2467
|
+
gap,
|
|
2468
|
+
expanded,
|
|
2469
|
+
swipeDirections: props.swipeDirections
|
|
2470
|
+
});
|
|
2471
|
+
}));
|
|
2472
|
+
}))
|
|
2473
|
+
);
|
|
2474
|
+
});
|
|
1585
2475
|
function FunnelToaster(props = {}) {
|
|
1586
|
-
return
|
|
2476
|
+
return React.createElement(Toaster, { position: "top-center", ...props });
|
|
1587
2477
|
}
|
|
1588
2478
|
function renderToaster(toaster) {
|
|
1589
2479
|
if (toaster === false) return null;
|
|
1590
|
-
return
|
|
2480
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FunnelToaster, { ...toaster === true ? {} : toaster });
|
|
1591
2481
|
}
|
|
1592
2482
|
|
|
1593
2483
|
// src/state/namespaces.ts
|
|
@@ -1653,7 +2543,7 @@ function createFunnel(store, context, tracker, experiments = []) {
|
|
|
1653
2543
|
})
|
|
1654
2544
|
};
|
|
1655
2545
|
}
|
|
1656
|
-
var FunnelCtx =
|
|
2546
|
+
var FunnelCtx = React.createContext(null);
|
|
1657
2547
|
function FunnelProvider({
|
|
1658
2548
|
config,
|
|
1659
2549
|
sessionValues,
|
|
@@ -1669,7 +2559,7 @@ function FunnelProvider({
|
|
|
1669
2559
|
children
|
|
1670
2560
|
}) {
|
|
1671
2561
|
const resolvedTracker = tracker ?? FALLBACK_TRACKER;
|
|
1672
|
-
const [value] =
|
|
2562
|
+
const [value] = React.useState(() => {
|
|
1673
2563
|
const s = store ?? createFunnelStore(
|
|
1674
2564
|
{ responses: config?.responses, data: config?.data },
|
|
1675
2565
|
sessionValues
|
|
@@ -1686,44 +2576,51 @@ function FunnelProvider({
|
|
|
1686
2576
|
getVisitorId: () => ctx.identity.visitorId
|
|
1687
2577
|
});
|
|
1688
2578
|
const busTracker = withBus(resolvedTracker, bus);
|
|
2579
|
+
const emailForCheckout = () => {
|
|
2580
|
+
const value2 = s.get("user.email");
|
|
2581
|
+
return typeof value2 === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(value2) ? value2 : void 0;
|
|
2582
|
+
};
|
|
2583
|
+
const catalog = chunkJSRKA375_cjs.buildCatalog(products ?? []);
|
|
1689
2584
|
return {
|
|
1690
2585
|
funnel: createFunnel(s, ctx, busTracker, experiments ?? []),
|
|
1691
2586
|
store: s,
|
|
1692
2587
|
context: ctx,
|
|
1693
|
-
catalog
|
|
1694
|
-
driver
|
|
2588
|
+
catalog,
|
|
2589
|
+
// Slot → catalog-key resolution wraps the email-enriching driver, so the wire charges the real
|
|
2590
|
+
// catalog key while pages + analytics keep the durable SLOT identity (req.product).
|
|
2591
|
+
driver: driverWithCatalog(driverWithEmail(checkout ?? createMockDriver(), emailForCheckout), catalog),
|
|
1695
2592
|
tracker: busTracker,
|
|
1696
2593
|
bus
|
|
1697
2594
|
};
|
|
1698
2595
|
});
|
|
1699
|
-
|
|
1700
|
-
|
|
2596
|
+
React.useEffect(() => attachBus(value.bus), [value.bus]);
|
|
2597
|
+
React.useEffect(() => {
|
|
1701
2598
|
value.tracker.setAcquisition?.(buildAcquisition(value.context));
|
|
1702
2599
|
}, [value]);
|
|
1703
|
-
const tree =
|
|
2600
|
+
const tree = React.createElement(TrackerProvider, {
|
|
1704
2601
|
tracker: value.tracker,
|
|
1705
|
-
children:
|
|
2602
|
+
children: React.createElement(CheckoutDriverProvider, {
|
|
1706
2603
|
driver: value.driver,
|
|
1707
|
-
children:
|
|
2604
|
+
children: React.createElement(CatalogProvider, {
|
|
1708
2605
|
catalog: value.catalog,
|
|
1709
|
-
children:
|
|
2606
|
+
children: React.createElement(FunnelCtx.Provider, {
|
|
1710
2607
|
value,
|
|
1711
|
-
children:
|
|
2608
|
+
children: React.createElement(LocaleProvider, {
|
|
1712
2609
|
config: config?.locales,
|
|
1713
2610
|
catalog: messages,
|
|
1714
2611
|
detected: value.context.locale.locale,
|
|
1715
2612
|
override: localeOverride,
|
|
1716
|
-
children:
|
|
2613
|
+
children: React.createElement(ModalRuntime, { children })
|
|
1717
2614
|
})
|
|
1718
2615
|
})
|
|
1719
2616
|
})
|
|
1720
2617
|
})
|
|
1721
2618
|
});
|
|
1722
|
-
return
|
|
2619
|
+
return React.createElement(React.Fragment, null, tree, renderToaster(toaster));
|
|
1723
2620
|
}
|
|
1724
2621
|
var FALLBACK_TRACKER = createConsoleTracker({ silent: true });
|
|
1725
2622
|
function useFunnelCtx() {
|
|
1726
|
-
const ctx =
|
|
2623
|
+
const ctx = React.useContext(FunnelCtx);
|
|
1727
2624
|
if (!ctx) {
|
|
1728
2625
|
throw new Error("useFunnel/useResponse/\u2026 must be used inside <FunnelProvider>");
|
|
1729
2626
|
}
|
|
@@ -1733,18 +2630,18 @@ function useFunnel() {
|
|
|
1733
2630
|
return useFunnelCtx().funnel;
|
|
1734
2631
|
}
|
|
1735
2632
|
function useStoreKey(store, key) {
|
|
1736
|
-
const subscribe =
|
|
2633
|
+
const subscribe = React.useCallback(
|
|
1737
2634
|
(cb) => store.subscribe(cb, { keys: [key] }),
|
|
1738
2635
|
[store, key]
|
|
1739
2636
|
);
|
|
1740
|
-
const getSnapshot =
|
|
1741
|
-
return
|
|
2637
|
+
const getSnapshot = React.useCallback(() => store.get(key), [store, key]);
|
|
2638
|
+
return React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
1742
2639
|
}
|
|
1743
2640
|
function makeFieldHook(ns) {
|
|
1744
2641
|
return function useNamespaceField(key) {
|
|
1745
2642
|
const { funnel, store } = useFunnelCtx();
|
|
1746
2643
|
const value = useStoreKey(store, `${NAMESPACE_PREFIX[ns]}.${key}`);
|
|
1747
|
-
const set =
|
|
2644
|
+
const set = React.useCallback(
|
|
1748
2645
|
(v) => funnel[ns].set({ [key]: v }),
|
|
1749
2646
|
[funnel, key]
|
|
1750
2647
|
);
|
|
@@ -1763,7 +2660,7 @@ function useField(path) {
|
|
|
1763
2660
|
throw new Error(`useField: "${path}" is not a writable namespace (user/responses/data)`);
|
|
1764
2661
|
}
|
|
1765
2662
|
const value = useStoreKey(store, `${NAMESPACE_PREFIX[ns]}.${key}`);
|
|
1766
|
-
const set =
|
|
2663
|
+
const set = React.useCallback(
|
|
1767
2664
|
(v) => funnel[ns].set({ [key]: v }),
|
|
1768
2665
|
[funnel, ns, key]
|
|
1769
2666
|
);
|
|
@@ -1789,11 +2686,237 @@ function useSystem() {
|
|
|
1789
2686
|
}
|
|
1790
2687
|
function useContextValue(path) {
|
|
1791
2688
|
const ctx = useContextObject();
|
|
1792
|
-
return
|
|
2689
|
+
return React.useMemo(
|
|
1793
2690
|
() => path.split(".").reduce((acc, k) => acc?.[k], ctx),
|
|
1794
2691
|
[ctx, path]
|
|
1795
2692
|
);
|
|
1796
2693
|
}
|
|
2694
|
+
|
|
2695
|
+
// src/tracking/platformTracker.ts
|
|
2696
|
+
function validClickIds(acq) {
|
|
2697
|
+
return Object.entries(acq.clickIds ?? {}).filter(
|
|
2698
|
+
(e) => typeof e[1] === "string" && e[1] !== ""
|
|
2699
|
+
);
|
|
2700
|
+
}
|
|
2701
|
+
function acquisitionQueryBag(acq) {
|
|
2702
|
+
const q = {};
|
|
2703
|
+
const utm = acq.utm ?? {};
|
|
2704
|
+
for (const [k, v] of Object.entries({
|
|
2705
|
+
utm_source: utm.source,
|
|
2706
|
+
utm_medium: utm.medium,
|
|
2707
|
+
utm_campaign: utm.campaign,
|
|
2708
|
+
utm_term: utm.term,
|
|
2709
|
+
utm_content: utm.content
|
|
2710
|
+
})) if (v) q[k] = v;
|
|
2711
|
+
for (const [k, v] of validClickIds(acq)) q[k] = v;
|
|
2712
|
+
if (acq.cookies?.fbp) q._fbp = acq.cookies.fbp;
|
|
2713
|
+
if (acq.cookies?.fbc) q._fbc = acq.cookies.fbc;
|
|
2714
|
+
return q;
|
|
2715
|
+
}
|
|
2716
|
+
function acquisitionAdAttribution(acq) {
|
|
2717
|
+
const a = {};
|
|
2718
|
+
for (const [k, v] of validClickIds(acq)) a[k] = v;
|
|
2719
|
+
if (acq.cookies?.fbp) a.fbp = acq.cookies.fbp;
|
|
2720
|
+
if (acq.cookies?.fbc) a.fbc = acq.cookies.fbc;
|
|
2721
|
+
else if (acq.clickIds?.fbclid) a.fbc = `fb.1.${Date.now()}.${acq.clickIds.fbclid}`;
|
|
2722
|
+
return a;
|
|
2723
|
+
}
|
|
2724
|
+
function createPlatformTracker(cfg) {
|
|
2725
|
+
if (typeof window === "undefined" || cfg.mode === "test") return createConsoleTracker();
|
|
2726
|
+
const base = cfg.apiBase.replace(/\/+$/, "");
|
|
2727
|
+
const url = `${base}/campaign/${encodeURIComponent(cfg.campaignId)}/event`;
|
|
2728
|
+
const sidKey = `af_sid:${cfg.campaignId}`;
|
|
2729
|
+
let sessionId = null;
|
|
2730
|
+
try {
|
|
2731
|
+
sessionId = window.sessionStorage.getItem(sidKey);
|
|
2732
|
+
} catch {
|
|
2733
|
+
}
|
|
2734
|
+
if (!sessionId && cfg.sessionId) sessionId = cfg.sessionId;
|
|
2735
|
+
let acquisition = null;
|
|
2736
|
+
let acquisitionSent = false;
|
|
2737
|
+
let chain = Promise.resolve();
|
|
2738
|
+
const send = async (event, data, userData) => {
|
|
2739
|
+
let mergedUserData = userData;
|
|
2740
|
+
let adAttribution;
|
|
2741
|
+
let attachingAcquisition = false;
|
|
2742
|
+
if (acquisition && !acquisitionSent) {
|
|
2743
|
+
attachingAcquisition = true;
|
|
2744
|
+
const query = acquisitionQueryBag(acquisition);
|
|
2745
|
+
mergedUserData = Object.keys(query).length ? { ...userData, query } : userData;
|
|
2746
|
+
const ad = acquisitionAdAttribution(acquisition);
|
|
2747
|
+
if (Object.keys(ad).length) adAttribution = ad;
|
|
2748
|
+
}
|
|
2749
|
+
const body = {
|
|
2750
|
+
campaignId: cfg.campaignId,
|
|
2751
|
+
funnelId: cfg.funnelId,
|
|
2752
|
+
event,
|
|
2753
|
+
sessionId: sessionId ?? void 0,
|
|
2754
|
+
visitorId: cfg.visitorId ?? void 0,
|
|
2755
|
+
eventId: typeof data?.eventId === "string" ? data.eventId : void 0,
|
|
2756
|
+
data: data ?? {},
|
|
2757
|
+
metadata: {
|
|
2758
|
+
language: typeof navigator !== "undefined" ? navigator.language : void 0,
|
|
2759
|
+
screen: typeof window.screen !== "undefined" ? `${window.screen.width}x${window.screen.height}` : void 0,
|
|
2760
|
+
timezone: (() => {
|
|
2761
|
+
try {
|
|
2762
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
2763
|
+
} catch {
|
|
2764
|
+
return void 0;
|
|
2765
|
+
}
|
|
2766
|
+
})(),
|
|
2767
|
+
referrer: typeof document !== "undefined" && document.referrer ? document.referrer : void 0
|
|
2768
|
+
},
|
|
2769
|
+
...mergedUserData ? { userData: mergedUserData } : {},
|
|
2770
|
+
...adAttribution ? { adAttribution } : {}
|
|
2771
|
+
};
|
|
2772
|
+
const res = await fetch(url, {
|
|
2773
|
+
method: "POST",
|
|
2774
|
+
headers: { "content-type": "application/json" },
|
|
2775
|
+
body: JSON.stringify(body),
|
|
2776
|
+
keepalive: true
|
|
2777
|
+
// survives page.exit / unload
|
|
2778
|
+
});
|
|
2779
|
+
if (attachingAcquisition) acquisitionSent = true;
|
|
2780
|
+
const json = await res.json().catch(() => null);
|
|
2781
|
+
if (json?.sessionId && json.sessionId !== sessionId) {
|
|
2782
|
+
sessionId = json.sessionId;
|
|
2783
|
+
try {
|
|
2784
|
+
window.sessionStorage.setItem(sidKey, sessionId);
|
|
2785
|
+
} catch {
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
};
|
|
2789
|
+
const enqueue = (event, data, userData) => {
|
|
2790
|
+
const task = () => send(event, data, userData).catch((e) => {
|
|
2791
|
+
if (process.env.NODE_ENV !== "production") console.warn(`[appfunnel] track failed (${event}):`, e);
|
|
2792
|
+
});
|
|
2793
|
+
if (!sessionId) {
|
|
2794
|
+
chain = chain.then(task);
|
|
2795
|
+
} else {
|
|
2796
|
+
void task();
|
|
2797
|
+
}
|
|
2798
|
+
};
|
|
2799
|
+
const VARS_DEBOUNCE_MS = 800;
|
|
2800
|
+
let pendingVars = null;
|
|
2801
|
+
let varsTimer = null;
|
|
2802
|
+
const flushVars = () => {
|
|
2803
|
+
if (varsTimer) {
|
|
2804
|
+
clearTimeout(varsTimer);
|
|
2805
|
+
varsTimer = null;
|
|
2806
|
+
}
|
|
2807
|
+
if (!pendingVars) return;
|
|
2808
|
+
const doPost = () => {
|
|
2809
|
+
if (!pendingVars || !sessionId) return;
|
|
2810
|
+
const userData = pendingVars;
|
|
2811
|
+
pendingVars = null;
|
|
2812
|
+
void fetch(`${base}/campaign/${encodeURIComponent(cfg.campaignId)}/event/session/data`, {
|
|
2813
|
+
method: "POST",
|
|
2814
|
+
headers: { "content-type": "application/json" },
|
|
2815
|
+
body: JSON.stringify({ sessionId, userData }),
|
|
2816
|
+
keepalive: true
|
|
2817
|
+
}).catch((e) => {
|
|
2818
|
+
if (process.env.NODE_ENV !== "production") console.warn("[appfunnel] variable persist failed:", e);
|
|
2819
|
+
});
|
|
2820
|
+
};
|
|
2821
|
+
if (sessionId) doPost();
|
|
2822
|
+
else chain = chain.then(doPost);
|
|
2823
|
+
};
|
|
2824
|
+
try {
|
|
2825
|
+
window.addEventListener("pagehide", flushVars);
|
|
2826
|
+
} catch {
|
|
2827
|
+
}
|
|
2828
|
+
if (cfg.experiment?.id && cfg.experiment.variant) {
|
|
2829
|
+
enqueue("experiment.exposure", exposurePayload(cfg.experiment.id, cfg.experiment.variant, cfg.experiment.version));
|
|
2830
|
+
}
|
|
2831
|
+
return {
|
|
2832
|
+
track: (event, data, userData) => enqueue(event, data, userData),
|
|
2833
|
+
identify: (email, eventId) => enqueue("user.registered", { email, ...eventId ? { eventId } : {} }),
|
|
2834
|
+
setVariables: (variables) => {
|
|
2835
|
+
pendingVars = variables;
|
|
2836
|
+
if (varsTimer) clearTimeout(varsTimer);
|
|
2837
|
+
varsTimer = setTimeout(flushVars, VARS_DEBOUNCE_MS);
|
|
2838
|
+
},
|
|
2839
|
+
setAcquisition: (acq) => {
|
|
2840
|
+
acquisition = acq;
|
|
2841
|
+
}
|
|
2842
|
+
};
|
|
2843
|
+
}
|
|
2844
|
+
|
|
2845
|
+
// src/flow/mount.tsx
|
|
2846
|
+
var AssetsContext = React.createContext({});
|
|
2847
|
+
function AssetsProvider({
|
|
2848
|
+
assets,
|
|
2849
|
+
children
|
|
2850
|
+
}) {
|
|
2851
|
+
return React.createElement(AssetsContext.Provider, { value: assets ?? {} }, children);
|
|
2852
|
+
}
|
|
2853
|
+
function useAssets() {
|
|
2854
|
+
return React.useContext(AssetsContext);
|
|
2855
|
+
}
|
|
2856
|
+
function useAsset(name) {
|
|
2857
|
+
return React.useContext(AssetsContext)[name];
|
|
2858
|
+
}
|
|
2859
|
+
function createFunnelTree({
|
|
2860
|
+
config,
|
|
2861
|
+
pages,
|
|
2862
|
+
layout,
|
|
2863
|
+
checkoutDriver,
|
|
2864
|
+
messages
|
|
2865
|
+
}) {
|
|
2866
|
+
return function tree(opts) {
|
|
2867
|
+
const mode = opts.mode ?? "live";
|
|
2868
|
+
const tracker = opts.tracking ? createPlatformTracker({
|
|
2869
|
+
...opts.tracking,
|
|
2870
|
+
visitorId: opts.visitorId,
|
|
2871
|
+
sessionId: opts.sessionId,
|
|
2872
|
+
mode
|
|
2873
|
+
}) : void 0;
|
|
2874
|
+
const checkout = checkoutDriver && opts.tracking ? checkoutDriver({
|
|
2875
|
+
apiBase: opts.tracking.apiBase,
|
|
2876
|
+
campaignId: opts.tracking.campaignId,
|
|
2877
|
+
funnelId: opts.tracking.funnelId,
|
|
2878
|
+
mode,
|
|
2879
|
+
sessionId: opts.sessionId,
|
|
2880
|
+
visitorId: opts.visitorId
|
|
2881
|
+
}) : void 0;
|
|
2882
|
+
const layoutWithResume = function LayoutWithCheckoutResume({
|
|
2883
|
+
children
|
|
2884
|
+
}) {
|
|
2885
|
+
return React.createElement(
|
|
2886
|
+
React.Fragment,
|
|
2887
|
+
null,
|
|
2888
|
+
React.createElement(CheckoutResume, null),
|
|
2889
|
+
layout ? React.createElement(layout, null, children) : children
|
|
2890
|
+
);
|
|
2891
|
+
};
|
|
2892
|
+
return React.createElement(AssetsProvider, {
|
|
2893
|
+
assets: opts.assets,
|
|
2894
|
+
children: React.createElement(FunnelProvider, {
|
|
2895
|
+
config,
|
|
2896
|
+
products: opts.products ?? [],
|
|
2897
|
+
messages: opts.messages ?? messages,
|
|
2898
|
+
locale: opts.locale,
|
|
2899
|
+
tracker,
|
|
2900
|
+
checkout,
|
|
2901
|
+
sessionValues: opts.sessionValues,
|
|
2902
|
+
experiments: opts.experiments,
|
|
2903
|
+
context: {
|
|
2904
|
+
mode,
|
|
2905
|
+
visitorId: opts.visitorId ?? null,
|
|
2906
|
+
customerId: opts.customerId ?? null,
|
|
2907
|
+
sessionId: opts.sessionId ?? null
|
|
2908
|
+
},
|
|
2909
|
+
children: React.createElement(FunnelView, {
|
|
2910
|
+
pages,
|
|
2911
|
+
layout: layoutWithResume,
|
|
2912
|
+
initialKey: opts.initialKey,
|
|
2913
|
+
prefetch: "off"
|
|
2914
|
+
// renderer background-modulepreloads all chunks
|
|
2915
|
+
})
|
|
2916
|
+
})
|
|
2917
|
+
});
|
|
2918
|
+
};
|
|
2919
|
+
}
|
|
1797
2920
|
function Choice({
|
|
1798
2921
|
bind,
|
|
1799
2922
|
options,
|
|
@@ -1806,7 +2929,7 @@ function Choice({
|
|
|
1806
2929
|
return options.map((opt) => {
|
|
1807
2930
|
const o = typeof opt === "string" ? { value: opt } : opt;
|
|
1808
2931
|
const selected = value === o.value;
|
|
1809
|
-
return
|
|
2932
|
+
return React.createElement(
|
|
1810
2933
|
"button",
|
|
1811
2934
|
{
|
|
1812
2935
|
key: o.value,
|
|
@@ -1825,7 +2948,7 @@ function Choice({
|
|
|
1825
2948
|
}
|
|
1826
2949
|
function Next({ children, onClick, ...rest }) {
|
|
1827
2950
|
const { next } = useNavigation();
|
|
1828
|
-
return
|
|
2951
|
+
return React.createElement(
|
|
1829
2952
|
"button",
|
|
1830
2953
|
{
|
|
1831
2954
|
type: "button",
|
|
@@ -1841,7 +2964,7 @@ function Next({ children, onClick, ...rest }) {
|
|
|
1841
2964
|
function Back({ children, onClick, ...rest }) {
|
|
1842
2965
|
const { back, canGoBack } = useNavigation();
|
|
1843
2966
|
if (!canGoBack) return null;
|
|
1844
|
-
return
|
|
2967
|
+
return React.createElement(
|
|
1845
2968
|
"button",
|
|
1846
2969
|
{
|
|
1847
2970
|
type: "button",
|
|
@@ -1894,7 +3017,7 @@ function Script({
|
|
|
1894
3017
|
onLoad,
|
|
1895
3018
|
onError
|
|
1896
3019
|
}) {
|
|
1897
|
-
|
|
3020
|
+
React.useEffect(() => {
|
|
1898
3021
|
if (typeof document === "undefined") return;
|
|
1899
3022
|
const key = id ?? src;
|
|
1900
3023
|
if (injected.has(key)) {
|
|
@@ -1933,159 +3056,190 @@ function Script({
|
|
|
1933
3056
|
return null;
|
|
1934
3057
|
}
|
|
1935
3058
|
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
return
|
|
1939
|
-
}
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
function
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
|
|
2025
|
-
|
|
3059
|
+
Object.defineProperty(exports, "assignVariant", {
|
|
3060
|
+
enumerable: true,
|
|
3061
|
+
get: function () { return chunkJSRKA375_cjs.assignVariant; }
|
|
3062
|
+
});
|
|
3063
|
+
Object.defineProperty(exports, "bucketingSeed", {
|
|
3064
|
+
enumerable: true,
|
|
3065
|
+
get: function () { return chunkJSRKA375_cjs.bucketingSeed; }
|
|
3066
|
+
});
|
|
3067
|
+
Object.defineProperty(exports, "buildCatalog", {
|
|
3068
|
+
enumerable: true,
|
|
3069
|
+
get: function () { return chunkJSRKA375_cjs.buildCatalog; }
|
|
3070
|
+
});
|
|
3071
|
+
Object.defineProperty(exports, "compileManifest", {
|
|
3072
|
+
enumerable: true,
|
|
3073
|
+
get: function () { return chunkJSRKA375_cjs.compileManifest; }
|
|
3074
|
+
});
|
|
3075
|
+
Object.defineProperty(exports, "currencyExponent", {
|
|
3076
|
+
enumerable: true,
|
|
3077
|
+
get: function () { return chunkJSRKA375_cjs.currencyExponent; }
|
|
3078
|
+
});
|
|
3079
|
+
Object.defineProperty(exports, "defineFunnel", {
|
|
3080
|
+
enumerable: true,
|
|
3081
|
+
get: function () { return chunkJSRKA375_cjs.defineFunnel; }
|
|
3082
|
+
});
|
|
3083
|
+
Object.defineProperty(exports, "definePage", {
|
|
3084
|
+
enumerable: true,
|
|
3085
|
+
get: function () { return chunkJSRKA375_cjs.definePage; }
|
|
3086
|
+
});
|
|
3087
|
+
Object.defineProperty(exports, "entryGuard", {
|
|
3088
|
+
enumerable: true,
|
|
3089
|
+
get: function () { return chunkJSRKA375_cjs.entryGuard; }
|
|
3090
|
+
});
|
|
3091
|
+
Object.defineProperty(exports, "evaluateCondition", {
|
|
3092
|
+
enumerable: true,
|
|
3093
|
+
get: function () { return chunkJSRKA375_cjs.evaluateCondition; }
|
|
3094
|
+
});
|
|
3095
|
+
Object.defineProperty(exports, "evaluateGate", {
|
|
3096
|
+
enumerable: true,
|
|
3097
|
+
get: function () { return chunkJSRKA375_cjs.evaluateGate; }
|
|
3098
|
+
});
|
|
3099
|
+
Object.defineProperty(exports, "expectedPathLength", {
|
|
3100
|
+
enumerable: true,
|
|
3101
|
+
get: function () { return chunkJSRKA375_cjs.expectedPathLength; }
|
|
3102
|
+
});
|
|
3103
|
+
Object.defineProperty(exports, "fnv1a", {
|
|
3104
|
+
enumerable: true,
|
|
3105
|
+
get: function () { return chunkJSRKA375_cjs.fnv1a; }
|
|
3106
|
+
});
|
|
3107
|
+
Object.defineProperty(exports, "formatMoney", {
|
|
3108
|
+
enumerable: true,
|
|
3109
|
+
get: function () { return chunkJSRKA375_cjs.formatMoney; }
|
|
3110
|
+
});
|
|
3111
|
+
Object.defineProperty(exports, "formatProduct", {
|
|
3112
|
+
enumerable: true,
|
|
3113
|
+
get: function () { return chunkJSRKA375_cjs.formatProduct; }
|
|
3114
|
+
});
|
|
3115
|
+
Object.defineProperty(exports, "hashToUnit", {
|
|
3116
|
+
enumerable: true,
|
|
3117
|
+
get: function () { return chunkJSRKA375_cjs.hashToUnit; }
|
|
3118
|
+
});
|
|
3119
|
+
Object.defineProperty(exports, "isRtl", {
|
|
3120
|
+
enumerable: true,
|
|
3121
|
+
get: function () { return chunkJSRKA375_cjs.isRtl; }
|
|
3122
|
+
});
|
|
3123
|
+
Object.defineProperty(exports, "isVariantKey", {
|
|
3124
|
+
enumerable: true,
|
|
3125
|
+
get: function () { return chunkJSRKA375_cjs.isVariantKey; }
|
|
3126
|
+
});
|
|
3127
|
+
Object.defineProperty(exports, "nextPage", {
|
|
3128
|
+
enumerable: true,
|
|
3129
|
+
get: function () { return chunkJSRKA375_cjs.nextPage; }
|
|
3130
|
+
});
|
|
3131
|
+
Object.defineProperty(exports, "outgoingKeys", {
|
|
3132
|
+
enumerable: true,
|
|
3133
|
+
get: function () { return chunkJSRKA375_cjs.outgoingKeys; }
|
|
3134
|
+
});
|
|
3135
|
+
Object.defineProperty(exports, "pageMeta", {
|
|
3136
|
+
enumerable: true,
|
|
3137
|
+
get: function () { return chunkJSRKA375_cjs.pageMeta; }
|
|
3138
|
+
});
|
|
3139
|
+
Object.defineProperty(exports, "parseSlotKey", {
|
|
3140
|
+
enumerable: true,
|
|
3141
|
+
get: function () { return chunkJSRKA375_cjs.parseSlotKey; }
|
|
3142
|
+
});
|
|
3143
|
+
Object.defineProperty(exports, "pickByWeight", {
|
|
3144
|
+
enumerable: true,
|
|
3145
|
+
get: function () { return chunkJSRKA375_cjs.pickByWeight; }
|
|
3146
|
+
});
|
|
3147
|
+
Object.defineProperty(exports, "resolveExperiments", {
|
|
3148
|
+
enumerable: true,
|
|
3149
|
+
get: function () { return chunkJSRKA375_cjs.resolveExperiments; }
|
|
3150
|
+
});
|
|
3151
|
+
Object.defineProperty(exports, "resolveLocale", {
|
|
3152
|
+
enumerable: true,
|
|
3153
|
+
get: function () { return chunkJSRKA375_cjs.resolveLocale; }
|
|
3154
|
+
});
|
|
3155
|
+
Object.defineProperty(exports, "resolveProduct", {
|
|
3156
|
+
enumerable: true,
|
|
3157
|
+
get: function () { return chunkJSRKA375_cjs.resolveProduct; }
|
|
3158
|
+
});
|
|
3159
|
+
Object.defineProperty(exports, "resolveRoute", {
|
|
3160
|
+
enumerable: true,
|
|
3161
|
+
get: function () { return chunkJSRKA375_cjs.resolveRoute; }
|
|
3162
|
+
});
|
|
3163
|
+
Object.defineProperty(exports, "validateExperiments", {
|
|
3164
|
+
enumerable: true,
|
|
3165
|
+
get: function () { return chunkJSRKA375_cjs.validateExperiments; }
|
|
3166
|
+
});
|
|
3167
|
+
Object.defineProperty(exports, "INLINE_SURFACES", {
|
|
3168
|
+
enumerable: true,
|
|
3169
|
+
get: function () { return chunkLJYLGLFS_cjs.INLINE_SURFACES; }
|
|
3170
|
+
});
|
|
3171
|
+
Object.defineProperty(exports, "PROVIDER_PROFILES", {
|
|
3172
|
+
enumerable: true,
|
|
3173
|
+
get: function () { return chunkLJYLGLFS_cjs.PROVIDER_PROFILES; }
|
|
3174
|
+
});
|
|
3175
|
+
Object.defineProperty(exports, "checkoutError", {
|
|
3176
|
+
enumerable: true,
|
|
3177
|
+
get: function () { return chunkLJYLGLFS_cjs.checkoutError; }
|
|
3178
|
+
});
|
|
3179
|
+
Object.defineProperty(exports, "isInlineSurface", {
|
|
3180
|
+
enumerable: true,
|
|
3181
|
+
get: function () { return chunkLJYLGLFS_cjs.isInlineSurface; }
|
|
3182
|
+
});
|
|
3183
|
+
Object.defineProperty(exports, "isMerchantOfRecord", {
|
|
3184
|
+
enumerable: true,
|
|
3185
|
+
get: function () { return chunkLJYLGLFS_cjs.isMerchantOfRecord; }
|
|
3186
|
+
});
|
|
3187
|
+
Object.defineProperty(exports, "isOrchestrator", {
|
|
3188
|
+
enumerable: true,
|
|
3189
|
+
get: function () { return chunkLJYLGLFS_cjs.isOrchestrator; }
|
|
3190
|
+
});
|
|
3191
|
+
Object.defineProperty(exports, "surfacesFor", {
|
|
3192
|
+
enumerable: true,
|
|
3193
|
+
get: function () { return chunkLJYLGLFS_cjs.surfacesFor; }
|
|
3194
|
+
});
|
|
3195
|
+
Object.defineProperty(exports, "validateCheckout", {
|
|
3196
|
+
enumerable: true,
|
|
3197
|
+
get: function () { return chunkLJYLGLFS_cjs.validateCheckout; }
|
|
3198
|
+
});
|
|
3199
|
+
Object.defineProperty(exports, "validateUpsell", {
|
|
2026
3200
|
enumerable: true,
|
|
2027
|
-
get: function () { return
|
|
3201
|
+
get: function () { return chunkLJYLGLFS_cjs.validateUpsell; }
|
|
2028
3202
|
});
|
|
3203
|
+
exports.AssetsContext = AssetsContext;
|
|
3204
|
+
exports.AssetsProvider = AssetsProvider;
|
|
2029
3205
|
exports.Back = Back;
|
|
2030
3206
|
exports.Checkout = Checkout;
|
|
3207
|
+
exports.CheckoutResume = CheckoutResume;
|
|
2031
3208
|
exports.Choice = Choice;
|
|
2032
3209
|
exports.EVENT_CATALOG = EVENT_CATALOG;
|
|
2033
3210
|
exports.FunnelProvider = FunnelProvider;
|
|
2034
3211
|
exports.FunnelToaster = FunnelToaster;
|
|
2035
3212
|
exports.FunnelView = FunnelView;
|
|
2036
|
-
exports.INLINE_SURFACES = INLINE_SURFACES;
|
|
2037
3213
|
exports.Modal = Modal;
|
|
2038
3214
|
exports.Next = Next;
|
|
2039
|
-
exports.PROVIDER_PROFILES = PROVIDER_PROFILES;
|
|
2040
3215
|
exports.Script = Script;
|
|
2041
3216
|
exports.Sheet = Sheet;
|
|
2042
3217
|
exports.Upsell = Upsell;
|
|
2043
3218
|
exports.VariableStore = VariableStore;
|
|
2044
|
-
exports.assignVariant = assignVariant;
|
|
2045
3219
|
exports.attachBus = attachBus;
|
|
2046
|
-
exports.bucketingSeed = bucketingSeed;
|
|
2047
3220
|
exports.buildAcquisition = buildAcquisition;
|
|
2048
|
-
exports.
|
|
2049
|
-
exports.checkoutError = checkoutError;
|
|
2050
|
-
exports.compileManifest = compileManifest;
|
|
3221
|
+
exports.buildContext = buildContext;
|
|
2051
3222
|
exports.createBus = createBus;
|
|
2052
3223
|
exports.createConsoleTracker = createConsoleTracker;
|
|
2053
3224
|
exports.createFunnelStore = createFunnelStore;
|
|
3225
|
+
exports.createFunnelTree = createFunnelTree;
|
|
2054
3226
|
exports.createMockDriver = createMockDriver;
|
|
2055
|
-
exports.
|
|
3227
|
+
exports.createPlatformTracker = createPlatformTracker;
|
|
2056
3228
|
exports.defineModal = defineModal;
|
|
2057
|
-
exports.
|
|
2058
|
-
exports.entryGuard = entryGuard;
|
|
2059
|
-
exports.evaluateCondition = evaluateCondition;
|
|
2060
|
-
exports.evaluateGate = evaluateGate;
|
|
2061
|
-
exports.expectedPathLength = expectedPathLength;
|
|
2062
|
-
exports.fnv1a = fnv1a;
|
|
2063
|
-
exports.formatProduct = formatProduct;
|
|
2064
|
-
exports.hashToUnit = hashToUnit;
|
|
3229
|
+
exports.driverWithEmail = driverWithEmail;
|
|
2065
3230
|
exports.hideModal = hideModal;
|
|
2066
3231
|
exports.integrationEvents = integrationEvents;
|
|
2067
|
-
exports.isInlineSurface = isInlineSurface;
|
|
2068
3232
|
exports.isIntegrationEvent = isIntegrationEvent;
|
|
2069
|
-
exports.isMerchantOfRecord = isMerchantOfRecord;
|
|
2070
|
-
exports.isOrchestrator = isOrchestrator;
|
|
2071
|
-
exports.isRtl = isRtl;
|
|
2072
3233
|
exports.isTrackableEvent = isTrackableEvent;
|
|
2073
|
-
exports.isVariantKey = isVariantKey;
|
|
2074
3234
|
exports.newEventId = newEventId;
|
|
2075
|
-
exports.nextPage = nextPage;
|
|
2076
|
-
exports.outgoingKeys = outgoingKeys;
|
|
2077
|
-
exports.pageMeta = pageMeta;
|
|
2078
|
-
exports.parseSlotKey = parseSlotKey;
|
|
2079
|
-
exports.pickByWeight = pickByWeight;
|
|
2080
3235
|
exports.registerModal = registerModal;
|
|
2081
3236
|
exports.removeModal = removeModal;
|
|
2082
|
-
exports.resolveExperiments = resolveExperiments;
|
|
2083
|
-
exports.resolveLocale = resolveLocale;
|
|
2084
|
-
exports.resolveProduct = resolveProduct;
|
|
2085
|
-
exports.resolveRoute = resolveRoute;
|
|
2086
3237
|
exports.showModal = showModal;
|
|
2087
|
-
exports.
|
|
3238
|
+
exports.toast = toast;
|
|
2088
3239
|
exports.unregisterModal = unregisterModal;
|
|
3240
|
+
exports.useActiveLocale = useActiveLocale;
|
|
3241
|
+
exports.useAsset = useAsset;
|
|
3242
|
+
exports.useAssets = useAssets;
|
|
2089
3243
|
exports.useCheckout = useCheckout;
|
|
2090
3244
|
exports.useClickIds = useClickIds;
|
|
2091
3245
|
exports.useContextValue = useContextValue;
|
|
@@ -2106,9 +3260,6 @@ exports.useTracker = useTracker;
|
|
|
2106
3260
|
exports.useTranslation = useTranslation;
|
|
2107
3261
|
exports.useUserAttribute = useUserAttribute;
|
|
2108
3262
|
exports.useUtm = useUtm;
|
|
2109
|
-
exports.validateCheckout = validateCheckout;
|
|
2110
|
-
exports.validateExperiments = validateExperiments;
|
|
2111
|
-
exports.validateUpsell = validateUpsell;
|
|
2112
3263
|
exports.withBus = withBus;
|
|
2113
3264
|
//# sourceMappingURL=index.cjs.map
|
|
2114
3265
|
//# sourceMappingURL=index.cjs.map
|