@appfunnel-dev/sdk 2.0.0-canary.1 → 2.0.0-canary.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities-7_hy5f5G.d.cts +114 -0
- package/dist/capabilities-7_hy5f5G.d.ts +114 -0
- package/dist/checkout-CZmEvWfC.d.cts +317 -0
- package/dist/checkout-DiQvRT5q.d.ts +317 -0
- package/dist/chunk-7UC5VXOR.js +446 -0
- package/dist/chunk-7UC5VXOR.js.map +1 -0
- package/dist/chunk-LJYLGLFS.cjs +153 -0
- package/dist/chunk-LJYLGLFS.cjs.map +1 -0
- package/dist/chunk-UIR6TGEW.js +97 -0
- package/dist/chunk-UIR6TGEW.js.map +1 -0
- package/dist/chunk-VQOD2Z6Q.cjs +104 -0
- package/dist/chunk-VQOD2Z6Q.cjs.map +1 -0
- package/dist/chunk-YY375F2B.js +140 -0
- package/dist/chunk-YY375F2B.js.map +1 -0
- package/dist/chunk-Z3TWO2PW.cjs +475 -0
- package/dist/chunk-Z3TWO2PW.cjs.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 +1949 -811
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +175 -933
- package/dist/index.d.ts +175 -933
- package/dist/index.js +1669 -652
- package/dist/index.js.map +1 -1
- package/dist/manifest-DQThneiG.d.cts +777 -0
- package/dist/manifest-DQThneiG.d.ts +777 -0
- package/dist/manifest-entry.cjs +203 -0
- package/dist/manifest-entry.cjs.map +1 -0
- package/dist/manifest-entry.d.cts +184 -0
- package/dist/manifest-entry.d.ts +184 -0
- package/dist/manifest-entry.js +98 -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 chunkZ3TWO2PW_cjs = require('./chunk-Z3TWO2PW.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(() => chunkZ3TWO2PW_cjs.resolveLocale(config, detected, override));
|
|
456
|
+
React.useEffect(() => {
|
|
457
|
+
setLocale(chunkZ3TWO2PW_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: chunkZ3TWO2PW_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 ? chunkZ3TWO2PW_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) => chunkZ3TWO2PW_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 = chunkZ3TWO2PW_cjs.bucketingSeed(funnel.context);
|
|
638
|
+
const seed = seedRef.current;
|
|
639
|
+
const experiments = React.useMemo(
|
|
640
|
+
() => chunkZ3TWO2PW_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 = chunkZ3TWO2PW_cjs.entryGuard(page2?.meta);
|
|
660
|
+
const ok = page2 && (!guard || chunkZ3TWO2PW_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
|
+
() => chunkZ3TWO2PW_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 = chunkZ3TWO2PW_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(chunkZ3TWO2PW_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,66 @@ 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
|
-
var DriverContext =
|
|
1106
|
+
var DriverContext = React.createContext(null);
|
|
1418
1107
|
function CheckoutDriverProvider({
|
|
1419
1108
|
driver,
|
|
1420
1109
|
children
|
|
1421
1110
|
}) {
|
|
1422
|
-
return
|
|
1111
|
+
return React.createElement(DriverContext.Provider, { value: driver }, children);
|
|
1423
1112
|
}
|
|
1424
1113
|
function useDriver() {
|
|
1425
|
-
return
|
|
1114
|
+
return React.useContext(DriverContext) ?? FALLBACK_DRIVER;
|
|
1426
1115
|
}
|
|
1427
1116
|
var FALLBACK_DRIVER = createMockDriver();
|
|
1428
1117
|
function useCheckout(opts = {}) {
|
|
1429
1118
|
const driver = useDriver();
|
|
1430
1119
|
const tracker = useTrackerRef();
|
|
1431
1120
|
const nav = useNavigation();
|
|
1432
|
-
const [status, setStatus] =
|
|
1433
|
-
const [error, setError] =
|
|
1121
|
+
const [status, setStatus] = React.useState("idle");
|
|
1122
|
+
const [error, setError] = React.useState(null);
|
|
1434
1123
|
const intent = opts.intent ?? "purchase";
|
|
1435
1124
|
const kind = opts.kind;
|
|
1436
1125
|
const advance = opts.advanceOnSuccess ?? true;
|
|
1437
|
-
const
|
|
1126
|
+
const recovering = React.useRef(false);
|
|
1127
|
+
const failRef = React.useRef(() => {
|
|
1128
|
+
});
|
|
1129
|
+
const attemptRef = React.useRef(
|
|
1130
|
+
async () => ({ ok: false })
|
|
1131
|
+
);
|
|
1132
|
+
const succeed = React.useCallback(
|
|
1438
1133
|
(result) => {
|
|
1439
1134
|
setStatus("success");
|
|
1440
1135
|
tracker.track("purchase.complete", {
|
|
@@ -1448,21 +1143,9 @@ function useCheckout(opts = {}) {
|
|
|
1448
1143
|
},
|
|
1449
1144
|
[tracker, nav, advance, opts]
|
|
1450
1145
|
);
|
|
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(
|
|
1146
|
+
const succeedRef = React.useRef(succeed);
|
|
1147
|
+
succeedRef.current = succeed;
|
|
1148
|
+
const begin = React.useCallback(
|
|
1466
1149
|
(product, surface) => {
|
|
1467
1150
|
setStatus("loading");
|
|
1468
1151
|
setError(null);
|
|
@@ -1470,64 +1153,157 @@ function useCheckout(opts = {}) {
|
|
|
1470
1153
|
},
|
|
1471
1154
|
[tracker]
|
|
1472
1155
|
);
|
|
1473
|
-
const paymentAdded =
|
|
1474
|
-
const
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1156
|
+
const paymentAdded = React.useCallback(() => tracker.track("checkout.payment_added", {}), [tracker]);
|
|
1157
|
+
const hostInSheet = (surface) => surface === "sheet" || chunkLJYLGLFS_cjs.isInlineSurface(surface) && !!chunkLJYLGLFS_cjs.PROVIDER_PROFILES[driver.provider]?.surfaces.sheet;
|
|
1158
|
+
const startRecovery = (product, surface) => {
|
|
1159
|
+
recovering.current = true;
|
|
1160
|
+
if (hostInSheet(surface)) {
|
|
1161
|
+
begin(product, "sheet");
|
|
1162
|
+
void showModal(CheckoutSheet, {
|
|
1163
|
+
product,
|
|
1164
|
+
surface: "sheet",
|
|
1165
|
+
intent,
|
|
1166
|
+
kind,
|
|
1167
|
+
onSuccess: (r) => succeedRef.current(r),
|
|
1168
|
+
onError: (e) => failRef.current(e, product),
|
|
1169
|
+
onPaymentAdded: () => paymentAdded()
|
|
1170
|
+
});
|
|
1171
|
+
} else {
|
|
1172
|
+
void attemptRef.current(product, surface);
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
failRef.current = (err, product) => {
|
|
1176
|
+
setStatus(err.category === "authentication_required" ? "requires_action" : "error");
|
|
1177
|
+
setError(err);
|
|
1178
|
+
tracker.track("checkout.failed", {
|
|
1179
|
+
category: err.category,
|
|
1180
|
+
declineCode: err.declineCode,
|
|
1181
|
+
productId: product,
|
|
1182
|
+
intent
|
|
1183
|
+
});
|
|
1184
|
+
opts.onError?.(err);
|
|
1185
|
+
if (err.category === "canceled" && !opts.onFailed?.canceled) return;
|
|
1186
|
+
if (product && !recovering.current && opts.recoverySurface && err.category !== "canceled") {
|
|
1187
|
+
startRecovery(product, opts.recoverySurface);
|
|
1188
|
+
return;
|
|
1189
|
+
}
|
|
1190
|
+
let route = opts.onFailed?.[err.category] ?? (err.category === "canceled" ? void 0 : opts.onFailed?.default);
|
|
1191
|
+
if (route && typeof route === "object" && "fallback" in route && recovering.current) {
|
|
1192
|
+
const dflt = opts.onFailed?.default;
|
|
1193
|
+
route = dflt && dflt !== route && !(typeof dflt === "object" && "fallback" in dflt) ? dflt : void 0;
|
|
1194
|
+
}
|
|
1195
|
+
if (!route) return;
|
|
1196
|
+
if (typeof route === "function") route(err);
|
|
1197
|
+
else if ("go" in route) nav.go(route.go);
|
|
1198
|
+
else if ("modal" in route) {
|
|
1199
|
+
const props = {
|
|
1200
|
+
error: err,
|
|
1201
|
+
product,
|
|
1202
|
+
go: (pageKey) => nav.go(pageKey),
|
|
1203
|
+
retry: (surface) => {
|
|
1204
|
+
if (!product) return;
|
|
1205
|
+
recovering.current = true;
|
|
1206
|
+
if (!surface) {
|
|
1207
|
+
if (intent === "upsell") void attemptRef.current(product);
|
|
1208
|
+
else startRecovery(product, chunkLJYLGLFS_cjs.PROVIDER_PROFILES[driver.provider]?.surfaces.sheet ? "sheet" : "popup");
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
startRecovery(product, surface);
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
void showModal(route.modal, props);
|
|
1215
|
+
} else if ("fallback" in route) {
|
|
1216
|
+
if (product && !recovering.current) startRecovery(product, route.fallback);
|
|
1217
|
+
}
|
|
1218
|
+
};
|
|
1219
|
+
attemptRef.current = async (product, surface) => {
|
|
1220
|
+
begin(product, surface);
|
|
1221
|
+
try {
|
|
1222
|
+
const result = await driver.start({ product, intent, surface, kind });
|
|
1223
|
+
if (result.ok) succeedRef.current(result);
|
|
1224
|
+
else failRef.current(result.error ?? chunkLJYLGLFS_cjs.checkoutError("unknown", "Checkout failed"), product);
|
|
1225
|
+
return result;
|
|
1226
|
+
} catch (e) {
|
|
1227
|
+
const err = chunkLJYLGLFS_cjs.checkoutError("processing_error", e instanceof Error ? e.message : "Checkout failed");
|
|
1228
|
+
failRef.current(err, product);
|
|
1229
|
+
return { ok: false, error: err };
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
const open = React.useCallback(async (product, surface) => {
|
|
1233
|
+
recovering.current = false;
|
|
1234
|
+
return attemptRef.current(product, surface);
|
|
1235
|
+
}, []);
|
|
1236
|
+
const callbacksFor = React.useCallback(
|
|
1491
1237
|
(product, surface) => ({
|
|
1492
|
-
onStart: () =>
|
|
1493
|
-
|
|
1494
|
-
|
|
1238
|
+
onStart: () => {
|
|
1239
|
+
recovering.current = false;
|
|
1240
|
+
begin(product, surface);
|
|
1241
|
+
},
|
|
1242
|
+
onSuccess: (result) => succeedRef.current(result),
|
|
1243
|
+
onError: (err) => failRef.current(err, product),
|
|
1495
1244
|
onPaymentAdded: () => paymentAdded()
|
|
1496
1245
|
}),
|
|
1497
|
-
[begin,
|
|
1246
|
+
[begin, paymentAdded]
|
|
1498
1247
|
);
|
|
1499
|
-
const reset =
|
|
1248
|
+
const reset = React.useCallback(() => {
|
|
1249
|
+
recovering.current = false;
|
|
1500
1250
|
setStatus("idle");
|
|
1501
1251
|
setError(null);
|
|
1502
1252
|
}, []);
|
|
1503
1253
|
return { open, status, error, isLoading: status === "loading", reset, callbacksFor };
|
|
1504
1254
|
}
|
|
1505
|
-
var CheckoutSheet = defineModal(({ product, surface, intent, onSuccess, onError }) => {
|
|
1255
|
+
var CheckoutSheet = defineModal(({ product, surface, intent, kind, onSuccess, onError, onPaymentAdded }) => {
|
|
1506
1256
|
const driver = useDriver();
|
|
1507
1257
|
const modal = useModal();
|
|
1258
|
+
const resolved = React.useRef(false);
|
|
1259
|
+
const onErrorRef = React.useRef(onError);
|
|
1260
|
+
onErrorRef.current = onError;
|
|
1261
|
+
const hostable = !!driver.renderInline;
|
|
1262
|
+
React.useEffect(() => {
|
|
1263
|
+
if (!hostable) {
|
|
1264
|
+
resolved.current = true;
|
|
1265
|
+
onErrorRef.current(
|
|
1266
|
+
chunkLJYLGLFS_cjs.checkoutError("processing_error", "This checkout driver has no inline surface to host in the sheet")
|
|
1267
|
+
);
|
|
1268
|
+
void modal.hide();
|
|
1269
|
+
modal.remove();
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
return () => {
|
|
1273
|
+
if (!resolved.current) {
|
|
1274
|
+
onErrorRef.current(chunkLJYLGLFS_cjs.checkoutError("canceled", "Checkout was dismissed before completing"));
|
|
1275
|
+
}
|
|
1276
|
+
};
|
|
1277
|
+
}, []);
|
|
1508
1278
|
if (!driver.renderInline) return null;
|
|
1509
|
-
|
|
1279
|
+
const close = () => {
|
|
1280
|
+
resolved.current = true;
|
|
1281
|
+
void modal.hide();
|
|
1282
|
+
modal.remove();
|
|
1283
|
+
};
|
|
1284
|
+
return React.createElement(Sheet, {
|
|
1510
1285
|
children: driver.renderInline(
|
|
1511
|
-
{ product, intent, surface },
|
|
1286
|
+
{ product, intent, surface, kind },
|
|
1512
1287
|
{
|
|
1513
1288
|
onSuccess: (r) => {
|
|
1514
|
-
|
|
1289
|
+
close();
|
|
1515
1290
|
onSuccess(r);
|
|
1516
1291
|
},
|
|
1517
1292
|
onError: (e) => {
|
|
1518
|
-
|
|
1293
|
+
close();
|
|
1519
1294
|
onError(e);
|
|
1520
|
-
}
|
|
1295
|
+
},
|
|
1296
|
+
onPaymentAdded
|
|
1521
1297
|
}
|
|
1522
1298
|
)
|
|
1523
1299
|
});
|
|
1524
1300
|
});
|
|
1525
1301
|
function trigger(onClick, { asChild, children, className, disabled }) {
|
|
1526
|
-
if (asChild &&
|
|
1302
|
+
if (asChild && React.isValidElement(children)) {
|
|
1527
1303
|
const child = children;
|
|
1528
|
-
return
|
|
1304
|
+
return React.cloneElement(child, { onClick });
|
|
1529
1305
|
}
|
|
1530
|
-
return
|
|
1306
|
+
return React.createElement("button", { type: "button", className, disabled, onClick }, children ?? "Continue");
|
|
1531
1307
|
}
|
|
1532
1308
|
function Checkout({
|
|
1533
1309
|
product,
|
|
@@ -1540,8 +1316,8 @@ function Checkout({
|
|
|
1540
1316
|
const driver = useDriver();
|
|
1541
1317
|
const checkout = useCheckout(options);
|
|
1542
1318
|
const intent = options.intent ?? "purchase";
|
|
1543
|
-
if (isInlineSurface(surface)) {
|
|
1544
|
-
return driver.renderInline ?
|
|
1319
|
+
if (chunkLJYLGLFS_cjs.isInlineSurface(surface)) {
|
|
1320
|
+
return driver.renderInline ? React.createElement(
|
|
1545
1321
|
"div",
|
|
1546
1322
|
{ key: product, className },
|
|
1547
1323
|
driver.renderInline({ product, intent, surface }, checkout.callbacksFor(product, surface))
|
|
@@ -1551,7 +1327,15 @@ function Checkout({
|
|
|
1551
1327
|
const cb = checkout.callbacksFor(product, surface);
|
|
1552
1328
|
const open = () => {
|
|
1553
1329
|
cb.onStart();
|
|
1554
|
-
showModal(CheckoutSheet, {
|
|
1330
|
+
showModal(CheckoutSheet, {
|
|
1331
|
+
product,
|
|
1332
|
+
surface,
|
|
1333
|
+
intent,
|
|
1334
|
+
kind: options.kind,
|
|
1335
|
+
onSuccess: cb.onSuccess,
|
|
1336
|
+
onError: cb.onError,
|
|
1337
|
+
onPaymentAdded: cb.onPaymentAdded
|
|
1338
|
+
});
|
|
1555
1339
|
};
|
|
1556
1340
|
return trigger(open, { asChild, children, className, disabled: checkout.isLoading });
|
|
1557
1341
|
}
|
|
@@ -1563,31 +1347,1129 @@ function Checkout({
|
|
|
1563
1347
|
});
|
|
1564
1348
|
}
|
|
1565
1349
|
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, {
|
|
1350
|
+
const checkout = useCheckout({
|
|
1351
|
+
...options,
|
|
1352
|
+
intent: "upsell",
|
|
1353
|
+
recoverySurface: fallback ?? options.recoverySurface
|
|
1354
|
+
});
|
|
1355
|
+
return trigger(() => void checkout.open(product), {
|
|
1579
1356
|
asChild,
|
|
1580
1357
|
children: children ?? "Add to my plan",
|
|
1581
1358
|
className,
|
|
1582
1359
|
disabled: checkout.isLoading
|
|
1583
1360
|
});
|
|
1584
1361
|
}
|
|
1362
|
+
var consumedResumes = /* @__PURE__ */ new Set();
|
|
1363
|
+
function CheckoutResume(options = {}) {
|
|
1364
|
+
const driver = useDriver();
|
|
1365
|
+
const checkout = useCheckout(options);
|
|
1366
|
+
const callbacksRef = React.useRef(checkout.callbacksFor);
|
|
1367
|
+
callbacksRef.current = checkout.callbacksFor;
|
|
1368
|
+
React.useEffect(() => {
|
|
1369
|
+
if (typeof window === "undefined" || !driver.resume) return;
|
|
1370
|
+
const url = new URL(window.location.href);
|
|
1371
|
+
const correlationId = url.searchParams.get("af_checkout");
|
|
1372
|
+
if (!correlationId || consumedResumes.has(correlationId)) return;
|
|
1373
|
+
consumedResumes.add(correlationId);
|
|
1374
|
+
void driver.resume(correlationId).then((result) => {
|
|
1375
|
+
const cb = callbacksRef.current();
|
|
1376
|
+
if (result.ok) {
|
|
1377
|
+
url.searchParams.delete("af_checkout");
|
|
1378
|
+
window.history.replaceState(window.history.state, "", url.toString());
|
|
1379
|
+
cb.onSuccess(result);
|
|
1380
|
+
} else {
|
|
1381
|
+
cb.onError(result.error ?? chunkLJYLGLFS_cjs.checkoutError("unknown", "The checkout could not be verified"));
|
|
1382
|
+
}
|
|
1383
|
+
});
|
|
1384
|
+
}, []);
|
|
1385
|
+
return null;
|
|
1386
|
+
}
|
|
1387
|
+
function __insertCSS(code) {
|
|
1388
|
+
if (typeof document == "undefined") return;
|
|
1389
|
+
let head = document.head || document.getElementsByTagName("head")[0];
|
|
1390
|
+
let style = document.createElement("style");
|
|
1391
|
+
style.type = "text/css";
|
|
1392
|
+
head.appendChild(style);
|
|
1393
|
+
style.styleSheet ? style.styleSheet.cssText = code : style.appendChild(document.createTextNode(code));
|
|
1394
|
+
}
|
|
1395
|
+
var getAsset = (type) => {
|
|
1396
|
+
switch (type) {
|
|
1397
|
+
case "success":
|
|
1398
|
+
return SuccessIcon;
|
|
1399
|
+
case "info":
|
|
1400
|
+
return InfoIcon;
|
|
1401
|
+
case "warning":
|
|
1402
|
+
return WarningIcon;
|
|
1403
|
+
case "error":
|
|
1404
|
+
return ErrorIcon;
|
|
1405
|
+
default:
|
|
1406
|
+
return null;
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
var bars = Array(12).fill(0);
|
|
1410
|
+
var Loader = ({ visible, className }) => {
|
|
1411
|
+
return /* @__PURE__ */ React__default.default.createElement("div", {
|
|
1412
|
+
className: [
|
|
1413
|
+
"sonner-loading-wrapper",
|
|
1414
|
+
className
|
|
1415
|
+
].filter(Boolean).join(" "),
|
|
1416
|
+
"data-visible": visible
|
|
1417
|
+
}, /* @__PURE__ */ React__default.default.createElement("div", {
|
|
1418
|
+
className: "sonner-spinner"
|
|
1419
|
+
}, bars.map((_, i) => /* @__PURE__ */ React__default.default.createElement("div", {
|
|
1420
|
+
className: "sonner-loading-bar",
|
|
1421
|
+
key: `spinner-bar-${i}`
|
|
1422
|
+
}))));
|
|
1423
|
+
};
|
|
1424
|
+
var SuccessIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1425
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1426
|
+
viewBox: "0 0 20 20",
|
|
1427
|
+
fill: "currentColor",
|
|
1428
|
+
height: "20",
|
|
1429
|
+
width: "20"
|
|
1430
|
+
}, /* @__PURE__ */ React__default.default.createElement("path", {
|
|
1431
|
+
fillRule: "evenodd",
|
|
1432
|
+
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",
|
|
1433
|
+
clipRule: "evenodd"
|
|
1434
|
+
}));
|
|
1435
|
+
var WarningIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1436
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1437
|
+
viewBox: "0 0 24 24",
|
|
1438
|
+
fill: "currentColor",
|
|
1439
|
+
height: "20",
|
|
1440
|
+
width: "20"
|
|
1441
|
+
}, /* @__PURE__ */ React__default.default.createElement("path", {
|
|
1442
|
+
fillRule: "evenodd",
|
|
1443
|
+
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",
|
|
1444
|
+
clipRule: "evenodd"
|
|
1445
|
+
}));
|
|
1446
|
+
var InfoIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1447
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1448
|
+
viewBox: "0 0 20 20",
|
|
1449
|
+
fill: "currentColor",
|
|
1450
|
+
height: "20",
|
|
1451
|
+
width: "20"
|
|
1452
|
+
}, /* @__PURE__ */ React__default.default.createElement("path", {
|
|
1453
|
+
fillRule: "evenodd",
|
|
1454
|
+
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",
|
|
1455
|
+
clipRule: "evenodd"
|
|
1456
|
+
}));
|
|
1457
|
+
var ErrorIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1458
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1459
|
+
viewBox: "0 0 20 20",
|
|
1460
|
+
fill: "currentColor",
|
|
1461
|
+
height: "20",
|
|
1462
|
+
width: "20"
|
|
1463
|
+
}, /* @__PURE__ */ React__default.default.createElement("path", {
|
|
1464
|
+
fillRule: "evenodd",
|
|
1465
|
+
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",
|
|
1466
|
+
clipRule: "evenodd"
|
|
1467
|
+
}));
|
|
1468
|
+
var CloseIcon = /* @__PURE__ */ React__default.default.createElement("svg", {
|
|
1469
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1470
|
+
width: "12",
|
|
1471
|
+
height: "12",
|
|
1472
|
+
viewBox: "0 0 24 24",
|
|
1473
|
+
fill: "none",
|
|
1474
|
+
stroke: "currentColor",
|
|
1475
|
+
strokeWidth: "1.5",
|
|
1476
|
+
strokeLinecap: "round",
|
|
1477
|
+
strokeLinejoin: "round"
|
|
1478
|
+
}, /* @__PURE__ */ React__default.default.createElement("line", {
|
|
1479
|
+
x1: "18",
|
|
1480
|
+
y1: "6",
|
|
1481
|
+
x2: "6",
|
|
1482
|
+
y2: "18"
|
|
1483
|
+
}), /* @__PURE__ */ React__default.default.createElement("line", {
|
|
1484
|
+
x1: "6",
|
|
1485
|
+
y1: "6",
|
|
1486
|
+
x2: "18",
|
|
1487
|
+
y2: "18"
|
|
1488
|
+
}));
|
|
1489
|
+
var useIsDocumentHidden = () => {
|
|
1490
|
+
const [isDocumentHidden, setIsDocumentHidden] = React__default.default.useState(document.hidden);
|
|
1491
|
+
React__default.default.useEffect(() => {
|
|
1492
|
+
const callback = () => {
|
|
1493
|
+
setIsDocumentHidden(document.hidden);
|
|
1494
|
+
};
|
|
1495
|
+
document.addEventListener("visibilitychange", callback);
|
|
1496
|
+
return () => window.removeEventListener("visibilitychange", callback);
|
|
1497
|
+
}, []);
|
|
1498
|
+
return isDocumentHidden;
|
|
1499
|
+
};
|
|
1500
|
+
var toastsCounter = 1;
|
|
1501
|
+
var Observer = class {
|
|
1502
|
+
constructor() {
|
|
1503
|
+
this.subscribe = (subscriber) => {
|
|
1504
|
+
this.subscribers.push(subscriber);
|
|
1505
|
+
return () => {
|
|
1506
|
+
const index = this.subscribers.indexOf(subscriber);
|
|
1507
|
+
this.subscribers.splice(index, 1);
|
|
1508
|
+
};
|
|
1509
|
+
};
|
|
1510
|
+
this.publish = (data) => {
|
|
1511
|
+
this.subscribers.forEach((subscriber) => subscriber(data));
|
|
1512
|
+
};
|
|
1513
|
+
this.addToast = (data) => {
|
|
1514
|
+
this.publish(data);
|
|
1515
|
+
this.toasts = [
|
|
1516
|
+
...this.toasts,
|
|
1517
|
+
data
|
|
1518
|
+
];
|
|
1519
|
+
};
|
|
1520
|
+
this.create = (data) => {
|
|
1521
|
+
var _data_id;
|
|
1522
|
+
const { message, ...rest } = data;
|
|
1523
|
+
const id = typeof (data == null ? void 0 : data.id) === "number" || ((_data_id = data.id) == null ? void 0 : _data_id.length) > 0 ? data.id : toastsCounter++;
|
|
1524
|
+
const alreadyExists = this.toasts.find((toast2) => {
|
|
1525
|
+
return toast2.id === id;
|
|
1526
|
+
});
|
|
1527
|
+
const dismissible = data.dismissible === void 0 ? true : data.dismissible;
|
|
1528
|
+
if (this.dismissedToasts.has(id)) {
|
|
1529
|
+
this.dismissedToasts.delete(id);
|
|
1530
|
+
}
|
|
1531
|
+
if (alreadyExists) {
|
|
1532
|
+
this.toasts = this.toasts.map((toast2) => {
|
|
1533
|
+
if (toast2.id === id) {
|
|
1534
|
+
this.publish({
|
|
1535
|
+
...toast2,
|
|
1536
|
+
...data,
|
|
1537
|
+
id,
|
|
1538
|
+
title: message
|
|
1539
|
+
});
|
|
1540
|
+
return {
|
|
1541
|
+
...toast2,
|
|
1542
|
+
...data,
|
|
1543
|
+
id,
|
|
1544
|
+
dismissible,
|
|
1545
|
+
title: message
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1548
|
+
return toast2;
|
|
1549
|
+
});
|
|
1550
|
+
} else {
|
|
1551
|
+
this.addToast({
|
|
1552
|
+
title: message,
|
|
1553
|
+
...rest,
|
|
1554
|
+
dismissible,
|
|
1555
|
+
id
|
|
1556
|
+
});
|
|
1557
|
+
}
|
|
1558
|
+
return id;
|
|
1559
|
+
};
|
|
1560
|
+
this.dismiss = (id) => {
|
|
1561
|
+
if (id) {
|
|
1562
|
+
this.dismissedToasts.add(id);
|
|
1563
|
+
requestAnimationFrame(() => this.subscribers.forEach((subscriber) => subscriber({
|
|
1564
|
+
id,
|
|
1565
|
+
dismiss: true
|
|
1566
|
+
})));
|
|
1567
|
+
} else {
|
|
1568
|
+
this.toasts.forEach((toast2) => {
|
|
1569
|
+
this.subscribers.forEach((subscriber) => subscriber({
|
|
1570
|
+
id: toast2.id,
|
|
1571
|
+
dismiss: true
|
|
1572
|
+
}));
|
|
1573
|
+
});
|
|
1574
|
+
}
|
|
1575
|
+
return id;
|
|
1576
|
+
};
|
|
1577
|
+
this.message = (message, data) => {
|
|
1578
|
+
return this.create({
|
|
1579
|
+
...data,
|
|
1580
|
+
message
|
|
1581
|
+
});
|
|
1582
|
+
};
|
|
1583
|
+
this.error = (message, data) => {
|
|
1584
|
+
return this.create({
|
|
1585
|
+
...data,
|
|
1586
|
+
message,
|
|
1587
|
+
type: "error"
|
|
1588
|
+
});
|
|
1589
|
+
};
|
|
1590
|
+
this.success = (message, data) => {
|
|
1591
|
+
return this.create({
|
|
1592
|
+
...data,
|
|
1593
|
+
type: "success",
|
|
1594
|
+
message
|
|
1595
|
+
});
|
|
1596
|
+
};
|
|
1597
|
+
this.info = (message, data) => {
|
|
1598
|
+
return this.create({
|
|
1599
|
+
...data,
|
|
1600
|
+
type: "info",
|
|
1601
|
+
message
|
|
1602
|
+
});
|
|
1603
|
+
};
|
|
1604
|
+
this.warning = (message, data) => {
|
|
1605
|
+
return this.create({
|
|
1606
|
+
...data,
|
|
1607
|
+
type: "warning",
|
|
1608
|
+
message
|
|
1609
|
+
});
|
|
1610
|
+
};
|
|
1611
|
+
this.loading = (message, data) => {
|
|
1612
|
+
return this.create({
|
|
1613
|
+
...data,
|
|
1614
|
+
type: "loading",
|
|
1615
|
+
message
|
|
1616
|
+
});
|
|
1617
|
+
};
|
|
1618
|
+
this.promise = (promise, data) => {
|
|
1619
|
+
if (!data) {
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
let id = void 0;
|
|
1623
|
+
if (data.loading !== void 0) {
|
|
1624
|
+
id = this.create({
|
|
1625
|
+
...data,
|
|
1626
|
+
promise,
|
|
1627
|
+
type: "loading",
|
|
1628
|
+
message: data.loading,
|
|
1629
|
+
description: typeof data.description !== "function" ? data.description : void 0
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
const p = Promise.resolve(promise instanceof Function ? promise() : promise);
|
|
1633
|
+
let shouldDismiss = id !== void 0;
|
|
1634
|
+
let result;
|
|
1635
|
+
const originalPromise = p.then(async (response) => {
|
|
1636
|
+
result = [
|
|
1637
|
+
"resolve",
|
|
1638
|
+
response
|
|
1639
|
+
];
|
|
1640
|
+
const isReactElementResponse = React__default.default.isValidElement(response);
|
|
1641
|
+
if (isReactElementResponse) {
|
|
1642
|
+
shouldDismiss = false;
|
|
1643
|
+
this.create({
|
|
1644
|
+
id,
|
|
1645
|
+
type: "default",
|
|
1646
|
+
message: response
|
|
1647
|
+
});
|
|
1648
|
+
} else if (isHttpResponse(response) && !response.ok) {
|
|
1649
|
+
shouldDismiss = false;
|
|
1650
|
+
const promiseData = typeof data.error === "function" ? await data.error(`HTTP error! status: ${response.status}`) : data.error;
|
|
1651
|
+
const description = typeof data.description === "function" ? await data.description(`HTTP error! status: ${response.status}`) : data.description;
|
|
1652
|
+
const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
|
|
1653
|
+
const toastSettings = isExtendedResult ? promiseData : {
|
|
1654
|
+
message: promiseData
|
|
1655
|
+
};
|
|
1656
|
+
this.create({
|
|
1657
|
+
id,
|
|
1658
|
+
type: "error",
|
|
1659
|
+
description,
|
|
1660
|
+
...toastSettings
|
|
1661
|
+
});
|
|
1662
|
+
} else if (response instanceof Error) {
|
|
1663
|
+
shouldDismiss = false;
|
|
1664
|
+
const promiseData = typeof data.error === "function" ? await data.error(response) : data.error;
|
|
1665
|
+
const description = typeof data.description === "function" ? await data.description(response) : data.description;
|
|
1666
|
+
const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
|
|
1667
|
+
const toastSettings = isExtendedResult ? promiseData : {
|
|
1668
|
+
message: promiseData
|
|
1669
|
+
};
|
|
1670
|
+
this.create({
|
|
1671
|
+
id,
|
|
1672
|
+
type: "error",
|
|
1673
|
+
description,
|
|
1674
|
+
...toastSettings
|
|
1675
|
+
});
|
|
1676
|
+
} else if (data.success !== void 0) {
|
|
1677
|
+
shouldDismiss = false;
|
|
1678
|
+
const promiseData = typeof data.success === "function" ? await data.success(response) : data.success;
|
|
1679
|
+
const description = typeof data.description === "function" ? await data.description(response) : data.description;
|
|
1680
|
+
const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
|
|
1681
|
+
const toastSettings = isExtendedResult ? promiseData : {
|
|
1682
|
+
message: promiseData
|
|
1683
|
+
};
|
|
1684
|
+
this.create({
|
|
1685
|
+
id,
|
|
1686
|
+
type: "success",
|
|
1687
|
+
description,
|
|
1688
|
+
...toastSettings
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
}).catch(async (error) => {
|
|
1692
|
+
result = [
|
|
1693
|
+
"reject",
|
|
1694
|
+
error
|
|
1695
|
+
];
|
|
1696
|
+
if (data.error !== void 0) {
|
|
1697
|
+
shouldDismiss = false;
|
|
1698
|
+
const promiseData = typeof data.error === "function" ? await data.error(error) : data.error;
|
|
1699
|
+
const description = typeof data.description === "function" ? await data.description(error) : data.description;
|
|
1700
|
+
const isExtendedResult = typeof promiseData === "object" && !React__default.default.isValidElement(promiseData);
|
|
1701
|
+
const toastSettings = isExtendedResult ? promiseData : {
|
|
1702
|
+
message: promiseData
|
|
1703
|
+
};
|
|
1704
|
+
this.create({
|
|
1705
|
+
id,
|
|
1706
|
+
type: "error",
|
|
1707
|
+
description,
|
|
1708
|
+
...toastSettings
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
}).finally(() => {
|
|
1712
|
+
if (shouldDismiss) {
|
|
1713
|
+
this.dismiss(id);
|
|
1714
|
+
id = void 0;
|
|
1715
|
+
}
|
|
1716
|
+
data.finally == null ? void 0 : data.finally.call(data);
|
|
1717
|
+
});
|
|
1718
|
+
const unwrap = () => new Promise((resolve, reject) => originalPromise.then(() => result[0] === "reject" ? reject(result[1]) : resolve(result[1])).catch(reject));
|
|
1719
|
+
if (typeof id !== "string" && typeof id !== "number") {
|
|
1720
|
+
return {
|
|
1721
|
+
unwrap
|
|
1722
|
+
};
|
|
1723
|
+
} else {
|
|
1724
|
+
return Object.assign(id, {
|
|
1725
|
+
unwrap
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
this.custom = (jsx2, data) => {
|
|
1730
|
+
const id = (data == null ? void 0 : data.id) || toastsCounter++;
|
|
1731
|
+
this.create({
|
|
1732
|
+
jsx: jsx2(id),
|
|
1733
|
+
id,
|
|
1734
|
+
...data
|
|
1735
|
+
});
|
|
1736
|
+
return id;
|
|
1737
|
+
};
|
|
1738
|
+
this.getActiveToasts = () => {
|
|
1739
|
+
return this.toasts.filter((toast2) => !this.dismissedToasts.has(toast2.id));
|
|
1740
|
+
};
|
|
1741
|
+
this.subscribers = [];
|
|
1742
|
+
this.toasts = [];
|
|
1743
|
+
this.dismissedToasts = /* @__PURE__ */ new Set();
|
|
1744
|
+
}
|
|
1745
|
+
};
|
|
1746
|
+
var ToastState = new Observer();
|
|
1747
|
+
var toastFunction = (message, data) => {
|
|
1748
|
+
const id = (data == null ? void 0 : data.id) || toastsCounter++;
|
|
1749
|
+
ToastState.addToast({
|
|
1750
|
+
title: message,
|
|
1751
|
+
...data,
|
|
1752
|
+
id
|
|
1753
|
+
});
|
|
1754
|
+
return id;
|
|
1755
|
+
};
|
|
1756
|
+
var isHttpResponse = (data) => {
|
|
1757
|
+
return data && typeof data === "object" && "ok" in data && typeof data.ok === "boolean" && "status" in data && typeof data.status === "number";
|
|
1758
|
+
};
|
|
1759
|
+
var basicToast = toastFunction;
|
|
1760
|
+
var getHistory = () => ToastState.toasts;
|
|
1761
|
+
var getToasts = () => ToastState.getActiveToasts();
|
|
1762
|
+
var toast = Object.assign(basicToast, {
|
|
1763
|
+
success: ToastState.success,
|
|
1764
|
+
info: ToastState.info,
|
|
1765
|
+
warning: ToastState.warning,
|
|
1766
|
+
error: ToastState.error,
|
|
1767
|
+
custom: ToastState.custom,
|
|
1768
|
+
message: ToastState.message,
|
|
1769
|
+
promise: ToastState.promise,
|
|
1770
|
+
dismiss: ToastState.dismiss,
|
|
1771
|
+
loading: ToastState.loading
|
|
1772
|
+
}, {
|
|
1773
|
+
getHistory,
|
|
1774
|
+
getToasts
|
|
1775
|
+
});
|
|
1776
|
+
__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%)}");
|
|
1777
|
+
function isAction(action) {
|
|
1778
|
+
return action.label !== void 0;
|
|
1779
|
+
}
|
|
1780
|
+
var VISIBLE_TOASTS_AMOUNT = 3;
|
|
1781
|
+
var VIEWPORT_OFFSET = "24px";
|
|
1782
|
+
var MOBILE_VIEWPORT_OFFSET = "16px";
|
|
1783
|
+
var TOAST_LIFETIME = 4e3;
|
|
1784
|
+
var TOAST_WIDTH = 356;
|
|
1785
|
+
var GAP = 14;
|
|
1786
|
+
var SWIPE_THRESHOLD = 45;
|
|
1787
|
+
var TIME_BEFORE_UNMOUNT = 200;
|
|
1788
|
+
function cn(...classes) {
|
|
1789
|
+
return classes.filter(Boolean).join(" ");
|
|
1790
|
+
}
|
|
1791
|
+
function getDefaultSwipeDirections(position) {
|
|
1792
|
+
const [y, x] = position.split("-");
|
|
1793
|
+
const directions = [];
|
|
1794
|
+
if (y) {
|
|
1795
|
+
directions.push(y);
|
|
1796
|
+
}
|
|
1797
|
+
if (x) {
|
|
1798
|
+
directions.push(x);
|
|
1799
|
+
}
|
|
1800
|
+
return directions;
|
|
1801
|
+
}
|
|
1802
|
+
var Toast = (props) => {
|
|
1803
|
+
var _toast_classNames, _toast_classNames1, _toast_classNames2, _toast_classNames3, _toast_classNames4, _toast_classNames5, _toast_classNames6, _toast_classNames7, _toast_classNames8;
|
|
1804
|
+
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;
|
|
1805
|
+
const [swipeDirection, setSwipeDirection] = React__default.default.useState(null);
|
|
1806
|
+
const [swipeOutDirection, setSwipeOutDirection] = React__default.default.useState(null);
|
|
1807
|
+
const [mounted, setMounted] = React__default.default.useState(false);
|
|
1808
|
+
const [removed, setRemoved] = React__default.default.useState(false);
|
|
1809
|
+
const [swiping, setSwiping] = React__default.default.useState(false);
|
|
1810
|
+
const [swipeOut, setSwipeOut] = React__default.default.useState(false);
|
|
1811
|
+
const [isSwiped, setIsSwiped] = React__default.default.useState(false);
|
|
1812
|
+
const [offsetBeforeRemove, setOffsetBeforeRemove] = React__default.default.useState(0);
|
|
1813
|
+
const [initialHeight, setInitialHeight] = React__default.default.useState(0);
|
|
1814
|
+
const remainingTime = React__default.default.useRef(toast2.duration || durationFromToaster || TOAST_LIFETIME);
|
|
1815
|
+
const dragStartTime = React__default.default.useRef(null);
|
|
1816
|
+
const toastRef = React__default.default.useRef(null);
|
|
1817
|
+
const isFront = index === 0;
|
|
1818
|
+
const isVisible = index + 1 <= visibleToasts;
|
|
1819
|
+
const toastType = toast2.type;
|
|
1820
|
+
const dismissible = toast2.dismissible !== false;
|
|
1821
|
+
const toastClassname = toast2.className || "";
|
|
1822
|
+
const toastDescriptionClassname = toast2.descriptionClassName || "";
|
|
1823
|
+
const heightIndex = React__default.default.useMemo(() => heights.findIndex((height) => height.toastId === toast2.id) || 0, [
|
|
1824
|
+
heights,
|
|
1825
|
+
toast2.id
|
|
1826
|
+
]);
|
|
1827
|
+
const closeButton = React__default.default.useMemo(() => {
|
|
1828
|
+
var _toast_closeButton;
|
|
1829
|
+
return (_toast_closeButton = toast2.closeButton) != null ? _toast_closeButton : closeButtonFromToaster;
|
|
1830
|
+
}, [
|
|
1831
|
+
toast2.closeButton,
|
|
1832
|
+
closeButtonFromToaster
|
|
1833
|
+
]);
|
|
1834
|
+
const duration = React__default.default.useMemo(() => toast2.duration || durationFromToaster || TOAST_LIFETIME, [
|
|
1835
|
+
toast2.duration,
|
|
1836
|
+
durationFromToaster
|
|
1837
|
+
]);
|
|
1838
|
+
const closeTimerStartTimeRef = React__default.default.useRef(0);
|
|
1839
|
+
const offset = React__default.default.useRef(0);
|
|
1840
|
+
const lastCloseTimerStartTimeRef = React__default.default.useRef(0);
|
|
1841
|
+
const pointerStartRef = React__default.default.useRef(null);
|
|
1842
|
+
const [y, x] = position.split("-");
|
|
1843
|
+
const toastsHeightBefore = React__default.default.useMemo(() => {
|
|
1844
|
+
return heights.reduce((prev, curr, reducerIndex) => {
|
|
1845
|
+
if (reducerIndex >= heightIndex) {
|
|
1846
|
+
return prev;
|
|
1847
|
+
}
|
|
1848
|
+
return prev + curr.height;
|
|
1849
|
+
}, 0);
|
|
1850
|
+
}, [
|
|
1851
|
+
heights,
|
|
1852
|
+
heightIndex
|
|
1853
|
+
]);
|
|
1854
|
+
const isDocumentHidden = useIsDocumentHidden();
|
|
1855
|
+
const invert = toast2.invert || ToasterInvert;
|
|
1856
|
+
const disabled = toastType === "loading";
|
|
1857
|
+
offset.current = React__default.default.useMemo(() => heightIndex * gap + toastsHeightBefore, [
|
|
1858
|
+
heightIndex,
|
|
1859
|
+
toastsHeightBefore
|
|
1860
|
+
]);
|
|
1861
|
+
React__default.default.useEffect(() => {
|
|
1862
|
+
remainingTime.current = duration;
|
|
1863
|
+
}, [
|
|
1864
|
+
duration
|
|
1865
|
+
]);
|
|
1866
|
+
React__default.default.useEffect(() => {
|
|
1867
|
+
setMounted(true);
|
|
1868
|
+
}, []);
|
|
1869
|
+
React__default.default.useEffect(() => {
|
|
1870
|
+
const toastNode = toastRef.current;
|
|
1871
|
+
if (toastNode) {
|
|
1872
|
+
const height = toastNode.getBoundingClientRect().height;
|
|
1873
|
+
setInitialHeight(height);
|
|
1874
|
+
setHeights((h) => [
|
|
1875
|
+
{
|
|
1876
|
+
toastId: toast2.id,
|
|
1877
|
+
height,
|
|
1878
|
+
position: toast2.position
|
|
1879
|
+
},
|
|
1880
|
+
...h
|
|
1881
|
+
]);
|
|
1882
|
+
return () => setHeights((h) => h.filter((height2) => height2.toastId !== toast2.id));
|
|
1883
|
+
}
|
|
1884
|
+
}, [
|
|
1885
|
+
setHeights,
|
|
1886
|
+
toast2.id
|
|
1887
|
+
]);
|
|
1888
|
+
React__default.default.useLayoutEffect(() => {
|
|
1889
|
+
if (!mounted) return;
|
|
1890
|
+
const toastNode = toastRef.current;
|
|
1891
|
+
const originalHeight = toastNode.style.height;
|
|
1892
|
+
toastNode.style.height = "auto";
|
|
1893
|
+
const newHeight = toastNode.getBoundingClientRect().height;
|
|
1894
|
+
toastNode.style.height = originalHeight;
|
|
1895
|
+
setInitialHeight(newHeight);
|
|
1896
|
+
setHeights((heights2) => {
|
|
1897
|
+
const alreadyExists = heights2.find((height) => height.toastId === toast2.id);
|
|
1898
|
+
if (!alreadyExists) {
|
|
1899
|
+
return [
|
|
1900
|
+
{
|
|
1901
|
+
toastId: toast2.id,
|
|
1902
|
+
height: newHeight,
|
|
1903
|
+
position: toast2.position
|
|
1904
|
+
},
|
|
1905
|
+
...heights2
|
|
1906
|
+
];
|
|
1907
|
+
} else {
|
|
1908
|
+
return heights2.map((height) => height.toastId === toast2.id ? {
|
|
1909
|
+
...height,
|
|
1910
|
+
height: newHeight
|
|
1911
|
+
} : height);
|
|
1912
|
+
}
|
|
1913
|
+
});
|
|
1914
|
+
}, [
|
|
1915
|
+
mounted,
|
|
1916
|
+
toast2.title,
|
|
1917
|
+
toast2.description,
|
|
1918
|
+
setHeights,
|
|
1919
|
+
toast2.id,
|
|
1920
|
+
toast2.jsx,
|
|
1921
|
+
toast2.action,
|
|
1922
|
+
toast2.cancel
|
|
1923
|
+
]);
|
|
1924
|
+
const deleteToast = React__default.default.useCallback(() => {
|
|
1925
|
+
setRemoved(true);
|
|
1926
|
+
setOffsetBeforeRemove(offset.current);
|
|
1927
|
+
setHeights((h) => h.filter((height) => height.toastId !== toast2.id));
|
|
1928
|
+
setTimeout(() => {
|
|
1929
|
+
removeToast(toast2);
|
|
1930
|
+
}, TIME_BEFORE_UNMOUNT);
|
|
1931
|
+
}, [
|
|
1932
|
+
toast2,
|
|
1933
|
+
removeToast,
|
|
1934
|
+
setHeights,
|
|
1935
|
+
offset
|
|
1936
|
+
]);
|
|
1937
|
+
React__default.default.useEffect(() => {
|
|
1938
|
+
if (toast2.promise && toastType === "loading" || toast2.duration === Infinity || toast2.type === "loading") return;
|
|
1939
|
+
let timeoutId;
|
|
1940
|
+
const pauseTimer = () => {
|
|
1941
|
+
if (lastCloseTimerStartTimeRef.current < closeTimerStartTimeRef.current) {
|
|
1942
|
+
const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - closeTimerStartTimeRef.current;
|
|
1943
|
+
remainingTime.current = remainingTime.current - elapsedTime;
|
|
1944
|
+
}
|
|
1945
|
+
lastCloseTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime();
|
|
1946
|
+
};
|
|
1947
|
+
const startTimer = () => {
|
|
1948
|
+
if (remainingTime.current === Infinity) return;
|
|
1949
|
+
closeTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime();
|
|
1950
|
+
timeoutId = setTimeout(() => {
|
|
1951
|
+
toast2.onAutoClose == null ? void 0 : toast2.onAutoClose.call(toast2, toast2);
|
|
1952
|
+
deleteToast();
|
|
1953
|
+
}, remainingTime.current);
|
|
1954
|
+
};
|
|
1955
|
+
if (expanded || interacting || isDocumentHidden) {
|
|
1956
|
+
pauseTimer();
|
|
1957
|
+
} else {
|
|
1958
|
+
startTimer();
|
|
1959
|
+
}
|
|
1960
|
+
return () => clearTimeout(timeoutId);
|
|
1961
|
+
}, [
|
|
1962
|
+
expanded,
|
|
1963
|
+
interacting,
|
|
1964
|
+
toast2,
|
|
1965
|
+
toastType,
|
|
1966
|
+
isDocumentHidden,
|
|
1967
|
+
deleteToast
|
|
1968
|
+
]);
|
|
1969
|
+
React__default.default.useEffect(() => {
|
|
1970
|
+
if (toast2.delete) {
|
|
1971
|
+
deleteToast();
|
|
1972
|
+
toast2.onDismiss == null ? void 0 : toast2.onDismiss.call(toast2, toast2);
|
|
1973
|
+
}
|
|
1974
|
+
}, [
|
|
1975
|
+
deleteToast,
|
|
1976
|
+
toast2.delete
|
|
1977
|
+
]);
|
|
1978
|
+
function getLoadingIcon() {
|
|
1979
|
+
var _toast_classNames9;
|
|
1980
|
+
if (icons == null ? void 0 : icons.loading) {
|
|
1981
|
+
var _toast_classNames12;
|
|
1982
|
+
return /* @__PURE__ */ React__default.default.createElement("div", {
|
|
1983
|
+
className: cn(classNames == null ? void 0 : classNames.loader, toast2 == null ? void 0 : (_toast_classNames12 = toast2.classNames) == null ? void 0 : _toast_classNames12.loader, "sonner-loader"),
|
|
1984
|
+
"data-visible": toastType === "loading"
|
|
1985
|
+
}, icons.loading);
|
|
1986
|
+
}
|
|
1987
|
+
return /* @__PURE__ */ React__default.default.createElement(Loader, {
|
|
1988
|
+
className: cn(classNames == null ? void 0 : classNames.loader, toast2 == null ? void 0 : (_toast_classNames9 = toast2.classNames) == null ? void 0 : _toast_classNames9.loader),
|
|
1989
|
+
visible: toastType === "loading"
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
const icon = toast2.icon || (icons == null ? void 0 : icons[toastType]) || getAsset(toastType);
|
|
1993
|
+
var _toast_richColors, _icons_close;
|
|
1994
|
+
return /* @__PURE__ */ React__default.default.createElement("li", {
|
|
1995
|
+
tabIndex: 0,
|
|
1996
|
+
ref: toastRef,
|
|
1997
|
+
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]),
|
|
1998
|
+
"data-sonner-toast": "",
|
|
1999
|
+
"data-rich-colors": (_toast_richColors = toast2.richColors) != null ? _toast_richColors : defaultRichColors,
|
|
2000
|
+
"data-styled": !Boolean(toast2.jsx || toast2.unstyled || unstyled),
|
|
2001
|
+
"data-mounted": mounted,
|
|
2002
|
+
"data-promise": Boolean(toast2.promise),
|
|
2003
|
+
"data-swiped": isSwiped,
|
|
2004
|
+
"data-removed": removed,
|
|
2005
|
+
"data-visible": isVisible,
|
|
2006
|
+
"data-y-position": y,
|
|
2007
|
+
"data-x-position": x,
|
|
2008
|
+
"data-index": index,
|
|
2009
|
+
"data-front": isFront,
|
|
2010
|
+
"data-swiping": swiping,
|
|
2011
|
+
"data-dismissible": dismissible,
|
|
2012
|
+
"data-type": toastType,
|
|
2013
|
+
"data-invert": invert,
|
|
2014
|
+
"data-swipe-out": swipeOut,
|
|
2015
|
+
"data-swipe-direction": swipeOutDirection,
|
|
2016
|
+
"data-expanded": Boolean(expanded || expandByDefault && mounted),
|
|
2017
|
+
"data-testid": toast2.testId,
|
|
2018
|
+
style: {
|
|
2019
|
+
"--index": index,
|
|
2020
|
+
"--toasts-before": index,
|
|
2021
|
+
"--z-index": toasts.length - index,
|
|
2022
|
+
"--offset": `${removed ? offsetBeforeRemove : offset.current}px`,
|
|
2023
|
+
"--initial-height": expandByDefault ? "auto" : `${initialHeight}px`,
|
|
2024
|
+
...style,
|
|
2025
|
+
...toast2.style
|
|
2026
|
+
},
|
|
2027
|
+
onDragEnd: () => {
|
|
2028
|
+
setSwiping(false);
|
|
2029
|
+
setSwipeDirection(null);
|
|
2030
|
+
pointerStartRef.current = null;
|
|
2031
|
+
},
|
|
2032
|
+
onPointerDown: (event) => {
|
|
2033
|
+
if (event.button === 2) return;
|
|
2034
|
+
if (disabled || !dismissible) return;
|
|
2035
|
+
dragStartTime.current = /* @__PURE__ */ new Date();
|
|
2036
|
+
setOffsetBeforeRemove(offset.current);
|
|
2037
|
+
event.target.setPointerCapture(event.pointerId);
|
|
2038
|
+
if (event.target.tagName === "BUTTON") return;
|
|
2039
|
+
setSwiping(true);
|
|
2040
|
+
pointerStartRef.current = {
|
|
2041
|
+
x: event.clientX,
|
|
2042
|
+
y: event.clientY
|
|
2043
|
+
};
|
|
2044
|
+
},
|
|
2045
|
+
onPointerUp: () => {
|
|
2046
|
+
var _toastRef_current, _toastRef_current1, _dragStartTime_current;
|
|
2047
|
+
if (swipeOut || !dismissible) return;
|
|
2048
|
+
pointerStartRef.current = null;
|
|
2049
|
+
const swipeAmountX = Number(((_toastRef_current = toastRef.current) == null ? void 0 : _toastRef_current.style.getPropertyValue("--swipe-amount-x").replace("px", "")) || 0);
|
|
2050
|
+
const swipeAmountY = Number(((_toastRef_current1 = toastRef.current) == null ? void 0 : _toastRef_current1.style.getPropertyValue("--swipe-amount-y").replace("px", "")) || 0);
|
|
2051
|
+
const timeTaken = (/* @__PURE__ */ new Date()).getTime() - ((_dragStartTime_current = dragStartTime.current) == null ? void 0 : _dragStartTime_current.getTime());
|
|
2052
|
+
const swipeAmount = swipeDirection === "x" ? swipeAmountX : swipeAmountY;
|
|
2053
|
+
const velocity = Math.abs(swipeAmount) / timeTaken;
|
|
2054
|
+
if (Math.abs(swipeAmount) >= SWIPE_THRESHOLD || velocity > 0.11) {
|
|
2055
|
+
setOffsetBeforeRemove(offset.current);
|
|
2056
|
+
toast2.onDismiss == null ? void 0 : toast2.onDismiss.call(toast2, toast2);
|
|
2057
|
+
if (swipeDirection === "x") {
|
|
2058
|
+
setSwipeOutDirection(swipeAmountX > 0 ? "right" : "left");
|
|
2059
|
+
} else {
|
|
2060
|
+
setSwipeOutDirection(swipeAmountY > 0 ? "down" : "up");
|
|
2061
|
+
}
|
|
2062
|
+
deleteToast();
|
|
2063
|
+
setSwipeOut(true);
|
|
2064
|
+
return;
|
|
2065
|
+
} else {
|
|
2066
|
+
var _toastRef_current2, _toastRef_current3;
|
|
2067
|
+
(_toastRef_current2 = toastRef.current) == null ? void 0 : _toastRef_current2.style.setProperty("--swipe-amount-x", `0px`);
|
|
2068
|
+
(_toastRef_current3 = toastRef.current) == null ? void 0 : _toastRef_current3.style.setProperty("--swipe-amount-y", `0px`);
|
|
2069
|
+
}
|
|
2070
|
+
setIsSwiped(false);
|
|
2071
|
+
setSwiping(false);
|
|
2072
|
+
setSwipeDirection(null);
|
|
2073
|
+
},
|
|
2074
|
+
onPointerMove: (event) => {
|
|
2075
|
+
var _window_getSelection, _toastRef_current, _toastRef_current1;
|
|
2076
|
+
if (!pointerStartRef.current || !dismissible) return;
|
|
2077
|
+
const isHighlighted = ((_window_getSelection = window.getSelection()) == null ? void 0 : _window_getSelection.toString().length) > 0;
|
|
2078
|
+
if (isHighlighted) return;
|
|
2079
|
+
const yDelta = event.clientY - pointerStartRef.current.y;
|
|
2080
|
+
const xDelta = event.clientX - pointerStartRef.current.x;
|
|
2081
|
+
var _props_swipeDirections;
|
|
2082
|
+
const swipeDirections = (_props_swipeDirections = props.swipeDirections) != null ? _props_swipeDirections : getDefaultSwipeDirections(position);
|
|
2083
|
+
if (!swipeDirection && (Math.abs(xDelta) > 1 || Math.abs(yDelta) > 1)) {
|
|
2084
|
+
setSwipeDirection(Math.abs(xDelta) > Math.abs(yDelta) ? "x" : "y");
|
|
2085
|
+
}
|
|
2086
|
+
let swipeAmount = {
|
|
2087
|
+
x: 0,
|
|
2088
|
+
y: 0
|
|
2089
|
+
};
|
|
2090
|
+
const getDampening = (delta) => {
|
|
2091
|
+
const factor = Math.abs(delta) / 20;
|
|
2092
|
+
return 1 / (1.5 + factor);
|
|
2093
|
+
};
|
|
2094
|
+
if (swipeDirection === "y") {
|
|
2095
|
+
if (swipeDirections.includes("top") || swipeDirections.includes("bottom")) {
|
|
2096
|
+
if (swipeDirections.includes("top") && yDelta < 0 || swipeDirections.includes("bottom") && yDelta > 0) {
|
|
2097
|
+
swipeAmount.y = yDelta;
|
|
2098
|
+
} else {
|
|
2099
|
+
const dampenedDelta = yDelta * getDampening(yDelta);
|
|
2100
|
+
swipeAmount.y = Math.abs(dampenedDelta) < Math.abs(yDelta) ? dampenedDelta : yDelta;
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
} else if (swipeDirection === "x") {
|
|
2104
|
+
if (swipeDirections.includes("left") || swipeDirections.includes("right")) {
|
|
2105
|
+
if (swipeDirections.includes("left") && xDelta < 0 || swipeDirections.includes("right") && xDelta > 0) {
|
|
2106
|
+
swipeAmount.x = xDelta;
|
|
2107
|
+
} else {
|
|
2108
|
+
const dampenedDelta = xDelta * getDampening(xDelta);
|
|
2109
|
+
swipeAmount.x = Math.abs(dampenedDelta) < Math.abs(xDelta) ? dampenedDelta : xDelta;
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
if (Math.abs(swipeAmount.x) > 0 || Math.abs(swipeAmount.y) > 0) {
|
|
2114
|
+
setIsSwiped(true);
|
|
2115
|
+
}
|
|
2116
|
+
(_toastRef_current = toastRef.current) == null ? void 0 : _toastRef_current.style.setProperty("--swipe-amount-x", `${swipeAmount.x}px`);
|
|
2117
|
+
(_toastRef_current1 = toastRef.current) == null ? void 0 : _toastRef_current1.style.setProperty("--swipe-amount-y", `${swipeAmount.y}px`);
|
|
2118
|
+
}
|
|
2119
|
+
}, closeButton && !toast2.jsx && toastType !== "loading" ? /* @__PURE__ */ React__default.default.createElement("button", {
|
|
2120
|
+
"aria-label": closeButtonAriaLabel,
|
|
2121
|
+
"data-disabled": disabled,
|
|
2122
|
+
"data-close-button": true,
|
|
2123
|
+
onClick: disabled || !dismissible ? () => {
|
|
2124
|
+
} : () => {
|
|
2125
|
+
deleteToast();
|
|
2126
|
+
toast2.onDismiss == null ? void 0 : toast2.onDismiss.call(toast2, toast2);
|
|
2127
|
+
},
|
|
2128
|
+
className: cn(classNames == null ? void 0 : classNames.closeButton, toast2 == null ? void 0 : (_toast_classNames2 = toast2.classNames) == null ? void 0 : _toast_classNames2.closeButton)
|
|
2129
|
+
}, (_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", {
|
|
2130
|
+
"data-icon": "",
|
|
2131
|
+
className: cn(classNames == null ? void 0 : classNames.icon, toast2 == null ? void 0 : (_toast_classNames3 = toast2.classNames) == null ? void 0 : _toast_classNames3.icon)
|
|
2132
|
+
}, toast2.promise || toast2.type === "loading" && !toast2.icon ? toast2.icon || getLoadingIcon() : null, toast2.type !== "loading" ? icon : null) : null, /* @__PURE__ */ React__default.default.createElement("div", {
|
|
2133
|
+
"data-content": "",
|
|
2134
|
+
className: cn(classNames == null ? void 0 : classNames.content, toast2 == null ? void 0 : (_toast_classNames4 = toast2.classNames) == null ? void 0 : _toast_classNames4.content)
|
|
2135
|
+
}, /* @__PURE__ */ React__default.default.createElement("div", {
|
|
2136
|
+
"data-title": "",
|
|
2137
|
+
className: cn(classNames == null ? void 0 : classNames.title, toast2 == null ? void 0 : (_toast_classNames5 = toast2.classNames) == null ? void 0 : _toast_classNames5.title)
|
|
2138
|
+
}, toast2.jsx ? toast2.jsx : typeof toast2.title === "function" ? toast2.title() : toast2.title), toast2.description ? /* @__PURE__ */ React__default.default.createElement("div", {
|
|
2139
|
+
"data-description": "",
|
|
2140
|
+
className: cn(descriptionClassName, toastDescriptionClassname, classNames == null ? void 0 : classNames.description, toast2 == null ? void 0 : (_toast_classNames6 = toast2.classNames) == null ? void 0 : _toast_classNames6.description)
|
|
2141
|
+
}, 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", {
|
|
2142
|
+
"data-button": true,
|
|
2143
|
+
"data-cancel": true,
|
|
2144
|
+
style: toast2.cancelButtonStyle || cancelButtonStyle,
|
|
2145
|
+
onClick: (event) => {
|
|
2146
|
+
if (!isAction(toast2.cancel)) return;
|
|
2147
|
+
if (!dismissible) return;
|
|
2148
|
+
toast2.cancel.onClick == null ? void 0 : toast2.cancel.onClick.call(toast2.cancel, event);
|
|
2149
|
+
deleteToast();
|
|
2150
|
+
},
|
|
2151
|
+
className: cn(classNames == null ? void 0 : classNames.cancelButton, toast2 == null ? void 0 : (_toast_classNames7 = toast2.classNames) == null ? void 0 : _toast_classNames7.cancelButton)
|
|
2152
|
+
}, toast2.cancel.label) : null, /* @__PURE__ */ React__default.default.isValidElement(toast2.action) ? toast2.action : toast2.action && isAction(toast2.action) ? /* @__PURE__ */ React__default.default.createElement("button", {
|
|
2153
|
+
"data-button": true,
|
|
2154
|
+
"data-action": true,
|
|
2155
|
+
style: toast2.actionButtonStyle || actionButtonStyle,
|
|
2156
|
+
onClick: (event) => {
|
|
2157
|
+
if (!isAction(toast2.action)) return;
|
|
2158
|
+
toast2.action.onClick == null ? void 0 : toast2.action.onClick.call(toast2.action, event);
|
|
2159
|
+
if (event.defaultPrevented) return;
|
|
2160
|
+
deleteToast();
|
|
2161
|
+
},
|
|
2162
|
+
className: cn(classNames == null ? void 0 : classNames.actionButton, toast2 == null ? void 0 : (_toast_classNames8 = toast2.classNames) == null ? void 0 : _toast_classNames8.actionButton)
|
|
2163
|
+
}, toast2.action.label) : null);
|
|
2164
|
+
};
|
|
2165
|
+
function getDocumentDirection() {
|
|
2166
|
+
if (typeof window === "undefined") return "ltr";
|
|
2167
|
+
if (typeof document === "undefined") return "ltr";
|
|
2168
|
+
const dirAttribute = document.documentElement.getAttribute("dir");
|
|
2169
|
+
if (dirAttribute === "auto" || !dirAttribute) {
|
|
2170
|
+
return window.getComputedStyle(document.documentElement).direction;
|
|
2171
|
+
}
|
|
2172
|
+
return dirAttribute;
|
|
2173
|
+
}
|
|
2174
|
+
function assignOffset(defaultOffset, mobileOffset) {
|
|
2175
|
+
const styles = {};
|
|
2176
|
+
[
|
|
2177
|
+
defaultOffset,
|
|
2178
|
+
mobileOffset
|
|
2179
|
+
].forEach((offset, index) => {
|
|
2180
|
+
const isMobile = index === 1;
|
|
2181
|
+
const prefix = isMobile ? "--mobile-offset" : "--offset";
|
|
2182
|
+
const defaultValue = isMobile ? MOBILE_VIEWPORT_OFFSET : VIEWPORT_OFFSET;
|
|
2183
|
+
function assignAll(offset2) {
|
|
2184
|
+
[
|
|
2185
|
+
"top",
|
|
2186
|
+
"right",
|
|
2187
|
+
"bottom",
|
|
2188
|
+
"left"
|
|
2189
|
+
].forEach((key) => {
|
|
2190
|
+
styles[`${prefix}-${key}`] = typeof offset2 === "number" ? `${offset2}px` : offset2;
|
|
2191
|
+
});
|
|
2192
|
+
}
|
|
2193
|
+
if (typeof offset === "number" || typeof offset === "string") {
|
|
2194
|
+
assignAll(offset);
|
|
2195
|
+
} else if (typeof offset === "object") {
|
|
2196
|
+
[
|
|
2197
|
+
"top",
|
|
2198
|
+
"right",
|
|
2199
|
+
"bottom",
|
|
2200
|
+
"left"
|
|
2201
|
+
].forEach((key) => {
|
|
2202
|
+
if (offset[key] === void 0) {
|
|
2203
|
+
styles[`${prefix}-${key}`] = defaultValue;
|
|
2204
|
+
} else {
|
|
2205
|
+
styles[`${prefix}-${key}`] = typeof offset[key] === "number" ? `${offset[key]}px` : offset[key];
|
|
2206
|
+
}
|
|
2207
|
+
});
|
|
2208
|
+
} else {
|
|
2209
|
+
assignAll(defaultValue);
|
|
2210
|
+
}
|
|
2211
|
+
});
|
|
2212
|
+
return styles;
|
|
2213
|
+
}
|
|
2214
|
+
var Toaster = /* @__PURE__ */ React__default.default.forwardRef(function Toaster2(props, ref) {
|
|
2215
|
+
const { id, invert, position = "bottom-right", hotkey = [
|
|
2216
|
+
"altKey",
|
|
2217
|
+
"KeyT"
|
|
2218
|
+
], expand, closeButton, className, offset, mobileOffset, theme = "light", richColors, duration, style, visibleToasts = VISIBLE_TOASTS_AMOUNT, toastOptions, dir = getDocumentDirection(), gap = GAP, icons, containerAriaLabel = "Notifications" } = props;
|
|
2219
|
+
const [toasts, setToasts] = React__default.default.useState([]);
|
|
2220
|
+
const filteredToasts = React__default.default.useMemo(() => {
|
|
2221
|
+
if (id) {
|
|
2222
|
+
return toasts.filter((toast2) => toast2.toasterId === id);
|
|
2223
|
+
}
|
|
2224
|
+
return toasts.filter((toast2) => !toast2.toasterId);
|
|
2225
|
+
}, [
|
|
2226
|
+
toasts,
|
|
2227
|
+
id
|
|
2228
|
+
]);
|
|
2229
|
+
const possiblePositions = React__default.default.useMemo(() => {
|
|
2230
|
+
return Array.from(new Set([
|
|
2231
|
+
position
|
|
2232
|
+
].concat(filteredToasts.filter((toast2) => toast2.position).map((toast2) => toast2.position))));
|
|
2233
|
+
}, [
|
|
2234
|
+
filteredToasts,
|
|
2235
|
+
position
|
|
2236
|
+
]);
|
|
2237
|
+
const [heights, setHeights] = React__default.default.useState([]);
|
|
2238
|
+
const [expanded, setExpanded] = React__default.default.useState(false);
|
|
2239
|
+
const [interacting, setInteracting] = React__default.default.useState(false);
|
|
2240
|
+
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");
|
|
2241
|
+
const listRef = React__default.default.useRef(null);
|
|
2242
|
+
const hotkeyLabel = hotkey.join("+").replace(/Key/g, "").replace(/Digit/g, "");
|
|
2243
|
+
const lastFocusedElementRef = React__default.default.useRef(null);
|
|
2244
|
+
const isFocusWithinRef = React__default.default.useRef(false);
|
|
2245
|
+
const removeToast = React__default.default.useCallback((toastToRemove) => {
|
|
2246
|
+
setToasts((toasts2) => {
|
|
2247
|
+
var _toasts_find;
|
|
2248
|
+
if (!((_toasts_find = toasts2.find((toast2) => toast2.id === toastToRemove.id)) == null ? void 0 : _toasts_find.delete)) {
|
|
2249
|
+
ToastState.dismiss(toastToRemove.id);
|
|
2250
|
+
}
|
|
2251
|
+
return toasts2.filter(({ id: id2 }) => id2 !== toastToRemove.id);
|
|
2252
|
+
});
|
|
2253
|
+
}, []);
|
|
2254
|
+
React__default.default.useEffect(() => {
|
|
2255
|
+
return ToastState.subscribe((toast2) => {
|
|
2256
|
+
if (toast2.dismiss) {
|
|
2257
|
+
requestAnimationFrame(() => {
|
|
2258
|
+
setToasts((toasts2) => toasts2.map((t) => t.id === toast2.id ? {
|
|
2259
|
+
...t,
|
|
2260
|
+
delete: true
|
|
2261
|
+
} : t));
|
|
2262
|
+
});
|
|
2263
|
+
return;
|
|
2264
|
+
}
|
|
2265
|
+
setTimeout(() => {
|
|
2266
|
+
ReactDOM__default.default.flushSync(() => {
|
|
2267
|
+
setToasts((toasts2) => {
|
|
2268
|
+
const indexOfExistingToast = toasts2.findIndex((t) => t.id === toast2.id);
|
|
2269
|
+
if (indexOfExistingToast !== -1) {
|
|
2270
|
+
return [
|
|
2271
|
+
...toasts2.slice(0, indexOfExistingToast),
|
|
2272
|
+
{
|
|
2273
|
+
...toasts2[indexOfExistingToast],
|
|
2274
|
+
...toast2
|
|
2275
|
+
},
|
|
2276
|
+
...toasts2.slice(indexOfExistingToast + 1)
|
|
2277
|
+
];
|
|
2278
|
+
}
|
|
2279
|
+
return [
|
|
2280
|
+
toast2,
|
|
2281
|
+
...toasts2
|
|
2282
|
+
];
|
|
2283
|
+
});
|
|
2284
|
+
});
|
|
2285
|
+
});
|
|
2286
|
+
});
|
|
2287
|
+
}, [
|
|
2288
|
+
toasts
|
|
2289
|
+
]);
|
|
2290
|
+
React__default.default.useEffect(() => {
|
|
2291
|
+
if (theme !== "system") {
|
|
2292
|
+
setActualTheme(theme);
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
if (theme === "system") {
|
|
2296
|
+
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
2297
|
+
setActualTheme("dark");
|
|
2298
|
+
} else {
|
|
2299
|
+
setActualTheme("light");
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
if (typeof window === "undefined") return;
|
|
2303
|
+
const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
2304
|
+
try {
|
|
2305
|
+
darkMediaQuery.addEventListener("change", ({ matches }) => {
|
|
2306
|
+
if (matches) {
|
|
2307
|
+
setActualTheme("dark");
|
|
2308
|
+
} else {
|
|
2309
|
+
setActualTheme("light");
|
|
2310
|
+
}
|
|
2311
|
+
});
|
|
2312
|
+
} catch (error) {
|
|
2313
|
+
darkMediaQuery.addListener(({ matches }) => {
|
|
2314
|
+
try {
|
|
2315
|
+
if (matches) {
|
|
2316
|
+
setActualTheme("dark");
|
|
2317
|
+
} else {
|
|
2318
|
+
setActualTheme("light");
|
|
2319
|
+
}
|
|
2320
|
+
} catch (e) {
|
|
2321
|
+
console.error(e);
|
|
2322
|
+
}
|
|
2323
|
+
});
|
|
2324
|
+
}
|
|
2325
|
+
}, [
|
|
2326
|
+
theme
|
|
2327
|
+
]);
|
|
2328
|
+
React__default.default.useEffect(() => {
|
|
2329
|
+
if (toasts.length <= 1) {
|
|
2330
|
+
setExpanded(false);
|
|
2331
|
+
}
|
|
2332
|
+
}, [
|
|
2333
|
+
toasts
|
|
2334
|
+
]);
|
|
2335
|
+
React__default.default.useEffect(() => {
|
|
2336
|
+
const handleKeyDown = (event) => {
|
|
2337
|
+
var _listRef_current;
|
|
2338
|
+
const isHotkeyPressed = hotkey.every((key) => event[key] || event.code === key);
|
|
2339
|
+
if (isHotkeyPressed) {
|
|
2340
|
+
var _listRef_current1;
|
|
2341
|
+
setExpanded(true);
|
|
2342
|
+
(_listRef_current1 = listRef.current) == null ? void 0 : _listRef_current1.focus();
|
|
2343
|
+
}
|
|
2344
|
+
if (event.code === "Escape" && (document.activeElement === listRef.current || ((_listRef_current = listRef.current) == null ? void 0 : _listRef_current.contains(document.activeElement)))) {
|
|
2345
|
+
setExpanded(false);
|
|
2346
|
+
}
|
|
2347
|
+
};
|
|
2348
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2349
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
2350
|
+
}, [
|
|
2351
|
+
hotkey
|
|
2352
|
+
]);
|
|
2353
|
+
React__default.default.useEffect(() => {
|
|
2354
|
+
if (listRef.current) {
|
|
2355
|
+
return () => {
|
|
2356
|
+
if (lastFocusedElementRef.current) {
|
|
2357
|
+
lastFocusedElementRef.current.focus({
|
|
2358
|
+
preventScroll: true
|
|
2359
|
+
});
|
|
2360
|
+
lastFocusedElementRef.current = null;
|
|
2361
|
+
isFocusWithinRef.current = false;
|
|
2362
|
+
}
|
|
2363
|
+
};
|
|
2364
|
+
}
|
|
2365
|
+
}, [
|
|
2366
|
+
listRef.current
|
|
2367
|
+
]);
|
|
2368
|
+
return (
|
|
2369
|
+
// Remove item from normal navigation flow, only available via hotkey
|
|
2370
|
+
/* @__PURE__ */ React__default.default.createElement("section", {
|
|
2371
|
+
ref,
|
|
2372
|
+
"aria-label": `${containerAriaLabel} ${hotkeyLabel}`,
|
|
2373
|
+
tabIndex: -1,
|
|
2374
|
+
"aria-live": "polite",
|
|
2375
|
+
"aria-relevant": "additions text",
|
|
2376
|
+
"aria-atomic": "false",
|
|
2377
|
+
suppressHydrationWarning: true
|
|
2378
|
+
}, possiblePositions.map((position2, index) => {
|
|
2379
|
+
var _heights_;
|
|
2380
|
+
const [y, x] = position2.split("-");
|
|
2381
|
+
if (!filteredToasts.length) return null;
|
|
2382
|
+
return /* @__PURE__ */ React__default.default.createElement("ol", {
|
|
2383
|
+
key: position2,
|
|
2384
|
+
dir: dir === "auto" ? getDocumentDirection() : dir,
|
|
2385
|
+
tabIndex: -1,
|
|
2386
|
+
ref: listRef,
|
|
2387
|
+
className,
|
|
2388
|
+
"data-sonner-toaster": true,
|
|
2389
|
+
"data-sonner-theme": actualTheme,
|
|
2390
|
+
"data-y-position": y,
|
|
2391
|
+
"data-x-position": x,
|
|
2392
|
+
style: {
|
|
2393
|
+
"--front-toast-height": `${((_heights_ = heights[0]) == null ? void 0 : _heights_.height) || 0}px`,
|
|
2394
|
+
"--width": `${TOAST_WIDTH}px`,
|
|
2395
|
+
"--gap": `${gap}px`,
|
|
2396
|
+
...style,
|
|
2397
|
+
...assignOffset(offset, mobileOffset)
|
|
2398
|
+
},
|
|
2399
|
+
onBlur: (event) => {
|
|
2400
|
+
if (isFocusWithinRef.current && !event.currentTarget.contains(event.relatedTarget)) {
|
|
2401
|
+
isFocusWithinRef.current = false;
|
|
2402
|
+
if (lastFocusedElementRef.current) {
|
|
2403
|
+
lastFocusedElementRef.current.focus({
|
|
2404
|
+
preventScroll: true
|
|
2405
|
+
});
|
|
2406
|
+
lastFocusedElementRef.current = null;
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
},
|
|
2410
|
+
onFocus: (event) => {
|
|
2411
|
+
const isNotDismissible = event.target instanceof HTMLElement && event.target.dataset.dismissible === "false";
|
|
2412
|
+
if (isNotDismissible) return;
|
|
2413
|
+
if (!isFocusWithinRef.current) {
|
|
2414
|
+
isFocusWithinRef.current = true;
|
|
2415
|
+
lastFocusedElementRef.current = event.relatedTarget;
|
|
2416
|
+
}
|
|
2417
|
+
},
|
|
2418
|
+
onMouseEnter: () => setExpanded(true),
|
|
2419
|
+
onMouseMove: () => setExpanded(true),
|
|
2420
|
+
onMouseLeave: () => {
|
|
2421
|
+
if (!interacting) {
|
|
2422
|
+
setExpanded(false);
|
|
2423
|
+
}
|
|
2424
|
+
},
|
|
2425
|
+
onDragEnd: () => setExpanded(false),
|
|
2426
|
+
onPointerDown: (event) => {
|
|
2427
|
+
const isNotDismissible = event.target instanceof HTMLElement && event.target.dataset.dismissible === "false";
|
|
2428
|
+
if (isNotDismissible) return;
|
|
2429
|
+
setInteracting(true);
|
|
2430
|
+
},
|
|
2431
|
+
onPointerUp: () => setInteracting(false)
|
|
2432
|
+
}, filteredToasts.filter((toast2) => !toast2.position && index === 0 || toast2.position === position2).map((toast2, index2) => {
|
|
2433
|
+
var _toastOptions_duration, _toastOptions_closeButton;
|
|
2434
|
+
return /* @__PURE__ */ React__default.default.createElement(Toast, {
|
|
2435
|
+
key: toast2.id,
|
|
2436
|
+
icons,
|
|
2437
|
+
index: index2,
|
|
2438
|
+
toast: toast2,
|
|
2439
|
+
defaultRichColors: richColors,
|
|
2440
|
+
duration: (_toastOptions_duration = toastOptions == null ? void 0 : toastOptions.duration) != null ? _toastOptions_duration : duration,
|
|
2441
|
+
className: toastOptions == null ? void 0 : toastOptions.className,
|
|
2442
|
+
descriptionClassName: toastOptions == null ? void 0 : toastOptions.descriptionClassName,
|
|
2443
|
+
invert,
|
|
2444
|
+
visibleToasts,
|
|
2445
|
+
closeButton: (_toastOptions_closeButton = toastOptions == null ? void 0 : toastOptions.closeButton) != null ? _toastOptions_closeButton : closeButton,
|
|
2446
|
+
interacting,
|
|
2447
|
+
position: position2,
|
|
2448
|
+
style: toastOptions == null ? void 0 : toastOptions.style,
|
|
2449
|
+
unstyled: toastOptions == null ? void 0 : toastOptions.unstyled,
|
|
2450
|
+
classNames: toastOptions == null ? void 0 : toastOptions.classNames,
|
|
2451
|
+
cancelButtonStyle: toastOptions == null ? void 0 : toastOptions.cancelButtonStyle,
|
|
2452
|
+
actionButtonStyle: toastOptions == null ? void 0 : toastOptions.actionButtonStyle,
|
|
2453
|
+
closeButtonAriaLabel: toastOptions == null ? void 0 : toastOptions.closeButtonAriaLabel,
|
|
2454
|
+
removeToast,
|
|
2455
|
+
toasts: filteredToasts.filter((t) => t.position == toast2.position),
|
|
2456
|
+
heights: heights.filter((h) => h.position == toast2.position),
|
|
2457
|
+
setHeights,
|
|
2458
|
+
expandByDefault: expand,
|
|
2459
|
+
gap,
|
|
2460
|
+
expanded,
|
|
2461
|
+
swipeDirections: props.swipeDirections
|
|
2462
|
+
});
|
|
2463
|
+
}));
|
|
2464
|
+
}))
|
|
2465
|
+
);
|
|
2466
|
+
});
|
|
1585
2467
|
function FunnelToaster(props = {}) {
|
|
1586
|
-
return
|
|
2468
|
+
return React.createElement(Toaster, { position: "top-center", ...props });
|
|
1587
2469
|
}
|
|
1588
2470
|
function renderToaster(toaster) {
|
|
1589
2471
|
if (toaster === false) return null;
|
|
1590
|
-
return
|
|
2472
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FunnelToaster, { ...toaster === true ? {} : toaster });
|
|
1591
2473
|
}
|
|
1592
2474
|
|
|
1593
2475
|
// src/state/namespaces.ts
|
|
@@ -1653,7 +2535,7 @@ function createFunnel(store, context, tracker, experiments = []) {
|
|
|
1653
2535
|
})
|
|
1654
2536
|
};
|
|
1655
2537
|
}
|
|
1656
|
-
var FunnelCtx =
|
|
2538
|
+
var FunnelCtx = React.createContext(null);
|
|
1657
2539
|
function FunnelProvider({
|
|
1658
2540
|
config,
|
|
1659
2541
|
sessionValues,
|
|
@@ -1669,7 +2551,7 @@ function FunnelProvider({
|
|
|
1669
2551
|
children
|
|
1670
2552
|
}) {
|
|
1671
2553
|
const resolvedTracker = tracker ?? FALLBACK_TRACKER;
|
|
1672
|
-
const [value] =
|
|
2554
|
+
const [value] = React.useState(() => {
|
|
1673
2555
|
const s = store ?? createFunnelStore(
|
|
1674
2556
|
{ responses: config?.responses, data: config?.data },
|
|
1675
2557
|
sessionValues
|
|
@@ -1686,44 +2568,48 @@ function FunnelProvider({
|
|
|
1686
2568
|
getVisitorId: () => ctx.identity.visitorId
|
|
1687
2569
|
});
|
|
1688
2570
|
const busTracker = withBus(resolvedTracker, bus);
|
|
2571
|
+
const emailForCheckout = () => {
|
|
2572
|
+
const value2 = s.get("user.email");
|
|
2573
|
+
return typeof value2 === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(value2) ? value2 : void 0;
|
|
2574
|
+
};
|
|
1689
2575
|
return {
|
|
1690
2576
|
funnel: createFunnel(s, ctx, busTracker, experiments ?? []),
|
|
1691
2577
|
store: s,
|
|
1692
2578
|
context: ctx,
|
|
1693
|
-
catalog: buildCatalog(products ?? []),
|
|
1694
|
-
driver: checkout ?? createMockDriver(),
|
|
2579
|
+
catalog: chunkZ3TWO2PW_cjs.buildCatalog(products ?? []),
|
|
2580
|
+
driver: driverWithEmail(checkout ?? createMockDriver(), emailForCheckout),
|
|
1695
2581
|
tracker: busTracker,
|
|
1696
2582
|
bus
|
|
1697
2583
|
};
|
|
1698
2584
|
});
|
|
1699
|
-
|
|
1700
|
-
|
|
2585
|
+
React.useEffect(() => attachBus(value.bus), [value.bus]);
|
|
2586
|
+
React.useEffect(() => {
|
|
1701
2587
|
value.tracker.setAcquisition?.(buildAcquisition(value.context));
|
|
1702
2588
|
}, [value]);
|
|
1703
|
-
const tree =
|
|
2589
|
+
const tree = React.createElement(TrackerProvider, {
|
|
1704
2590
|
tracker: value.tracker,
|
|
1705
|
-
children:
|
|
2591
|
+
children: React.createElement(CheckoutDriverProvider, {
|
|
1706
2592
|
driver: value.driver,
|
|
1707
|
-
children:
|
|
2593
|
+
children: React.createElement(CatalogProvider, {
|
|
1708
2594
|
catalog: value.catalog,
|
|
1709
|
-
children:
|
|
2595
|
+
children: React.createElement(FunnelCtx.Provider, {
|
|
1710
2596
|
value,
|
|
1711
|
-
children:
|
|
2597
|
+
children: React.createElement(LocaleProvider, {
|
|
1712
2598
|
config: config?.locales,
|
|
1713
2599
|
catalog: messages,
|
|
1714
2600
|
detected: value.context.locale.locale,
|
|
1715
2601
|
override: localeOverride,
|
|
1716
|
-
children:
|
|
2602
|
+
children: React.createElement(ModalRuntime, { children })
|
|
1717
2603
|
})
|
|
1718
2604
|
})
|
|
1719
2605
|
})
|
|
1720
2606
|
})
|
|
1721
2607
|
});
|
|
1722
|
-
return
|
|
2608
|
+
return React.createElement(React.Fragment, null, tree, renderToaster(toaster));
|
|
1723
2609
|
}
|
|
1724
2610
|
var FALLBACK_TRACKER = createConsoleTracker({ silent: true });
|
|
1725
2611
|
function useFunnelCtx() {
|
|
1726
|
-
const ctx =
|
|
2612
|
+
const ctx = React.useContext(FunnelCtx);
|
|
1727
2613
|
if (!ctx) {
|
|
1728
2614
|
throw new Error("useFunnel/useResponse/\u2026 must be used inside <FunnelProvider>");
|
|
1729
2615
|
}
|
|
@@ -1733,18 +2619,18 @@ function useFunnel() {
|
|
|
1733
2619
|
return useFunnelCtx().funnel;
|
|
1734
2620
|
}
|
|
1735
2621
|
function useStoreKey(store, key) {
|
|
1736
|
-
const subscribe =
|
|
2622
|
+
const subscribe = React.useCallback(
|
|
1737
2623
|
(cb) => store.subscribe(cb, { keys: [key] }),
|
|
1738
2624
|
[store, key]
|
|
1739
2625
|
);
|
|
1740
|
-
const getSnapshot =
|
|
1741
|
-
return
|
|
2626
|
+
const getSnapshot = React.useCallback(() => store.get(key), [store, key]);
|
|
2627
|
+
return React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
1742
2628
|
}
|
|
1743
2629
|
function makeFieldHook(ns) {
|
|
1744
2630
|
return function useNamespaceField(key) {
|
|
1745
2631
|
const { funnel, store } = useFunnelCtx();
|
|
1746
2632
|
const value = useStoreKey(store, `${NAMESPACE_PREFIX[ns]}.${key}`);
|
|
1747
|
-
const set =
|
|
2633
|
+
const set = React.useCallback(
|
|
1748
2634
|
(v) => funnel[ns].set({ [key]: v }),
|
|
1749
2635
|
[funnel, key]
|
|
1750
2636
|
);
|
|
@@ -1763,7 +2649,7 @@ function useField(path) {
|
|
|
1763
2649
|
throw new Error(`useField: "${path}" is not a writable namespace (user/responses/data)`);
|
|
1764
2650
|
}
|
|
1765
2651
|
const value = useStoreKey(store, `${NAMESPACE_PREFIX[ns]}.${key}`);
|
|
1766
|
-
const set =
|
|
2652
|
+
const set = React.useCallback(
|
|
1767
2653
|
(v) => funnel[ns].set({ [key]: v }),
|
|
1768
2654
|
[funnel, ns, key]
|
|
1769
2655
|
);
|
|
@@ -1789,11 +2675,235 @@ function useSystem() {
|
|
|
1789
2675
|
}
|
|
1790
2676
|
function useContextValue(path) {
|
|
1791
2677
|
const ctx = useContextObject();
|
|
1792
|
-
return
|
|
2678
|
+
return React.useMemo(
|
|
1793
2679
|
() => path.split(".").reduce((acc, k) => acc?.[k], ctx),
|
|
1794
2680
|
[ctx, path]
|
|
1795
2681
|
);
|
|
1796
2682
|
}
|
|
2683
|
+
|
|
2684
|
+
// src/tracking/platformTracker.ts
|
|
2685
|
+
function validClickIds(acq) {
|
|
2686
|
+
return Object.entries(acq.clickIds ?? {}).filter(
|
|
2687
|
+
(e) => typeof e[1] === "string" && e[1] !== ""
|
|
2688
|
+
);
|
|
2689
|
+
}
|
|
2690
|
+
function acquisitionQueryBag(acq) {
|
|
2691
|
+
const q = {};
|
|
2692
|
+
const utm = acq.utm ?? {};
|
|
2693
|
+
for (const [k, v] of Object.entries({
|
|
2694
|
+
utm_source: utm.source,
|
|
2695
|
+
utm_medium: utm.medium,
|
|
2696
|
+
utm_campaign: utm.campaign,
|
|
2697
|
+
utm_term: utm.term,
|
|
2698
|
+
utm_content: utm.content
|
|
2699
|
+
})) if (v) q[k] = v;
|
|
2700
|
+
for (const [k, v] of validClickIds(acq)) q[k] = v;
|
|
2701
|
+
if (acq.cookies?.fbp) q._fbp = acq.cookies.fbp;
|
|
2702
|
+
if (acq.cookies?.fbc) q._fbc = acq.cookies.fbc;
|
|
2703
|
+
return q;
|
|
2704
|
+
}
|
|
2705
|
+
function acquisitionAdAttribution(acq) {
|
|
2706
|
+
const a = {};
|
|
2707
|
+
for (const [k, v] of validClickIds(acq)) a[k] = v;
|
|
2708
|
+
if (acq.cookies?.fbp) a.fbp = acq.cookies.fbp;
|
|
2709
|
+
if (acq.cookies?.fbc) a.fbc = acq.cookies.fbc;
|
|
2710
|
+
else if (acq.clickIds?.fbclid) a.fbc = `fb.1.${Date.now()}.${acq.clickIds.fbclid}`;
|
|
2711
|
+
return a;
|
|
2712
|
+
}
|
|
2713
|
+
function createPlatformTracker(cfg) {
|
|
2714
|
+
if (typeof window === "undefined" || cfg.mode === "test") return createConsoleTracker();
|
|
2715
|
+
const base = cfg.apiBase.replace(/\/+$/, "");
|
|
2716
|
+
const url = `${base}/campaign/${encodeURIComponent(cfg.campaignId)}/event`;
|
|
2717
|
+
const sidKey = `af_sid:${cfg.campaignId}`;
|
|
2718
|
+
let sessionId = null;
|
|
2719
|
+
try {
|
|
2720
|
+
sessionId = window.sessionStorage.getItem(sidKey);
|
|
2721
|
+
} catch {
|
|
2722
|
+
}
|
|
2723
|
+
if (!sessionId && cfg.sessionId) sessionId = cfg.sessionId;
|
|
2724
|
+
let acquisition = null;
|
|
2725
|
+
let acquisitionSent = false;
|
|
2726
|
+
let chain = Promise.resolve();
|
|
2727
|
+
const send = async (event, data, userData) => {
|
|
2728
|
+
let mergedUserData = userData;
|
|
2729
|
+
let adAttribution;
|
|
2730
|
+
let attachingAcquisition = false;
|
|
2731
|
+
if (acquisition && !acquisitionSent) {
|
|
2732
|
+
attachingAcquisition = true;
|
|
2733
|
+
const query = acquisitionQueryBag(acquisition);
|
|
2734
|
+
mergedUserData = Object.keys(query).length ? { ...userData, query } : userData;
|
|
2735
|
+
const ad = acquisitionAdAttribution(acquisition);
|
|
2736
|
+
if (Object.keys(ad).length) adAttribution = ad;
|
|
2737
|
+
}
|
|
2738
|
+
const body = {
|
|
2739
|
+
campaignId: cfg.campaignId,
|
|
2740
|
+
funnelId: cfg.funnelId,
|
|
2741
|
+
event,
|
|
2742
|
+
sessionId: sessionId ?? void 0,
|
|
2743
|
+
visitorId: cfg.visitorId ?? void 0,
|
|
2744
|
+
eventId: typeof data?.eventId === "string" ? data.eventId : void 0,
|
|
2745
|
+
data: data ?? {},
|
|
2746
|
+
metadata: {
|
|
2747
|
+
language: typeof navigator !== "undefined" ? navigator.language : void 0,
|
|
2748
|
+
screen: typeof window.screen !== "undefined" ? `${window.screen.width}x${window.screen.height}` : void 0,
|
|
2749
|
+
timezone: (() => {
|
|
2750
|
+
try {
|
|
2751
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
2752
|
+
} catch {
|
|
2753
|
+
return void 0;
|
|
2754
|
+
}
|
|
2755
|
+
})(),
|
|
2756
|
+
referrer: typeof document !== "undefined" && document.referrer ? document.referrer : void 0
|
|
2757
|
+
},
|
|
2758
|
+
...mergedUserData ? { userData: mergedUserData } : {},
|
|
2759
|
+
...adAttribution ? { adAttribution } : {}
|
|
2760
|
+
};
|
|
2761
|
+
const res = await fetch(url, {
|
|
2762
|
+
method: "POST",
|
|
2763
|
+
headers: { "content-type": "application/json" },
|
|
2764
|
+
body: JSON.stringify(body),
|
|
2765
|
+
keepalive: true
|
|
2766
|
+
// survives page.exit / unload
|
|
2767
|
+
});
|
|
2768
|
+
if (attachingAcquisition) acquisitionSent = true;
|
|
2769
|
+
const json = await res.json().catch(() => null);
|
|
2770
|
+
if (json?.sessionId && json.sessionId !== sessionId) {
|
|
2771
|
+
sessionId = json.sessionId;
|
|
2772
|
+
try {
|
|
2773
|
+
window.sessionStorage.setItem(sidKey, sessionId);
|
|
2774
|
+
} catch {
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
};
|
|
2778
|
+
const enqueue = (event, data, userData) => {
|
|
2779
|
+
const task = () => send(event, data, userData).catch((e) => {
|
|
2780
|
+
if (process.env.NODE_ENV !== "production") console.warn(`[appfunnel] track failed (${event}):`, e);
|
|
2781
|
+
});
|
|
2782
|
+
if (!sessionId) {
|
|
2783
|
+
chain = chain.then(task);
|
|
2784
|
+
} else {
|
|
2785
|
+
void task();
|
|
2786
|
+
}
|
|
2787
|
+
};
|
|
2788
|
+
const VARS_DEBOUNCE_MS = 800;
|
|
2789
|
+
let pendingVars = null;
|
|
2790
|
+
let varsTimer = null;
|
|
2791
|
+
const flushVars = () => {
|
|
2792
|
+
if (varsTimer) {
|
|
2793
|
+
clearTimeout(varsTimer);
|
|
2794
|
+
varsTimer = null;
|
|
2795
|
+
}
|
|
2796
|
+
if (!pendingVars) return;
|
|
2797
|
+
const doPost = () => {
|
|
2798
|
+
if (!pendingVars || !sessionId) return;
|
|
2799
|
+
const userData = pendingVars;
|
|
2800
|
+
pendingVars = null;
|
|
2801
|
+
void fetch(`${base}/campaign/${encodeURIComponent(cfg.campaignId)}/event/session/data`, {
|
|
2802
|
+
method: "POST",
|
|
2803
|
+
headers: { "content-type": "application/json" },
|
|
2804
|
+
body: JSON.stringify({ sessionId, userData }),
|
|
2805
|
+
keepalive: true
|
|
2806
|
+
}).catch((e) => {
|
|
2807
|
+
if (process.env.NODE_ENV !== "production") console.warn("[appfunnel] variable persist failed:", e);
|
|
2808
|
+
});
|
|
2809
|
+
};
|
|
2810
|
+
if (sessionId) doPost();
|
|
2811
|
+
else chain = chain.then(doPost);
|
|
2812
|
+
};
|
|
2813
|
+
try {
|
|
2814
|
+
window.addEventListener("pagehide", flushVars);
|
|
2815
|
+
} catch {
|
|
2816
|
+
}
|
|
2817
|
+
if (cfg.experiment?.id && cfg.experiment.variant) {
|
|
2818
|
+
enqueue("experiment.exposure", exposurePayload(cfg.experiment.id, cfg.experiment.variant, cfg.experiment.version));
|
|
2819
|
+
}
|
|
2820
|
+
return {
|
|
2821
|
+
track: (event, data, userData) => enqueue(event, data, userData),
|
|
2822
|
+
identify: (email, eventId) => enqueue("user.registered", { email, ...eventId ? { eventId } : {} }),
|
|
2823
|
+
setVariables: (variables) => {
|
|
2824
|
+
pendingVars = variables;
|
|
2825
|
+
if (varsTimer) clearTimeout(varsTimer);
|
|
2826
|
+
varsTimer = setTimeout(flushVars, VARS_DEBOUNCE_MS);
|
|
2827
|
+
},
|
|
2828
|
+
setAcquisition: (acq) => {
|
|
2829
|
+
acquisition = acq;
|
|
2830
|
+
}
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
// src/flow/mount.tsx
|
|
2835
|
+
var AssetsContext = React.createContext({});
|
|
2836
|
+
function AssetsProvider({
|
|
2837
|
+
assets,
|
|
2838
|
+
children
|
|
2839
|
+
}) {
|
|
2840
|
+
return React.createElement(AssetsContext.Provider, { value: assets ?? {} }, children);
|
|
2841
|
+
}
|
|
2842
|
+
function useAssets() {
|
|
2843
|
+
return React.useContext(AssetsContext);
|
|
2844
|
+
}
|
|
2845
|
+
function useAsset(name) {
|
|
2846
|
+
return React.useContext(AssetsContext)[name];
|
|
2847
|
+
}
|
|
2848
|
+
function createFunnelTree({
|
|
2849
|
+
config,
|
|
2850
|
+
pages,
|
|
2851
|
+
layout,
|
|
2852
|
+
checkoutDriver
|
|
2853
|
+
}) {
|
|
2854
|
+
return function tree(opts) {
|
|
2855
|
+
const mode = opts.mode ?? "live";
|
|
2856
|
+
const tracker = opts.tracking ? createPlatformTracker({
|
|
2857
|
+
...opts.tracking,
|
|
2858
|
+
visitorId: opts.visitorId,
|
|
2859
|
+
sessionId: opts.sessionId,
|
|
2860
|
+
mode
|
|
2861
|
+
}) : void 0;
|
|
2862
|
+
const checkout = checkoutDriver && opts.tracking ? checkoutDriver({
|
|
2863
|
+
apiBase: opts.tracking.apiBase,
|
|
2864
|
+
campaignId: opts.tracking.campaignId,
|
|
2865
|
+
funnelId: opts.tracking.funnelId,
|
|
2866
|
+
mode,
|
|
2867
|
+
sessionId: opts.sessionId,
|
|
2868
|
+
visitorId: opts.visitorId
|
|
2869
|
+
}) : void 0;
|
|
2870
|
+
const layoutWithResume = function LayoutWithCheckoutResume({
|
|
2871
|
+
children
|
|
2872
|
+
}) {
|
|
2873
|
+
return React.createElement(
|
|
2874
|
+
React.Fragment,
|
|
2875
|
+
null,
|
|
2876
|
+
React.createElement(CheckoutResume, null),
|
|
2877
|
+
layout ? React.createElement(layout, null, children) : children
|
|
2878
|
+
);
|
|
2879
|
+
};
|
|
2880
|
+
return React.createElement(AssetsProvider, {
|
|
2881
|
+
assets: opts.assets,
|
|
2882
|
+
children: React.createElement(FunnelProvider, {
|
|
2883
|
+
config,
|
|
2884
|
+
products: opts.products ?? [],
|
|
2885
|
+
locale: opts.locale,
|
|
2886
|
+
tracker,
|
|
2887
|
+
checkout,
|
|
2888
|
+
sessionValues: opts.sessionValues,
|
|
2889
|
+
experiments: opts.experiments,
|
|
2890
|
+
context: {
|
|
2891
|
+
mode,
|
|
2892
|
+
visitorId: opts.visitorId ?? null,
|
|
2893
|
+
customerId: opts.customerId ?? null,
|
|
2894
|
+
sessionId: opts.sessionId ?? null
|
|
2895
|
+
},
|
|
2896
|
+
children: React.createElement(FunnelView, {
|
|
2897
|
+
pages,
|
|
2898
|
+
layout: layoutWithResume,
|
|
2899
|
+
initialKey: opts.initialKey,
|
|
2900
|
+
prefetch: "off"
|
|
2901
|
+
// renderer background-modulepreloads all chunks
|
|
2902
|
+
})
|
|
2903
|
+
})
|
|
2904
|
+
});
|
|
2905
|
+
};
|
|
2906
|
+
}
|
|
1797
2907
|
function Choice({
|
|
1798
2908
|
bind,
|
|
1799
2909
|
options,
|
|
@@ -1806,7 +2916,7 @@ function Choice({
|
|
|
1806
2916
|
return options.map((opt) => {
|
|
1807
2917
|
const o = typeof opt === "string" ? { value: opt } : opt;
|
|
1808
2918
|
const selected = value === o.value;
|
|
1809
|
-
return
|
|
2919
|
+
return React.createElement(
|
|
1810
2920
|
"button",
|
|
1811
2921
|
{
|
|
1812
2922
|
key: o.value,
|
|
@@ -1825,7 +2935,7 @@ function Choice({
|
|
|
1825
2935
|
}
|
|
1826
2936
|
function Next({ children, onClick, ...rest }) {
|
|
1827
2937
|
const { next } = useNavigation();
|
|
1828
|
-
return
|
|
2938
|
+
return React.createElement(
|
|
1829
2939
|
"button",
|
|
1830
2940
|
{
|
|
1831
2941
|
type: "button",
|
|
@@ -1841,7 +2951,7 @@ function Next({ children, onClick, ...rest }) {
|
|
|
1841
2951
|
function Back({ children, onClick, ...rest }) {
|
|
1842
2952
|
const { back, canGoBack } = useNavigation();
|
|
1843
2953
|
if (!canGoBack) return null;
|
|
1844
|
-
return
|
|
2954
|
+
return React.createElement(
|
|
1845
2955
|
"button",
|
|
1846
2956
|
{
|
|
1847
2957
|
type: "button",
|
|
@@ -1894,7 +3004,7 @@ function Script({
|
|
|
1894
3004
|
onLoad,
|
|
1895
3005
|
onError
|
|
1896
3006
|
}) {
|
|
1897
|
-
|
|
3007
|
+
React.useEffect(() => {
|
|
1898
3008
|
if (typeof document === "undefined") return;
|
|
1899
3009
|
const key = id ?? src;
|
|
1900
3010
|
if (injected.has(key)) {
|
|
@@ -1933,159 +3043,190 @@ function Script({
|
|
|
1933
3043
|
return null;
|
|
1934
3044
|
}
|
|
1935
3045
|
|
|
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
|
-
|
|
3046
|
+
Object.defineProperty(exports, "assignVariant", {
|
|
3047
|
+
enumerable: true,
|
|
3048
|
+
get: function () { return chunkZ3TWO2PW_cjs.assignVariant; }
|
|
3049
|
+
});
|
|
3050
|
+
Object.defineProperty(exports, "bucketingSeed", {
|
|
3051
|
+
enumerable: true,
|
|
3052
|
+
get: function () { return chunkZ3TWO2PW_cjs.bucketingSeed; }
|
|
3053
|
+
});
|
|
3054
|
+
Object.defineProperty(exports, "buildCatalog", {
|
|
3055
|
+
enumerable: true,
|
|
3056
|
+
get: function () { return chunkZ3TWO2PW_cjs.buildCatalog; }
|
|
3057
|
+
});
|
|
3058
|
+
Object.defineProperty(exports, "compileManifest", {
|
|
3059
|
+
enumerable: true,
|
|
3060
|
+
get: function () { return chunkZ3TWO2PW_cjs.compileManifest; }
|
|
3061
|
+
});
|
|
3062
|
+
Object.defineProperty(exports, "currencyExponent", {
|
|
3063
|
+
enumerable: true,
|
|
3064
|
+
get: function () { return chunkZ3TWO2PW_cjs.currencyExponent; }
|
|
3065
|
+
});
|
|
3066
|
+
Object.defineProperty(exports, "defineFunnel", {
|
|
3067
|
+
enumerable: true,
|
|
3068
|
+
get: function () { return chunkZ3TWO2PW_cjs.defineFunnel; }
|
|
3069
|
+
});
|
|
3070
|
+
Object.defineProperty(exports, "definePage", {
|
|
3071
|
+
enumerable: true,
|
|
3072
|
+
get: function () { return chunkZ3TWO2PW_cjs.definePage; }
|
|
3073
|
+
});
|
|
3074
|
+
Object.defineProperty(exports, "entryGuard", {
|
|
3075
|
+
enumerable: true,
|
|
3076
|
+
get: function () { return chunkZ3TWO2PW_cjs.entryGuard; }
|
|
3077
|
+
});
|
|
3078
|
+
Object.defineProperty(exports, "evaluateCondition", {
|
|
3079
|
+
enumerable: true,
|
|
3080
|
+
get: function () { return chunkZ3TWO2PW_cjs.evaluateCondition; }
|
|
3081
|
+
});
|
|
3082
|
+
Object.defineProperty(exports, "evaluateGate", {
|
|
3083
|
+
enumerable: true,
|
|
3084
|
+
get: function () { return chunkZ3TWO2PW_cjs.evaluateGate; }
|
|
3085
|
+
});
|
|
3086
|
+
Object.defineProperty(exports, "expectedPathLength", {
|
|
3087
|
+
enumerable: true,
|
|
3088
|
+
get: function () { return chunkZ3TWO2PW_cjs.expectedPathLength; }
|
|
3089
|
+
});
|
|
3090
|
+
Object.defineProperty(exports, "fnv1a", {
|
|
3091
|
+
enumerable: true,
|
|
3092
|
+
get: function () { return chunkZ3TWO2PW_cjs.fnv1a; }
|
|
3093
|
+
});
|
|
3094
|
+
Object.defineProperty(exports, "formatMoney", {
|
|
3095
|
+
enumerable: true,
|
|
3096
|
+
get: function () { return chunkZ3TWO2PW_cjs.formatMoney; }
|
|
3097
|
+
});
|
|
3098
|
+
Object.defineProperty(exports, "formatProduct", {
|
|
3099
|
+
enumerable: true,
|
|
3100
|
+
get: function () { return chunkZ3TWO2PW_cjs.formatProduct; }
|
|
3101
|
+
});
|
|
3102
|
+
Object.defineProperty(exports, "hashToUnit", {
|
|
3103
|
+
enumerable: true,
|
|
3104
|
+
get: function () { return chunkZ3TWO2PW_cjs.hashToUnit; }
|
|
3105
|
+
});
|
|
3106
|
+
Object.defineProperty(exports, "isRtl", {
|
|
3107
|
+
enumerable: true,
|
|
3108
|
+
get: function () { return chunkZ3TWO2PW_cjs.isRtl; }
|
|
3109
|
+
});
|
|
3110
|
+
Object.defineProperty(exports, "isVariantKey", {
|
|
3111
|
+
enumerable: true,
|
|
3112
|
+
get: function () { return chunkZ3TWO2PW_cjs.isVariantKey; }
|
|
3113
|
+
});
|
|
3114
|
+
Object.defineProperty(exports, "nextPage", {
|
|
3115
|
+
enumerable: true,
|
|
3116
|
+
get: function () { return chunkZ3TWO2PW_cjs.nextPage; }
|
|
3117
|
+
});
|
|
3118
|
+
Object.defineProperty(exports, "outgoingKeys", {
|
|
3119
|
+
enumerable: true,
|
|
3120
|
+
get: function () { return chunkZ3TWO2PW_cjs.outgoingKeys; }
|
|
3121
|
+
});
|
|
3122
|
+
Object.defineProperty(exports, "pageMeta", {
|
|
3123
|
+
enumerable: true,
|
|
3124
|
+
get: function () { return chunkZ3TWO2PW_cjs.pageMeta; }
|
|
3125
|
+
});
|
|
3126
|
+
Object.defineProperty(exports, "parseSlotKey", {
|
|
3127
|
+
enumerable: true,
|
|
3128
|
+
get: function () { return chunkZ3TWO2PW_cjs.parseSlotKey; }
|
|
3129
|
+
});
|
|
3130
|
+
Object.defineProperty(exports, "pickByWeight", {
|
|
3131
|
+
enumerable: true,
|
|
3132
|
+
get: function () { return chunkZ3TWO2PW_cjs.pickByWeight; }
|
|
3133
|
+
});
|
|
3134
|
+
Object.defineProperty(exports, "resolveExperiments", {
|
|
3135
|
+
enumerable: true,
|
|
3136
|
+
get: function () { return chunkZ3TWO2PW_cjs.resolveExperiments; }
|
|
3137
|
+
});
|
|
3138
|
+
Object.defineProperty(exports, "resolveLocale", {
|
|
3139
|
+
enumerable: true,
|
|
3140
|
+
get: function () { return chunkZ3TWO2PW_cjs.resolveLocale; }
|
|
3141
|
+
});
|
|
3142
|
+
Object.defineProperty(exports, "resolveProduct", {
|
|
3143
|
+
enumerable: true,
|
|
3144
|
+
get: function () { return chunkZ3TWO2PW_cjs.resolveProduct; }
|
|
3145
|
+
});
|
|
3146
|
+
Object.defineProperty(exports, "resolveRoute", {
|
|
3147
|
+
enumerable: true,
|
|
3148
|
+
get: function () { return chunkZ3TWO2PW_cjs.resolveRoute; }
|
|
3149
|
+
});
|
|
3150
|
+
Object.defineProperty(exports, "validateExperiments", {
|
|
3151
|
+
enumerable: true,
|
|
3152
|
+
get: function () { return chunkZ3TWO2PW_cjs.validateExperiments; }
|
|
3153
|
+
});
|
|
3154
|
+
Object.defineProperty(exports, "INLINE_SURFACES", {
|
|
3155
|
+
enumerable: true,
|
|
3156
|
+
get: function () { return chunkLJYLGLFS_cjs.INLINE_SURFACES; }
|
|
3157
|
+
});
|
|
3158
|
+
Object.defineProperty(exports, "PROVIDER_PROFILES", {
|
|
3159
|
+
enumerable: true,
|
|
3160
|
+
get: function () { return chunkLJYLGLFS_cjs.PROVIDER_PROFILES; }
|
|
3161
|
+
});
|
|
3162
|
+
Object.defineProperty(exports, "checkoutError", {
|
|
3163
|
+
enumerable: true,
|
|
3164
|
+
get: function () { return chunkLJYLGLFS_cjs.checkoutError; }
|
|
3165
|
+
});
|
|
3166
|
+
Object.defineProperty(exports, "isInlineSurface", {
|
|
3167
|
+
enumerable: true,
|
|
3168
|
+
get: function () { return chunkLJYLGLFS_cjs.isInlineSurface; }
|
|
3169
|
+
});
|
|
3170
|
+
Object.defineProperty(exports, "isMerchantOfRecord", {
|
|
3171
|
+
enumerable: true,
|
|
3172
|
+
get: function () { return chunkLJYLGLFS_cjs.isMerchantOfRecord; }
|
|
3173
|
+
});
|
|
3174
|
+
Object.defineProperty(exports, "isOrchestrator", {
|
|
3175
|
+
enumerable: true,
|
|
3176
|
+
get: function () { return chunkLJYLGLFS_cjs.isOrchestrator; }
|
|
3177
|
+
});
|
|
3178
|
+
Object.defineProperty(exports, "surfacesFor", {
|
|
3179
|
+
enumerable: true,
|
|
3180
|
+
get: function () { return chunkLJYLGLFS_cjs.surfacesFor; }
|
|
3181
|
+
});
|
|
3182
|
+
Object.defineProperty(exports, "validateCheckout", {
|
|
3183
|
+
enumerable: true,
|
|
3184
|
+
get: function () { return chunkLJYLGLFS_cjs.validateCheckout; }
|
|
3185
|
+
});
|
|
3186
|
+
Object.defineProperty(exports, "validateUpsell", {
|
|
2026
3187
|
enumerable: true,
|
|
2027
|
-
get: function () { return
|
|
3188
|
+
get: function () { return chunkLJYLGLFS_cjs.validateUpsell; }
|
|
2028
3189
|
});
|
|
3190
|
+
exports.AssetsContext = AssetsContext;
|
|
3191
|
+
exports.AssetsProvider = AssetsProvider;
|
|
2029
3192
|
exports.Back = Back;
|
|
2030
3193
|
exports.Checkout = Checkout;
|
|
3194
|
+
exports.CheckoutResume = CheckoutResume;
|
|
2031
3195
|
exports.Choice = Choice;
|
|
2032
3196
|
exports.EVENT_CATALOG = EVENT_CATALOG;
|
|
2033
3197
|
exports.FunnelProvider = FunnelProvider;
|
|
2034
3198
|
exports.FunnelToaster = FunnelToaster;
|
|
2035
3199
|
exports.FunnelView = FunnelView;
|
|
2036
|
-
exports.INLINE_SURFACES = INLINE_SURFACES;
|
|
2037
3200
|
exports.Modal = Modal;
|
|
2038
3201
|
exports.Next = Next;
|
|
2039
|
-
exports.PROVIDER_PROFILES = PROVIDER_PROFILES;
|
|
2040
3202
|
exports.Script = Script;
|
|
2041
3203
|
exports.Sheet = Sheet;
|
|
2042
3204
|
exports.Upsell = Upsell;
|
|
2043
3205
|
exports.VariableStore = VariableStore;
|
|
2044
|
-
exports.assignVariant = assignVariant;
|
|
2045
3206
|
exports.attachBus = attachBus;
|
|
2046
|
-
exports.bucketingSeed = bucketingSeed;
|
|
2047
3207
|
exports.buildAcquisition = buildAcquisition;
|
|
2048
|
-
exports.
|
|
2049
|
-
exports.checkoutError = checkoutError;
|
|
2050
|
-
exports.compileManifest = compileManifest;
|
|
3208
|
+
exports.buildContext = buildContext;
|
|
2051
3209
|
exports.createBus = createBus;
|
|
2052
3210
|
exports.createConsoleTracker = createConsoleTracker;
|
|
2053
3211
|
exports.createFunnelStore = createFunnelStore;
|
|
3212
|
+
exports.createFunnelTree = createFunnelTree;
|
|
2054
3213
|
exports.createMockDriver = createMockDriver;
|
|
2055
|
-
exports.
|
|
3214
|
+
exports.createPlatformTracker = createPlatformTracker;
|
|
2056
3215
|
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;
|
|
3216
|
+
exports.driverWithEmail = driverWithEmail;
|
|
2065
3217
|
exports.hideModal = hideModal;
|
|
2066
3218
|
exports.integrationEvents = integrationEvents;
|
|
2067
|
-
exports.isInlineSurface = isInlineSurface;
|
|
2068
3219
|
exports.isIntegrationEvent = isIntegrationEvent;
|
|
2069
|
-
exports.isMerchantOfRecord = isMerchantOfRecord;
|
|
2070
|
-
exports.isOrchestrator = isOrchestrator;
|
|
2071
|
-
exports.isRtl = isRtl;
|
|
2072
3220
|
exports.isTrackableEvent = isTrackableEvent;
|
|
2073
|
-
exports.isVariantKey = isVariantKey;
|
|
2074
3221
|
exports.newEventId = newEventId;
|
|
2075
|
-
exports.nextPage = nextPage;
|
|
2076
|
-
exports.outgoingKeys = outgoingKeys;
|
|
2077
|
-
exports.pageMeta = pageMeta;
|
|
2078
|
-
exports.parseSlotKey = parseSlotKey;
|
|
2079
|
-
exports.pickByWeight = pickByWeight;
|
|
2080
3222
|
exports.registerModal = registerModal;
|
|
2081
3223
|
exports.removeModal = removeModal;
|
|
2082
|
-
exports.resolveExperiments = resolveExperiments;
|
|
2083
|
-
exports.resolveLocale = resolveLocale;
|
|
2084
|
-
exports.resolveProduct = resolveProduct;
|
|
2085
|
-
exports.resolveRoute = resolveRoute;
|
|
2086
3224
|
exports.showModal = showModal;
|
|
2087
|
-
exports.
|
|
3225
|
+
exports.toast = toast;
|
|
2088
3226
|
exports.unregisterModal = unregisterModal;
|
|
3227
|
+
exports.useActiveLocale = useActiveLocale;
|
|
3228
|
+
exports.useAsset = useAsset;
|
|
3229
|
+
exports.useAssets = useAssets;
|
|
2089
3230
|
exports.useCheckout = useCheckout;
|
|
2090
3231
|
exports.useClickIds = useClickIds;
|
|
2091
3232
|
exports.useContextValue = useContextValue;
|
|
@@ -2106,9 +3247,6 @@ exports.useTracker = useTracker;
|
|
|
2106
3247
|
exports.useTranslation = useTranslation;
|
|
2107
3248
|
exports.useUserAttribute = useUserAttribute;
|
|
2108
3249
|
exports.useUtm = useUtm;
|
|
2109
|
-
exports.validateCheckout = validateCheckout;
|
|
2110
|
-
exports.validateExperiments = validateExperiments;
|
|
2111
|
-
exports.validateUpsell = validateUpsell;
|
|
2112
3250
|
exports.withBus = withBus;
|
|
2113
3251
|
//# sourceMappingURL=index.cjs.map
|
|
2114
3252
|
//# sourceMappingURL=index.cjs.map
|