@hook-sdk/template 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -28,11 +28,21 @@ __export(index_exports, {
28
28
  DefaultSignupScreen: () => DefaultSignupScreen,
29
29
  EmptyState: () => EmptyState,
30
30
  ErrorBoundary: () => ErrorBoundary,
31
+ InstallGate: () => InstallGate,
32
+ InstallSplash: () => InstallSplash,
31
33
  LoadingState: () => LoadingState,
32
34
  PushPrompt: () => PushPrompt2,
35
+ detectAndroidBrowser: () => detectAndroidBrowser,
36
+ detectIOSBrowser: () => detectIOSBrowser,
37
+ detectInAppApp: () => detectInAppApp,
38
+ detectPlatform: () => detectPlatform,
39
+ detectStandalone: () => detectStandalone,
40
+ shouldBlockInstall: () => shouldBlockInstall,
41
+ shouldShowPermanentOption: () => shouldShowPermanentOption,
33
42
  useAuth: () => useAuth,
34
43
  useAuthPrimitives: () => useAuthPrimitives,
35
44
  useForgotForm: () => useForgotForm,
45
+ useInstallPrompt: () => useInstallPrompt,
36
46
  useLoginForm: () => useLoginForm,
37
47
  usePaywallState: () => usePaywallState,
38
48
  usePush: () => usePush,
@@ -45,7 +55,7 @@ __export(index_exports, {
45
55
  module.exports = __toCommonJS(index_exports);
46
56
 
47
57
  // src/AppRoot.tsx
48
- var import_react12 = require("react");
58
+ var import_react16 = require("react");
49
59
  var import_sdk9 = require("@hook-sdk/sdk");
50
60
 
51
61
  // src/internal/TemplateConfigContext.tsx
@@ -210,10 +220,1226 @@ function PushPrompt() {
210
220
  return null;
211
221
  }
212
222
 
213
- // src/defaults/ErrorBoundary.tsx
223
+ // src/components/InstallGate/InstallGate.tsx
224
+ var import_react8 = require("react");
225
+
226
+ // src/hooks/useInstallPrompt.ts
214
227
  var import_react5 = require("react");
228
+ var IOS_RE = /iPad|iPhone|iPod/;
229
+ var IOS_NON_SAFARI_RE = /CriOS|FxiOS|EdgiOS/;
230
+ var ANDROID_RE = /Android/;
231
+ var IN_APP_RE = /Instagram|FBAN|FBAV|BytedanceWebview|TikTok|Line\/|Twitter|Snapchat|Pinterest|LinkedIn|WhatsApp|MicroMessenger|Telegram/i;
232
+ var PERMANENT_DISMISS_REPROMPT_DAYS = 14;
233
+ var SESSION_SKIPS_BEFORE_PERMANENT_OPTION = 2;
234
+ var storageKey = {
235
+ sessionSkip: (slug) => `install:${slug}:session-skip`,
236
+ dismissedAt: (slug) => `install:${slug}:dismissed-at`,
237
+ installedAt: (slug) => `install:${slug}:installed-at`,
238
+ skipCount: (slug) => `install:${slug}:skip-count`
239
+ };
240
+ function detectPlatform(ua) {
241
+ if (IN_APP_RE.test(ua)) return "in-app";
242
+ const isIOS = IOS_RE.test(ua);
243
+ if (isIOS) {
244
+ const isSafari = /Safari/.test(ua) && !IOS_NON_SAFARI_RE.test(ua);
245
+ return isSafari ? "ios-safari" : "ios-other";
246
+ }
247
+ if (ANDROID_RE.test(ua)) return "android";
248
+ return "desktop";
249
+ }
250
+ function detectIOSBrowser(ua) {
251
+ if (!IOS_RE.test(ua)) return null;
252
+ if (/CriOS/.test(ua)) return "chrome";
253
+ if (/FxiOS/.test(ua)) return "firefox";
254
+ if (/EdgiOS/.test(ua)) return "edge";
255
+ if (/Safari/.test(ua)) return "safari";
256
+ return "other";
257
+ }
258
+ function detectAndroidBrowser(ua) {
259
+ if (!ANDROID_RE.test(ua)) return null;
260
+ if (/EdgA/.test(ua)) return "edge";
261
+ if (/OPR|OPT/.test(ua)) return "opera";
262
+ if (/SamsungBrowser/.test(ua)) return "samsung";
263
+ if (/Firefox/.test(ua)) return "firefox";
264
+ if (/Chrome/.test(ua)) return "chrome";
265
+ return "other";
266
+ }
267
+ function detectInAppApp(ua) {
268
+ if (!IN_APP_RE.test(ua)) return null;
269
+ if (/Instagram/i.test(ua)) return "instagram";
270
+ if (/FBAN|FBAV/.test(ua)) return "facebook";
271
+ if (/BytedanceWebview|TikTok/i.test(ua)) return "tiktok";
272
+ if (/WhatsApp/i.test(ua)) return "whatsapp";
273
+ if (/Twitter/i.test(ua)) return "twitter";
274
+ if (/LinkedIn/i.test(ua)) return "linkedin";
275
+ if (/Telegram/i.test(ua)) return "telegram";
276
+ if (/Line\//i.test(ua)) return "line";
277
+ if (/Snapchat/i.test(ua)) return "snapchat";
278
+ if (/Pinterest/i.test(ua)) return "pinterest";
279
+ if (/MicroMessenger/i.test(ua)) return "wechat";
280
+ return "other";
281
+ }
282
+ function detectStandalone() {
283
+ if (typeof window === "undefined" || typeof navigator === "undefined") {
284
+ return { installed: false, source: null };
285
+ }
286
+ const mm = window.matchMedia?.("(display-mode: standalone)");
287
+ if (mm?.matches) return { installed: true, source: "match_media" };
288
+ const fs = window.matchMedia?.("(display-mode: fullscreen)");
289
+ if (fs?.matches) return { installed: true, source: "match_media" };
290
+ if (navigator.standalone === true) return { installed: true, source: "navigator_standalone" };
291
+ return { installed: false, source: null };
292
+ }
293
+ function track(event, props) {
294
+ if (typeof window === "undefined") return;
295
+ window.posthog?.capture?.(event, props);
296
+ }
297
+ function pickVariant(state) {
298
+ if (state.isInstalled) return "none";
299
+ switch (state.platform) {
300
+ case "android":
301
+ return state.isInstallable ? "android-native" : "android-manual";
302
+ case "ios-safari":
303
+ return "ios-safari";
304
+ case "ios-other":
305
+ return "ios-other";
306
+ case "in-app":
307
+ return "in-app";
308
+ case "desktop":
309
+ return state.isInstallable ? "desktop" : "none";
310
+ default:
311
+ return "none";
312
+ }
313
+ }
314
+ function safeStorage() {
315
+ if (typeof localStorage === "undefined") return null;
316
+ try {
317
+ localStorage.setItem("__install_probe", "1");
318
+ localStorage.removeItem("__install_probe");
319
+ return localStorage;
320
+ } catch {
321
+ return null;
322
+ }
323
+ }
324
+ function readPermanentDismiss(slug) {
325
+ const storage = safeStorage();
326
+ if (!storage) return { dismissed: false, dismissedAt: null };
327
+ const raw = storage.getItem(storageKey.dismissedAt(slug));
328
+ if (!raw) return { dismissed: false, dismissedAt: null };
329
+ const parsed = Date.parse(raw);
330
+ if (Number.isNaN(parsed)) return { dismissed: false, dismissedAt: null };
331
+ const daysAgo = (Date.now() - parsed) / (1e3 * 60 * 60 * 24);
332
+ return { dismissed: daysAgo < PERMANENT_DISMISS_REPROMPT_DAYS, dismissedAt: raw };
333
+ }
334
+ function readInstalledMarker(slug) {
335
+ const storage = safeStorage();
336
+ if (!storage) return false;
337
+ return storage.getItem(storageKey.installedAt(slug)) !== null;
338
+ }
339
+ function readSkipCount(slug) {
340
+ const storage = safeStorage();
341
+ if (!storage) return 0;
342
+ const raw = storage.getItem(storageKey.skipCount(slug));
343
+ const n = raw ? Number.parseInt(raw, 10) : 0;
344
+ return Number.isFinite(n) && n >= 0 ? n : 0;
345
+ }
346
+ function readSessionSkip(slug) {
347
+ if (typeof sessionStorage === "undefined") return false;
348
+ try {
349
+ return sessionStorage.getItem(storageKey.sessionSkip(slug)) === "true";
350
+ } catch {
351
+ return false;
352
+ }
353
+ }
354
+ function useInstallPrompt(slug) {
355
+ const ua = typeof navigator !== "undefined" && typeof navigator.userAgent === "string" ? navigator.userAgent : "";
356
+ const platform = detectPlatform(ua);
357
+ const iosBrowser = detectIOSBrowser(ua);
358
+ const androidBrowser = detectAndroidBrowser(ua);
359
+ const inAppApp = detectInAppApp(ua);
360
+ const [isInstallable, setIsInstallable] = (0, import_react5.useState)(() => {
361
+ if (typeof window === "undefined") return false;
362
+ return window.__pwaInstallPrompt != null;
363
+ });
364
+ const [isInstalled, setIsInstalled] = (0, import_react5.useState)(() => {
365
+ const { installed } = detectStandalone();
366
+ return installed || readInstalledMarker(slug);
367
+ });
368
+ const [isDismissedSession, setIsDismissedSession] = (0, import_react5.useState)(() => readSessionSkip(slug));
369
+ const [isDismissedPermanent, setIsDismissedPermanent] = (0, import_react5.useState)(() => readPermanentDismiss(slug).dismissed);
370
+ const [skipCount, setSkipCount] = (0, import_react5.useState)(() => readSkipCount(slug));
371
+ (0, import_react5.useEffect)(() => {
372
+ if (typeof window === "undefined") return;
373
+ if (window.__pwaInstallPrompt) {
374
+ setIsInstallable(true);
375
+ }
376
+ const onPrompt = (e) => {
377
+ e.preventDefault();
378
+ window.__pwaInstallPrompt = e;
379
+ setIsInstallable(true);
380
+ };
381
+ const onInstalled = () => {
382
+ setIsInstalled(true);
383
+ setIsInstallable(false);
384
+ window.__pwaInstallPrompt = null;
385
+ const storage = safeStorage();
386
+ if (storage) storage.setItem(storageKey.installedAt(slug), (/* @__PURE__ */ new Date()).toISOString());
387
+ };
388
+ window.addEventListener("beforeinstallprompt", onPrompt);
389
+ window.addEventListener("appinstalled", onInstalled);
390
+ return () => {
391
+ window.removeEventListener("beforeinstallprompt", onPrompt);
392
+ window.removeEventListener("appinstalled", onInstalled);
393
+ };
394
+ }, [slug]);
395
+ (0, import_react5.useEffect)(() => {
396
+ if (typeof window === "undefined") return;
397
+ const mq = window.matchMedia?.("(display-mode: standalone)");
398
+ if (!mq) return;
399
+ const handler = (e) => {
400
+ if (e.matches) {
401
+ setIsInstalled(true);
402
+ track("pwa_install_standalone_detected", { slug, source: "match_media" });
403
+ }
404
+ };
405
+ mq.addEventListener?.("change", handler);
406
+ return () => mq.removeEventListener?.("change", handler);
407
+ }, [slug]);
408
+ const variant = pickVariant({
409
+ platform,
410
+ iosBrowser,
411
+ androidBrowser,
412
+ inAppApp,
413
+ isInstallable,
414
+ isInstalled,
415
+ isDismissedSession,
416
+ isDismissedPermanent,
417
+ skipCount
418
+ });
419
+ const promptInstall = (0, import_react5.useCallback)(async () => {
420
+ if (typeof window === "undefined") return false;
421
+ const prompt = window.__pwaInstallPrompt;
422
+ if (!prompt) return false;
423
+ track("pwa_install_prompt_clicked", { slug });
424
+ try {
425
+ await prompt.prompt();
426
+ const { outcome } = await prompt.userChoice;
427
+ track("pwa_install_prompt_outcome", { slug, outcome });
428
+ if (outcome === "accepted") {
429
+ setIsInstalled(true);
430
+ setIsInstallable(false);
431
+ window.__pwaInstallPrompt = null;
432
+ const storage = safeStorage();
433
+ if (storage) storage.setItem(storageKey.installedAt(slug), (/* @__PURE__ */ new Date()).toISOString());
434
+ return true;
435
+ }
436
+ return false;
437
+ } catch {
438
+ return false;
439
+ }
440
+ }, [slug]);
441
+ const dismissSession = (0, import_react5.useCallback)(() => {
442
+ if (typeof sessionStorage !== "undefined") {
443
+ try {
444
+ sessionStorage.setItem(storageKey.sessionSkip(slug), "true");
445
+ } catch {
446
+ }
447
+ }
448
+ const storage = safeStorage();
449
+ const newCount = skipCount + 1;
450
+ if (storage) storage.setItem(storageKey.skipCount(slug), String(newCount));
451
+ setSkipCount(newCount);
452
+ setIsDismissedSession(true);
453
+ track("pwa_install_session_skip", { slug, platform, skip_count: newCount });
454
+ }, [slug, skipCount, platform]);
455
+ const dismissPermanent = (0, import_react5.useCallback)(() => {
456
+ const storage = safeStorage();
457
+ if (storage) storage.setItem(storageKey.dismissedAt(slug), (/* @__PURE__ */ new Date()).toISOString());
458
+ setIsDismissedPermanent(true);
459
+ track("pwa_install_permanent_dismiss", { slug, platform, prior_skip_count: skipCount });
460
+ }, [slug, platform, skipCount]);
461
+ const redirectToSafari = (0, import_react5.useCallback)(() => {
462
+ if (typeof location === "undefined") return;
463
+ track("pwa_install_redirect_to_safari", { slug });
464
+ const url = `safari-https://${location.host}${location.pathname}${location.search}${location.hash}`;
465
+ try {
466
+ window.location.href = url;
467
+ } catch {
468
+ }
469
+ }, [slug]);
470
+ const copyLink = (0, import_react5.useCallback)(async () => {
471
+ if (typeof navigator === "undefined" || typeof location === "undefined") return;
472
+ try {
473
+ await navigator.clipboard?.writeText?.(location.href);
474
+ } catch {
475
+ }
476
+ }, []);
477
+ const reset = (0, import_react5.useCallback)(() => {
478
+ const storage = safeStorage();
479
+ if (storage) {
480
+ storage.removeItem(storageKey.dismissedAt(slug));
481
+ storage.removeItem(storageKey.installedAt(slug));
482
+ storage.removeItem(storageKey.skipCount(slug));
483
+ }
484
+ if (typeof sessionStorage !== "undefined") {
485
+ try {
486
+ sessionStorage.removeItem(storageKey.sessionSkip(slug));
487
+ } catch {
488
+ }
489
+ }
490
+ setIsDismissedSession(false);
491
+ setIsDismissedPermanent(false);
492
+ setSkipCount(0);
493
+ }, [slug]);
494
+ return {
495
+ platform,
496
+ iosBrowser,
497
+ androidBrowser,
498
+ inAppApp,
499
+ isInstallable,
500
+ isInstalled,
501
+ isDismissedSession,
502
+ isDismissedPermanent,
503
+ skipCount,
504
+ variant,
505
+ promptInstall,
506
+ dismissSession,
507
+ dismissPermanent,
508
+ redirectToSafari,
509
+ copyLink,
510
+ reset
511
+ };
512
+ }
513
+ function shouldBlockInstall(state, now = Date.now()) {
514
+ if (state.isInstalled) return false;
515
+ if (state.variant === "none") return false;
516
+ if (state.isDismissedSession) return false;
517
+ if (state.isDismissedPermanent) {
518
+ void now;
519
+ return false;
520
+ }
521
+ if (state.platform === "desktop" && !state.isInstallable) return false;
522
+ if (state.platform === "unknown") return false;
523
+ return true;
524
+ }
525
+ function shouldShowPermanentOption(state) {
526
+ return state.skipCount >= SESSION_SKIPS_BEFORE_PERMANENT_OPTION;
527
+ }
528
+
529
+ // src/components/InstallGate/copy.ts
530
+ var INSTALL_COPY = {
531
+ android: {
532
+ native: {
533
+ title: "Instale no seu celular",
534
+ subtitle: "Acesso r\xE1pido, sem precisar do navegador",
535
+ cta: "Baixar",
536
+ skip: "Continuar no navegador",
537
+ skipPermanent: "N\xE3o me pergunte mais"
538
+ },
539
+ manual: {
540
+ title: "Instale em 2 toques",
541
+ subtitle: 'Toque no menu do navegador e escolha "Instalar aplicativo"',
542
+ step1: "Toque no menu do navegador",
543
+ step2: 'Escolha "Instalar aplicativo"',
544
+ cta: "Entendi",
545
+ skip: "Continuar no navegador",
546
+ skipPermanent: "N\xE3o me pergunte mais"
547
+ }
548
+ },
549
+ iosSafari: {
550
+ title: "Adicione \xE0 sua Tela de In\xEDcio",
551
+ subtitle: "Siga os 3 passos",
552
+ step1: {
553
+ title: "Toque em Compartilhar",
554
+ subtitle: "Na barra inferior do Safari"
555
+ },
556
+ step2: {
557
+ title: 'Role e toque em "Adicionar \xE0 Tela de In\xEDcio"',
558
+ iconLabel: "Adicionar \xE0 Tela de In\xEDcio"
559
+ },
560
+ step3: {
561
+ title: 'Toque em "Adicionar" pra confirmar',
562
+ buttonLabel: "Adicionar"
563
+ },
564
+ skip: "Continuar no Safari",
565
+ skipPermanent: "N\xE3o me pergunte mais"
566
+ },
567
+ iosOther: {
568
+ title: "Abra no Safari pra instalar",
569
+ subtitle: "No Chrome/Firefox/Edge do iPhone n\xE3o d\xE1 pra instalar PWA. Abra o link no Safari.",
570
+ ctaPrimary: "Abrir no Safari",
571
+ ctaSecondary: "Copiar link",
572
+ copiedToast: "Link copiado. Cole no Safari.",
573
+ skip: "Continuar mesmo assim",
574
+ skipPermanent: "N\xE3o me pergunte mais"
575
+ },
576
+ inApp: {
577
+ instagram: {
578
+ title: "Pra instalar, abra fora do Instagram",
579
+ step1: "Toque em \u22EF (canto superior direito)",
580
+ step2: 'Escolha "Abrir no navegador externo"'
581
+ },
582
+ facebook: {
583
+ title: "Pra instalar, abra fora do Facebook",
584
+ step1: "Toque em \u22EE",
585
+ step2: 'Escolha "Abrir no navegador"'
586
+ },
587
+ tiktok: {
588
+ title: "Pra instalar, abra fora do TikTok",
589
+ step1: "Toque em \u22EF",
590
+ step2: 'Escolha "Abrir no Safari" (iOS) ou "Abrir no Chrome" (Android)'
591
+ },
592
+ whatsapp: {
593
+ title: "Pra instalar, abra fora do WhatsApp",
594
+ step1: "Toque longo no link",
595
+ step2: 'Escolha "Abrir no navegador"'
596
+ },
597
+ twitter: {
598
+ title: "Pra instalar, abra fora do Twitter",
599
+ step1: "Toque em \u22EF",
600
+ step2: 'Escolha "Abrir no navegador"'
601
+ },
602
+ linkedin: {
603
+ title: "Pra instalar, abra fora do LinkedIn",
604
+ step1: "Toque em \u22EF",
605
+ step2: 'Escolha "Abrir no navegador"'
606
+ },
607
+ telegram: {
608
+ title: "Pra instalar, abra fora do Telegram",
609
+ step1: "Toque em \u22EE",
610
+ step2: 'Escolha "Abrir no navegador"'
611
+ },
612
+ line: {
613
+ title: "Pra instalar, abra fora do LINE",
614
+ step1: "Toque em \u22EF",
615
+ step2: 'Escolha "Abrir no navegador"'
616
+ },
617
+ snapchat: {
618
+ title: "Pra instalar, abra fora do Snapchat",
619
+ step1: "Mantenha pressionado o link",
620
+ step2: 'Escolha "Abrir no navegador"'
621
+ },
622
+ pinterest: {
623
+ title: "Pra instalar, abra fora do Pinterest",
624
+ step1: "Toque em \u22EF",
625
+ step2: 'Escolha "Abrir no navegador"'
626
+ },
627
+ wechat: {
628
+ title: "Pra instalar, abra fora do WeChat",
629
+ step1: "Toque em \u22EF",
630
+ step2: 'Escolha "Abrir no navegador"'
631
+ },
632
+ other: {
633
+ title: "Abra no navegador do celular",
634
+ step1: "Toque no menu do app atual",
635
+ step2: 'Escolha "Abrir no Chrome" ou "Abrir no Safari"'
636
+ },
637
+ copy: "Copiar link",
638
+ copiedToast: "Link copiado. Cole no Chrome/Safari.",
639
+ skip: "Continuar aqui mesmo",
640
+ skipPermanent: "N\xE3o me pergunte mais"
641
+ },
642
+ desktop: {
643
+ title: "Instale no computador",
644
+ subtitle: "Acesso r\xE1pido",
645
+ cta: "Baixar",
646
+ close: "Fechar"
647
+ }
648
+ };
649
+
650
+ // src/components/InstallGate/InstallSplash.tsx
215
651
  var import_jsx_runtime7 = require("react/jsx-runtime");
216
- var ErrorBoundary = class extends import_react5.Component {
652
+ function InstallSplash({ children, title, subtitle }) {
653
+ const { name, theme } = useTemplateConfig();
654
+ const iconUrl = theme.icon_url || theme.logo_url || null;
655
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
656
+ "div",
657
+ {
658
+ role: "dialog",
659
+ "aria-modal": "true",
660
+ "aria-labelledby": "install-splash-title",
661
+ "aria-describedby": subtitle ? "install-splash-subtitle" : void 0,
662
+ style: overlayStyle,
663
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: cardStyle, children: [
664
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", justifyContent: "center", marginBottom: 16 }, children: iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
665
+ "img",
666
+ {
667
+ src: iconUrl,
668
+ alt: `\xCDcone de ${name}`,
669
+ style: { width: 80, height: 80, borderRadius: 20, objectFit: "cover" }
670
+ }
671
+ ) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
672
+ "div",
673
+ {
674
+ style: {
675
+ width: 80,
676
+ height: 80,
677
+ borderRadius: 20,
678
+ background: "var(--hook-color-primary)",
679
+ color: "#fff",
680
+ display: "flex",
681
+ alignItems: "center",
682
+ justifyContent: "center",
683
+ fontSize: 36,
684
+ fontWeight: 700
685
+ },
686
+ children: name.charAt(0).toUpperCase()
687
+ }
688
+ ) }),
689
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { id: "install-splash-title", style: titleStyle, children: title }),
690
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { id: "install-splash-subtitle", style: subtitleStyle, children: subtitle }),
691
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { marginTop: 24 }, children }),
692
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: footerStyle, children: "por Hook" })
693
+ ] })
694
+ }
695
+ );
696
+ }
697
+ var primaryButtonStyle = {
698
+ width: "100%",
699
+ padding: "14px 20px",
700
+ background: "var(--hook-color-primary)",
701
+ color: "#fff",
702
+ border: "none",
703
+ borderRadius: 999,
704
+ fontSize: 17,
705
+ fontWeight: 600,
706
+ cursor: "pointer",
707
+ marginBottom: 12
708
+ };
709
+ var secondaryButtonStyle = {
710
+ width: "100%",
711
+ padding: "12px 20px",
712
+ background: "transparent",
713
+ color: "var(--hook-color-primary)",
714
+ border: "1px solid var(--hook-color-primary)",
715
+ borderRadius: 999,
716
+ fontSize: 15,
717
+ fontWeight: 500,
718
+ cursor: "pointer",
719
+ marginBottom: 12
720
+ };
721
+ var skipLinkStyle = {
722
+ display: "block",
723
+ width: "100%",
724
+ padding: "10px",
725
+ marginTop: 8,
726
+ background: "transparent",
727
+ color: "#555",
728
+ border: "none",
729
+ fontSize: 14,
730
+ textDecoration: "underline",
731
+ cursor: "pointer",
732
+ textAlign: "center"
733
+ };
734
+ var skipPermanentLinkStyle = {
735
+ ...skipLinkStyle,
736
+ color: "#999",
737
+ fontSize: 13,
738
+ marginTop: 4
739
+ };
740
+ var overlayStyle = {
741
+ position: "fixed",
742
+ inset: 0,
743
+ background: "var(--hook-color-background, #fafafa)",
744
+ zIndex: 1e4,
745
+ display: "flex",
746
+ alignItems: "center",
747
+ justifyContent: "center",
748
+ padding: 20,
749
+ overflow: "auto"
750
+ };
751
+ var cardStyle = {
752
+ width: "100%",
753
+ maxWidth: 420,
754
+ padding: 24,
755
+ textAlign: "center"
756
+ };
757
+ var titleStyle = {
758
+ fontSize: 24,
759
+ fontWeight: 700,
760
+ lineHeight: 1.2,
761
+ margin: "0 0 8px 0",
762
+ color: "#111"
763
+ };
764
+ var subtitleStyle = {
765
+ fontSize: 15,
766
+ lineHeight: 1.4,
767
+ color: "#555",
768
+ margin: 0
769
+ };
770
+ var footerStyle = {
771
+ fontSize: 11,
772
+ color: "#aaa",
773
+ marginTop: 32,
774
+ letterSpacing: 0.5
775
+ };
776
+
777
+ // src/components/InstallGate/icons.tsx
778
+ var import_jsx_runtime8 = require("react/jsx-runtime");
779
+ var defaultSvgProps = (size) => ({
780
+ width: size,
781
+ height: size,
782
+ viewBox: "0 0 24 24",
783
+ fill: "none",
784
+ stroke: "currentColor",
785
+ strokeWidth: 2,
786
+ strokeLinecap: "round",
787
+ strokeLinejoin: "round"
788
+ });
789
+ function ShareIconIOS({ size = 24, style, className }) {
790
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
791
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 2L12 15" }),
792
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 6L12 2L16 6" }),
793
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 11v9a2 2 0 002 2h12a2 2 0 002-2v-9" })
794
+ ] });
795
+ }
796
+ function MenuDotsVerticalIcon({ size = 24, style, className }) {
797
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
798
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "5", r: "1.5" }),
799
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
800
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "19", r: "1.5" })
801
+ ] });
802
+ }
803
+ function MenuDotsHorizontalIcon({ size = 24, style, className }) {
804
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
805
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "5", cy: "12", r: "1.5" }),
806
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
807
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "19", cy: "12", r: "1.5" })
808
+ ] });
809
+ }
810
+ function SquarePlusIcon({ size = 24, style, className }) {
811
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
812
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
813
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 8v8" }),
814
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 12h8" })
815
+ ] });
816
+ }
817
+ function DownloadIcon({ size = 24, style, className }) {
818
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
819
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" }),
820
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "7 10 12 15 17 10" }),
821
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
822
+ ] });
823
+ }
824
+ function ExternalLinkIcon({ size = 24, style, className }) {
825
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
826
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }),
827
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "15 3 21 3 21 9" }),
828
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
829
+ ] });
830
+ }
831
+ function XIcon({ size = 20, style, className }) {
832
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
833
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
834
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
835
+ ] });
836
+ }
837
+
838
+ // src/components/InstallGate/variants/AndroidNativeVariant.tsx
839
+ var import_jsx_runtime9 = require("react/jsx-runtime");
840
+ function AndroidNativeVariant({
841
+ state,
842
+ actions
843
+ }) {
844
+ const copy = INSTALL_COPY.android.native;
845
+ const showPermanent = shouldShowPermanentOption(state);
846
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
847
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
848
+ "button",
849
+ {
850
+ "data-testid": "install-prompt-cta-android-native",
851
+ type: "button",
852
+ onClick: () => void actions.promptInstall(),
853
+ style: { ...primaryButtonStyle, display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8 },
854
+ children: [
855
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DownloadIcon, { size: 18 }),
856
+ copy.cta
857
+ ]
858
+ }
859
+ ),
860
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
861
+ "button",
862
+ {
863
+ "data-testid": "install-prompt-skip-session",
864
+ type: "button",
865
+ onClick: actions.dismissSession,
866
+ style: skipLinkStyle,
867
+ children: copy.skip
868
+ }
869
+ ),
870
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
871
+ "button",
872
+ {
873
+ "data-testid": "install-prompt-skip-permanent",
874
+ type: "button",
875
+ onClick: actions.dismissPermanent,
876
+ style: skipPermanentLinkStyle,
877
+ children: copy.skipPermanent
878
+ }
879
+ )
880
+ ] });
881
+ }
882
+
883
+ // src/components/InstallGate/variants/AndroidManualVariant.tsx
884
+ var import_jsx_runtime10 = require("react/jsx-runtime");
885
+ function AndroidManualVariant({
886
+ state,
887
+ actions
888
+ }) {
889
+ const copy = INSTALL_COPY.android.manual;
890
+ const showPermanent = shouldShowPermanentOption(state);
891
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(InstallSplash, { title: copy.title, children: [
892
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Step, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MenuDotsVerticalIcon, { size: 20 }), children: copy.step1 }),
893
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Step, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DownloadIcon, { size: 18 }), children: copy.step2 }),
894
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
895
+ "button",
896
+ {
897
+ "data-testid": "install-prompt-cta-android-manual",
898
+ type: "button",
899
+ onClick: actions.dismissSession,
900
+ style: primaryButtonStyle,
901
+ children: copy.cta
902
+ }
903
+ ),
904
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
905
+ "button",
906
+ {
907
+ "data-testid": "install-prompt-skip-session",
908
+ type: "button",
909
+ onClick: actions.dismissSession,
910
+ style: skipLinkStyle,
911
+ children: copy.skip
912
+ }
913
+ ),
914
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
915
+ "button",
916
+ {
917
+ "data-testid": "install-prompt-skip-permanent",
918
+ type: "button",
919
+ onClick: actions.dismissPermanent,
920
+ style: skipPermanentLinkStyle,
921
+ children: copy.skipPermanent
922
+ }
923
+ )
924
+ ] });
925
+ }
926
+ function Step({ n, icon, children }) {
927
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
928
+ "div",
929
+ {
930
+ style: {
931
+ display: "flex",
932
+ alignItems: "center",
933
+ gap: 12,
934
+ padding: "12px 14px",
935
+ background: "#f5f5f7",
936
+ borderRadius: 12,
937
+ marginBottom: 10,
938
+ textAlign: "left"
939
+ },
940
+ children: [
941
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
942
+ "div",
943
+ {
944
+ style: {
945
+ width: 28,
946
+ height: 28,
947
+ borderRadius: "50%",
948
+ background: "var(--hook-color-primary)",
949
+ color: "#fff",
950
+ display: "flex",
951
+ alignItems: "center",
952
+ justifyContent: "center",
953
+ fontSize: 14,
954
+ fontWeight: 700,
955
+ flexShrink: 0
956
+ },
957
+ children: n
958
+ }
959
+ ),
960
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { flex: 1, fontSize: 15, color: "#333" }, children }),
961
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
962
+ ]
963
+ }
964
+ );
965
+ }
966
+
967
+ // src/components/InstallGate/variants/IOSafariVariant.tsx
968
+ var import_jsx_runtime11 = require("react/jsx-runtime");
969
+ function IOSafariVariant({
970
+ state,
971
+ actions
972
+ }) {
973
+ const copy = INSTALL_COPY.iosSafari;
974
+ const showPermanent = shouldShowPermanentOption(state);
975
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
976
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
977
+ Step2,
978
+ {
979
+ n: 1,
980
+ title: copy.step1.title,
981
+ subtitle: copy.step1.subtitle,
982
+ visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
983
+ "div",
984
+ {
985
+ style: {
986
+ display: "flex",
987
+ justifyContent: "center",
988
+ alignItems: "center",
989
+ background: "#f5f5f7",
990
+ borderRadius: 12,
991
+ padding: "12px 0",
992
+ marginTop: 8
993
+ },
994
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
995
+ }
996
+ )
997
+ }
998
+ ),
999
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1000
+ Step2,
1001
+ {
1002
+ n: 2,
1003
+ title: copy.step2.title,
1004
+ visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1005
+ "div",
1006
+ {
1007
+ style: {
1008
+ display: "flex",
1009
+ alignItems: "center",
1010
+ gap: 10,
1011
+ background: "#f5f5f7",
1012
+ borderRadius: 12,
1013
+ padding: "12px 14px",
1014
+ marginTop: 8
1015
+ },
1016
+ children: [
1017
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
1018
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
1019
+ ]
1020
+ }
1021
+ )
1022
+ }
1023
+ ),
1024
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1025
+ Step2,
1026
+ {
1027
+ n: 3,
1028
+ title: copy.step3.title,
1029
+ visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1030
+ "div",
1031
+ {
1032
+ style: {
1033
+ display: "flex",
1034
+ justifyContent: "flex-end",
1035
+ background: "#f5f5f7",
1036
+ borderRadius: 12,
1037
+ padding: "10px 14px",
1038
+ marginTop: 8
1039
+ },
1040
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1041
+ "span",
1042
+ {
1043
+ style: {
1044
+ color: "var(--hook-color-primary)",
1045
+ fontSize: 15,
1046
+ fontWeight: 600
1047
+ },
1048
+ children: copy.step3.buttonLabel
1049
+ }
1050
+ )
1051
+ }
1052
+ )
1053
+ }
1054
+ ),
1055
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1056
+ "button",
1057
+ {
1058
+ "data-testid": "install-prompt-skip-session",
1059
+ type: "button",
1060
+ onClick: actions.dismissSession,
1061
+ style: { ...skipLinkStyle, marginTop: 16 },
1062
+ children: copy.skip
1063
+ }
1064
+ ),
1065
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1066
+ "button",
1067
+ {
1068
+ "data-testid": "install-prompt-skip-permanent",
1069
+ type: "button",
1070
+ onClick: actions.dismissPermanent,
1071
+ style: skipPermanentLinkStyle,
1072
+ children: copy.skipPermanent
1073
+ }
1074
+ )
1075
+ ] });
1076
+ }
1077
+ function Step2({
1078
+ n,
1079
+ title,
1080
+ subtitle,
1081
+ visual
1082
+ }) {
1083
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1084
+ "div",
1085
+ {
1086
+ style: {
1087
+ display: "flex",
1088
+ alignItems: "flex-start",
1089
+ gap: 12,
1090
+ marginBottom: 16,
1091
+ textAlign: "left"
1092
+ },
1093
+ children: [
1094
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1095
+ "div",
1096
+ {
1097
+ style: {
1098
+ width: 32,
1099
+ height: 32,
1100
+ borderRadius: 10,
1101
+ background: "var(--hook-color-primary)",
1102
+ color: "#fff",
1103
+ display: "flex",
1104
+ alignItems: "center",
1105
+ justifyContent: "center",
1106
+ fontSize: 15,
1107
+ fontWeight: 700,
1108
+ flexShrink: 0
1109
+ },
1110
+ children: n
1111
+ }
1112
+ ),
1113
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { flex: 1 }, children: [
1114
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: 0, fontSize: 15, fontWeight: 500, color: "#111", lineHeight: 1.3 }, children: title }),
1115
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: "4px 0 0 0", fontSize: 13, color: "#777" }, children: subtitle }),
1116
+ visual
1117
+ ] })
1118
+ ]
1119
+ }
1120
+ );
1121
+ }
1122
+
1123
+ // src/components/InstallGate/variants/IOSOtherVariant.tsx
1124
+ var import_react6 = require("react");
1125
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1126
+ function IOSOtherVariant({
1127
+ state,
1128
+ actions
1129
+ }) {
1130
+ const copy = INSTALL_COPY.iosOther;
1131
+ const showPermanent = shouldShowPermanentOption(state);
1132
+ const [copied, setCopied] = (0, import_react6.useState)(false);
1133
+ const handleCopy = async () => {
1134
+ await actions.copyLink();
1135
+ setCopied(true);
1136
+ setTimeout(() => setCopied(false), 2e3);
1137
+ };
1138
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
1139
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1140
+ "button",
1141
+ {
1142
+ "data-testid": "install-prompt-cta-ios-other-primary",
1143
+ type: "button",
1144
+ onClick: actions.redirectToSafari,
1145
+ style: primaryButtonStyle,
1146
+ children: copy.ctaPrimary
1147
+ }
1148
+ ),
1149
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1150
+ "button",
1151
+ {
1152
+ "data-testid": "install-prompt-cta-ios-other-secondary",
1153
+ type: "button",
1154
+ onClick: () => void handleCopy(),
1155
+ style: secondaryButtonStyle,
1156
+ children: copied ? copy.copiedToast : copy.ctaSecondary
1157
+ }
1158
+ ),
1159
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1160
+ "button",
1161
+ {
1162
+ "data-testid": "install-prompt-skip-session",
1163
+ type: "button",
1164
+ onClick: actions.dismissSession,
1165
+ style: skipLinkStyle,
1166
+ children: copy.skip
1167
+ }
1168
+ ),
1169
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1170
+ "button",
1171
+ {
1172
+ "data-testid": "install-prompt-skip-permanent",
1173
+ type: "button",
1174
+ onClick: actions.dismissPermanent,
1175
+ style: skipPermanentLinkStyle,
1176
+ children: copy.skipPermanent
1177
+ }
1178
+ )
1179
+ ] });
1180
+ }
1181
+
1182
+ // src/components/InstallGate/variants/InAppBrowserVariant.tsx
1183
+ var import_react7 = require("react");
1184
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1185
+ function InAppBrowserVariant({
1186
+ state,
1187
+ actions
1188
+ }) {
1189
+ const app = state.inAppApp ?? "other";
1190
+ const appCopy = INSTALL_COPY.inApp[app] ?? INSTALL_COPY.inApp.other;
1191
+ const copy = INSTALL_COPY.inApp;
1192
+ const showPermanent = shouldShowPermanentOption(state);
1193
+ const [copied, setCopied] = (0, import_react7.useState)(false);
1194
+ const handleCopy = async () => {
1195
+ await actions.copyLink();
1196
+ setCopied(true);
1197
+ setTimeout(() => setCopied(false), 2e3);
1198
+ };
1199
+ const DotsIcon = app === "facebook" || app === "telegram" ? MenuDotsVerticalIcon : MenuDotsHorizontalIcon;
1200
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(InstallSplash, { title: appCopy.title, children: [
1201
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Step3, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DotsIcon, { size: 20 }), children: appCopy.step1 }),
1202
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Step3, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ExternalLinkIcon, { size: 18 }), children: appCopy.step2 }),
1203
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1204
+ "button",
1205
+ {
1206
+ "data-testid": "install-prompt-cta-inapp-copy",
1207
+ type: "button",
1208
+ onClick: () => void handleCopy(),
1209
+ style: { ...primaryButtonStyle, marginTop: 8 },
1210
+ children: copied ? copy.copiedToast : copy.copy
1211
+ }
1212
+ ),
1213
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1214
+ "button",
1215
+ {
1216
+ "data-testid": "install-prompt-skip-session",
1217
+ type: "button",
1218
+ onClick: actions.dismissSession,
1219
+ style: skipLinkStyle,
1220
+ children: copy.skip
1221
+ }
1222
+ ),
1223
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1224
+ "button",
1225
+ {
1226
+ "data-testid": "install-prompt-skip-permanent",
1227
+ type: "button",
1228
+ onClick: actions.dismissPermanent,
1229
+ style: skipPermanentLinkStyle,
1230
+ children: copy.skipPermanent
1231
+ }
1232
+ )
1233
+ ] });
1234
+ }
1235
+ function Step3({
1236
+ n,
1237
+ icon,
1238
+ children
1239
+ }) {
1240
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1241
+ "div",
1242
+ {
1243
+ style: {
1244
+ display: "flex",
1245
+ alignItems: "center",
1246
+ gap: 12,
1247
+ padding: "12px 14px",
1248
+ background: "#f5f5f7",
1249
+ borderRadius: 12,
1250
+ marginBottom: 10,
1251
+ textAlign: "left"
1252
+ },
1253
+ children: [
1254
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1255
+ "div",
1256
+ {
1257
+ style: {
1258
+ width: 28,
1259
+ height: 28,
1260
+ borderRadius: "50%",
1261
+ background: "var(--hook-color-primary)",
1262
+ color: "#fff",
1263
+ display: "flex",
1264
+ alignItems: "center",
1265
+ justifyContent: "center",
1266
+ fontSize: 14,
1267
+ fontWeight: 700,
1268
+ flexShrink: 0
1269
+ },
1270
+ children: n
1271
+ }
1272
+ ),
1273
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flex: 1, fontSize: 14, color: "#333" }, children }),
1274
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
1275
+ ]
1276
+ }
1277
+ );
1278
+ }
1279
+
1280
+ // src/components/InstallGate/variants/DesktopVariant.tsx
1281
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1282
+ function DesktopVariant({
1283
+ state,
1284
+ actions
1285
+ }) {
1286
+ const { name, theme } = useTemplateConfig();
1287
+ const copy = INSTALL_COPY.desktop;
1288
+ const iconUrl = theme.icon_url || theme.logo_url || null;
1289
+ if (!state.isInstallable) return null;
1290
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1291
+ "div",
1292
+ {
1293
+ role: "complementary",
1294
+ "aria-label": copy.title,
1295
+ style: bannerStyle,
1296
+ children: [
1297
+ iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1298
+ "img",
1299
+ {
1300
+ src: iconUrl,
1301
+ alt: "",
1302
+ style: { width: 40, height: 40, borderRadius: 10, objectFit: "cover", flexShrink: 0 }
1303
+ }
1304
+ ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1305
+ "div",
1306
+ {
1307
+ style: {
1308
+ width: 40,
1309
+ height: 40,
1310
+ borderRadius: 10,
1311
+ background: "var(--hook-color-primary)",
1312
+ color: "#fff",
1313
+ display: "flex",
1314
+ alignItems: "center",
1315
+ justifyContent: "center",
1316
+ fontSize: 18,
1317
+ fontWeight: 700,
1318
+ flexShrink: 0
1319
+ },
1320
+ children: name.charAt(0).toUpperCase()
1321
+ }
1322
+ ),
1323
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1324
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 14, fontWeight: 600, color: "#111" }, children: copy.title }),
1325
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 12, color: "#666" }, children: copy.subtitle })
1326
+ ] }),
1327
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1328
+ "button",
1329
+ {
1330
+ "data-testid": "install-prompt-cta-desktop",
1331
+ type: "button",
1332
+ onClick: () => void actions.promptInstall(),
1333
+ style: {
1334
+ padding: "8px 14px",
1335
+ background: "var(--hook-color-primary)",
1336
+ color: "#fff",
1337
+ border: "none",
1338
+ borderRadius: 999,
1339
+ fontSize: 13,
1340
+ fontWeight: 600,
1341
+ cursor: "pointer",
1342
+ display: "inline-flex",
1343
+ alignItems: "center",
1344
+ gap: 6,
1345
+ flexShrink: 0
1346
+ },
1347
+ children: [
1348
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DownloadIcon, { size: 14 }),
1349
+ copy.cta
1350
+ ]
1351
+ }
1352
+ ),
1353
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1354
+ "button",
1355
+ {
1356
+ "data-testid": "install-prompt-desktop-close",
1357
+ type: "button",
1358
+ onClick: actions.dismissPermanent,
1359
+ "aria-label": copy.close,
1360
+ style: {
1361
+ background: "transparent",
1362
+ border: "none",
1363
+ cursor: "pointer",
1364
+ color: "#888",
1365
+ padding: 4,
1366
+ flexShrink: 0
1367
+ },
1368
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(XIcon, { size: 16 })
1369
+ }
1370
+ )
1371
+ ]
1372
+ }
1373
+ );
1374
+ }
1375
+ var bannerStyle = {
1376
+ position: "fixed",
1377
+ bottom: 24,
1378
+ right: 24,
1379
+ zIndex: 1e4,
1380
+ display: "flex",
1381
+ alignItems: "center",
1382
+ gap: 12,
1383
+ padding: "12px 16px",
1384
+ background: "#fff",
1385
+ border: "1px solid rgba(0,0,0,0.08)",
1386
+ borderRadius: 16,
1387
+ boxShadow: "0 10px 30px rgba(0,0,0,0.12)",
1388
+ maxWidth: 400
1389
+ };
1390
+
1391
+ // src/components/InstallGate/InstallGate.tsx
1392
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1393
+ function InstallGate({ children }) {
1394
+ const { slug, features_enabled } = useTemplateConfig();
1395
+ const enabled = features_enabled.includes("install_prompt");
1396
+ const installState = useInstallPrompt(slug);
1397
+ const shouldBlock = enabled && shouldBlockInstall(installState);
1398
+ const trackedRef = (0, import_react8.useRef)(null);
1399
+ (0, import_react8.useEffect)(() => {
1400
+ if (!shouldBlock) return;
1401
+ if (typeof window === "undefined") return;
1402
+ const variantKey = `${slug}:${installState.variant}`;
1403
+ if (trackedRef.current === variantKey) return;
1404
+ trackedRef.current = variantKey;
1405
+ window.posthog?.capture?.("pwa_install_splash_shown", {
1406
+ slug,
1407
+ platform: installState.platform,
1408
+ browser: installState.iosBrowser ?? installState.androidBrowser ?? null,
1409
+ in_app_app: installState.inAppApp,
1410
+ variant: installState.variant
1411
+ });
1412
+ }, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
1413
+ if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
1414
+ if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
1415
+ if (installState.variant === "desktop") {
1416
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
1417
+ children,
1418
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DesktopVariant, { state: installState, actions: installState })
1419
+ ] });
1420
+ }
1421
+ if (!shouldBlock) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
1422
+ switch (installState.variant) {
1423
+ case "android-native":
1424
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AndroidNativeVariant, { state: installState, actions: installState });
1425
+ case "android-manual":
1426
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AndroidManualVariant, { state: installState, actions: installState });
1427
+ case "ios-safari":
1428
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IOSafariVariant, { state: installState, actions: installState });
1429
+ case "ios-other":
1430
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IOSOtherVariant, { state: installState, actions: installState });
1431
+ case "in-app":
1432
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(InAppBrowserVariant, { state: installState, actions: installState });
1433
+ case "none":
1434
+ default:
1435
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
1436
+ }
1437
+ }
1438
+
1439
+ // src/defaults/ErrorBoundary.tsx
1440
+ var import_react9 = require("react");
1441
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1442
+ var ErrorBoundary = class extends import_react9.Component {
217
1443
  state = { error: null };
218
1444
  static getDerivedStateFromError(error) {
219
1445
  return { error };
@@ -223,17 +1449,17 @@ var ErrorBoundary = class extends import_react5.Component {
223
1449
  }
224
1450
  render() {
225
1451
  if (this.state.error) {
226
- return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
227
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { children: "Algo deu errado" }),
228
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
1452
+ return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
1453
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { children: "Algo deu errado" }),
1454
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
229
1455
  ] });
230
1456
  }
231
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: this.props.children });
1457
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: this.props.children });
232
1458
  }
233
1459
  };
234
1460
 
235
1461
  // src/hooks/useLoginForm.ts
236
- var import_react6 = require("react");
1462
+ var import_react10 = require("react");
237
1463
  var import_sdk5 = require("@hook-sdk/sdk");
238
1464
 
239
1465
  // src/errors.ts
@@ -270,22 +1496,22 @@ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
270
1496
  var MIN_PASSWORD = 8;
271
1497
  function useLoginForm() {
272
1498
  const { auth } = (0, import_sdk5.useHook)();
273
- const [email, setEmail] = (0, import_react6.useState)("");
274
- const [password, setPassword] = (0, import_react6.useState)("");
275
- const [submitting, setSubmitting] = (0, import_react6.useState)(false);
276
- const [error, setError] = (0, import_react6.useState)(null);
277
- const emailError = (0, import_react6.useMemo)(() => {
1499
+ const [email, setEmail] = (0, import_react10.useState)("");
1500
+ const [password, setPassword] = (0, import_react10.useState)("");
1501
+ const [submitting, setSubmitting] = (0, import_react10.useState)(false);
1502
+ const [error, setError] = (0, import_react10.useState)(null);
1503
+ const emailError = (0, import_react10.useMemo)(() => {
278
1504
  if (email.length === 0) return null;
279
1505
  if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
280
1506
  return null;
281
1507
  }, [email]);
282
- const passwordError = (0, import_react6.useMemo)(() => {
1508
+ const passwordError = (0, import_react10.useMemo)(() => {
283
1509
  if (password.length === 0) return null;
284
1510
  if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
285
1511
  return null;
286
1512
  }, [password]);
287
1513
  const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && emailError === null && passwordError === null && !submitting;
288
- const submit = (0, import_react6.useCallback)(async () => {
1514
+ const submit = (0, import_react10.useCallback)(async () => {
289
1515
  if (!canSubmit) return false;
290
1516
  setSubmitting(true);
291
1517
  setError(null);
@@ -315,13 +1541,13 @@ function useLoginForm() {
315
1541
  }
316
1542
 
317
1543
  // src/internal/GoogleSignInButton.tsx
318
- var import_jsx_runtime8 = require("react/jsx-runtime");
1544
+ var import_jsx_runtime17 = require("react/jsx-runtime");
319
1545
  function GoogleSignInButton({
320
1546
  onClick,
321
1547
  testId = "oauth-google",
322
1548
  label = "Continuar com Google"
323
1549
  }) {
324
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1550
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
325
1551
  "button",
326
1552
  {
327
1553
  "data-testid": testId,
@@ -344,36 +1570,36 @@ function GoogleSignInButton({
344
1570
  fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
345
1571
  },
346
1572
  children: [
347
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(GoogleGlyph, {}),
1573
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GoogleGlyph, {}),
348
1574
  label
349
1575
  ]
350
1576
  }
351
1577
  );
352
1578
  }
353
1579
  function GoogleGlyph() {
354
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
355
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1580
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
1581
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
356
1582
  "path",
357
1583
  {
358
1584
  d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.874 2.684-6.615z",
359
1585
  fill: "#4285F4"
360
1586
  }
361
1587
  ),
362
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1588
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
363
1589
  "path",
364
1590
  {
365
1591
  d: "M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z",
366
1592
  fill: "#34A853"
367
1593
  }
368
1594
  ),
369
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1595
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
370
1596
  "path",
371
1597
  {
372
1598
  d: "M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z",
373
1599
  fill: "#FBBC05"
374
1600
  }
375
1601
  ),
376
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1602
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
377
1603
  "path",
378
1604
  {
379
1605
  d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z",
@@ -384,8 +1610,8 @@ function GoogleGlyph() {
384
1610
  }
385
1611
 
386
1612
  // src/internal/OAuthErrorBanner.tsx
387
- var import_react7 = require("react");
388
- var import_jsx_runtime9 = require("react/jsx-runtime");
1613
+ var import_react11 = require("react");
1614
+ var import_jsx_runtime18 = require("react/jsx-runtime");
389
1615
  var ERROR_MESSAGES = {
390
1616
  invalid_state: "Sess\xE3o expirou, tente de novo.",
391
1617
  access_denied: "Voc\xEA cancelou o login com Google.",
@@ -405,13 +1631,13 @@ function stripErrorFromUrl() {
405
1631
  window.history.replaceState({}, "", url.toString());
406
1632
  }
407
1633
  function OAuthErrorBanner() {
408
- const [code, setCode] = (0, import_react7.useState)(() => readErrorCode());
409
- (0, import_react7.useEffect)(() => {
1634
+ const [code, setCode] = (0, import_react11.useState)(() => readErrorCode());
1635
+ (0, import_react11.useEffect)(() => {
410
1636
  if (code !== null) stripErrorFromUrl();
411
1637
  }, [code]);
412
1638
  if (!code) return null;
413
1639
  const message = ERROR_MESSAGES[code] ?? "N\xE3o conseguimos conectar ao Google. Tente de novo.";
414
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1640
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
415
1641
  "div",
416
1642
  {
417
1643
  role: "alert",
@@ -426,7 +1652,7 @@ function OAuthErrorBanner() {
426
1652
  },
427
1653
  children: [
428
1654
  message,
429
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1655
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
430
1656
  "button",
431
1657
  {
432
1658
  type: "button",
@@ -451,16 +1677,16 @@ function OAuthErrorBanner() {
451
1677
  }
452
1678
 
453
1679
  // src/defaults/DefaultLoginScreen.tsx
454
- var import_jsx_runtime10 = require("react/jsx-runtime");
1680
+ var import_jsx_runtime19 = require("react/jsx-runtime");
455
1681
  function DefaultLoginScreen({ onNavigate }) {
456
1682
  const { name } = useTemplateConfig();
457
1683
  const f = useLoginForm();
458
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
459
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
460
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Entre na sua conta" }),
461
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(OAuthErrorBanner, {}),
462
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "login-oauth-google" }),
463
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1684
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
1685
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
1686
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Entre na sua conta" }),
1687
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(OAuthErrorBanner, {}),
1688
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "login-oauth-google" }),
1689
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
464
1690
  "div",
465
1691
  {
466
1692
  "aria-hidden": "true",
@@ -473,19 +1699,19 @@ function DefaultLoginScreen({ onNavigate }) {
473
1699
  fontSize: 12
474
1700
  },
475
1701
  children: [
476
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
1702
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
477
1703
  "ou",
478
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
1704
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
479
1705
  ]
480
1706
  }
481
1707
  ),
482
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("form", { onSubmit: (e) => {
1708
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("form", { onSubmit: (e) => {
483
1709
  e.preventDefault();
484
1710
  void f.submit();
485
1711
  }, children: [
486
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1712
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
487
1713
  "E-mail",
488
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1714
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
489
1715
  "input",
490
1716
  {
491
1717
  "data-testid": "login-email",
@@ -495,11 +1721,11 @@ function DefaultLoginScreen({ onNavigate }) {
495
1721
  style: { display: "block", width: "100%" }
496
1722
  }
497
1723
  ),
498
- f.emailError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
1724
+ f.emailError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
499
1725
  ] }),
500
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1726
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
501
1727
  "Senha",
502
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1728
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
503
1729
  "input",
504
1730
  {
505
1731
  "data-testid": "login-password",
@@ -509,10 +1735,10 @@ function DefaultLoginScreen({ onNavigate }) {
509
1735
  style: { display: "block", width: "100%" }
510
1736
  }
511
1737
  ),
512
- f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
1738
+ f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
513
1739
  ] }),
514
- f.error && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
515
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1740
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
1741
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
516
1742
  "button",
517
1743
  {
518
1744
  "data-testid": "login-submit",
@@ -531,42 +1757,42 @@ function DefaultLoginScreen({ onNavigate }) {
531
1757
  }
532
1758
  )
533
1759
  ] }),
534
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { marginTop: 16, display: "flex", justifyContent: "space-between" }, children: [
535
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-testid": "login-goto-signup", type: "button", onClick: () => onNavigate("signup"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Criar conta" }),
536
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { "data-testid": "login-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Esqueci senha" })
1760
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginTop: 16, display: "flex", justifyContent: "space-between" }, children: [
1761
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { "data-testid": "login-goto-signup", type: "button", onClick: () => onNavigate("signup"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Criar conta" }),
1762
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { "data-testid": "login-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Esqueci senha" })
537
1763
  ] })
538
1764
  ] });
539
1765
  }
540
1766
 
541
1767
  // src/hooks/useSignupForm.ts
542
- var import_react8 = require("react");
1768
+ var import_react12 = require("react");
543
1769
  var import_sdk6 = require("@hook-sdk/sdk");
544
1770
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
545
1771
  var MIN_PASSWORD2 = 8;
546
1772
  function useSignupForm() {
547
1773
  const { auth } = (0, import_sdk6.useHook)();
548
- const [name, setName] = (0, import_react8.useState)("");
549
- const [email, setEmail] = (0, import_react8.useState)("");
550
- const [password, setPassword] = (0, import_react8.useState)("");
551
- const [submitting, setSubmitting] = (0, import_react8.useState)(false);
552
- const [error, setError] = (0, import_react8.useState)(null);
553
- const nameError = (0, import_react8.useMemo)(() => {
1774
+ const [name, setName] = (0, import_react12.useState)("");
1775
+ const [email, setEmail] = (0, import_react12.useState)("");
1776
+ const [password, setPassword] = (0, import_react12.useState)("");
1777
+ const [submitting, setSubmitting] = (0, import_react12.useState)(false);
1778
+ const [error, setError] = (0, import_react12.useState)(null);
1779
+ const nameError = (0, import_react12.useMemo)(() => {
554
1780
  if (name.length === 0) return null;
555
1781
  if (name.trim().length < 2) return "Nome muito curto.";
556
1782
  return null;
557
1783
  }, [name]);
558
- const emailError = (0, import_react8.useMemo)(() => {
1784
+ const emailError = (0, import_react12.useMemo)(() => {
559
1785
  if (email.length === 0) return null;
560
1786
  if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
561
1787
  return null;
562
1788
  }, [email]);
563
- const passwordError = (0, import_react8.useMemo)(() => {
1789
+ const passwordError = (0, import_react12.useMemo)(() => {
564
1790
  if (password.length === 0) return null;
565
1791
  if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
566
1792
  return null;
567
1793
  }, [password]);
568
1794
  const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && nameError === null && emailError === null && passwordError === null && !submitting;
569
- const submit = (0, import_react8.useCallback)(async () => {
1795
+ const submit = (0, import_react12.useCallback)(async () => {
570
1796
  if (!canSubmit) return false;
571
1797
  setSubmitting(true);
572
1798
  setError(null);
@@ -599,16 +1825,16 @@ function useSignupForm() {
599
1825
  }
600
1826
 
601
1827
  // src/defaults/DefaultSignupScreen.tsx
602
- var import_jsx_runtime11 = require("react/jsx-runtime");
1828
+ var import_jsx_runtime20 = require("react/jsx-runtime");
603
1829
  function DefaultSignupScreen({ onNavigate }) {
604
1830
  const { name } = useTemplateConfig();
605
1831
  const f = useSignupForm();
606
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
607
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
608
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Criar sua conta" }),
609
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OAuthErrorBanner, {}),
610
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "signup-oauth-google" }),
611
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1832
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
1833
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
1834
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Criar sua conta" }),
1835
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(OAuthErrorBanner, {}),
1836
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "signup-oauth-google" }),
1837
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
612
1838
  "div",
613
1839
  {
614
1840
  "aria-hidden": "true",
@@ -621,55 +1847,55 @@ function DefaultSignupScreen({ onNavigate }) {
621
1847
  fontSize: 12
622
1848
  },
623
1849
  children: [
624
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
1850
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
625
1851
  "ou",
626
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
1852
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
627
1853
  ]
628
1854
  }
629
1855
  ),
630
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("form", { onSubmit: (e) => {
1856
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("form", { onSubmit: (e) => {
631
1857
  e.preventDefault();
632
1858
  void f.submit();
633
1859
  }, children: [
634
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1860
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
635
1861
  "Nome",
636
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { "data-testid": "signup-name", value: f.name, onChange: (e) => f.setName(e.target.value), style: { display: "block", width: "100%" } }),
637
- f.nameError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { style: { color: "#c00" }, children: f.nameError })
1862
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { "data-testid": "signup-name", value: f.name, onChange: (e) => f.setName(e.target.value), style: { display: "block", width: "100%" } }),
1863
+ f.nameError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.nameError })
638
1864
  ] }),
639
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1865
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
640
1866
  "E-mail",
641
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { "data-testid": "signup-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
642
- f.emailError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
1867
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { "data-testid": "signup-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
1868
+ f.emailError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
643
1869
  ] }),
644
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1870
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
645
1871
  "Senha",
646
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("input", { "data-testid": "signup-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" } }),
647
- f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
1872
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { "data-testid": "signup-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" } }),
1873
+ f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
648
1874
  ] }),
649
- f.error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
650
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { "data-testid": "signup-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Criando..." : "Criar conta" })
1875
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
1876
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { "data-testid": "signup-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Criando..." : "Criar conta" })
651
1877
  ] }),
652
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { "data-testid": "signup-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "J\xE1 tem conta? Entre" }) })
1878
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { "data-testid": "signup-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "J\xE1 tem conta? Entre" }) })
653
1879
  ] });
654
1880
  }
655
1881
 
656
1882
  // src/hooks/useForgotForm.ts
657
- var import_react9 = require("react");
1883
+ var import_react13 = require("react");
658
1884
  var import_sdk7 = require("@hook-sdk/sdk");
659
1885
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
660
1886
  function useForgotForm() {
661
1887
  const { auth } = (0, import_sdk7.useHook)();
662
- const [email, setEmail] = (0, import_react9.useState)("");
663
- const [submitting, setSubmitting] = (0, import_react9.useState)(false);
664
- const [sent, setSent] = (0, import_react9.useState)(false);
665
- const [error, setError] = (0, import_react9.useState)(null);
666
- const emailError = (0, import_react9.useMemo)(() => {
1888
+ const [email, setEmail] = (0, import_react13.useState)("");
1889
+ const [submitting, setSubmitting] = (0, import_react13.useState)(false);
1890
+ const [sent, setSent] = (0, import_react13.useState)(false);
1891
+ const [error, setError] = (0, import_react13.useState)(null);
1892
+ const emailError = (0, import_react13.useMemo)(() => {
667
1893
  if (email.length === 0) return null;
668
1894
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
669
1895
  return null;
670
1896
  }, [email]);
671
1897
  const canSubmit = email.length > 0 && emailError === null && !submitting;
672
- const submit = (0, import_react9.useCallback)(async () => {
1898
+ const submit = (0, import_react13.useCallback)(async () => {
673
1899
  if (!canSubmit) return false;
674
1900
  setSubmitting(true);
675
1901
  setError(null);
@@ -697,66 +1923,66 @@ function useForgotForm() {
697
1923
  }
698
1924
 
699
1925
  // src/defaults/DefaultForgotScreen.tsx
700
- var import_jsx_runtime12 = require("react/jsx-runtime");
1926
+ var import_jsx_runtime21 = require("react/jsx-runtime");
701
1927
  function DefaultForgotScreen({ onNavigate }) {
702
1928
  const { name } = useTemplateConfig();
703
1929
  const f = useForgotForm();
704
1930
  if (f.sent) {
705
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
706
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { children: "Verifique seu e-mail" }),
707
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { opacity: 0.7 }, children: "Enviamos um link pra redefinir sua senha." }),
708
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { "data-testid": "forgot-back-login", type: "button", onClick: () => onNavigate("login"), children: "Voltar pro login" })
1931
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
1932
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h1", { children: "Verifique seu e-mail" }),
1933
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { opacity: 0.7 }, children: "Enviamos um link pra redefinir sua senha." }),
1934
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { "data-testid": "forgot-back-login", type: "button", onClick: () => onNavigate("login"), children: "Voltar pro login" })
709
1935
  ] });
710
1936
  }
711
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
712
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
713
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Redefinir senha" }),
714
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("form", { onSubmit: (e) => {
1937
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
1938
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
1939
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Redefinir senha" }),
1940
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("form", { onSubmit: (e) => {
715
1941
  e.preventDefault();
716
1942
  void f.submit();
717
1943
  }, children: [
718
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1944
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
719
1945
  "E-mail",
720
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { "data-testid": "forgot-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
721
- f.emailError && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
1946
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { "data-testid": "forgot-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
1947
+ f.emailError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
722
1948
  ] }),
723
- f.error && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
724
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { "data-testid": "forgot-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Enviando..." : "Enviar link" })
1949
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
1950
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { "data-testid": "forgot-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Enviando..." : "Enviar link" })
725
1951
  ] }),
726
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { "data-testid": "forgot-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Voltar pro login" }) })
1952
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { "data-testid": "forgot-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Voltar pro login" }) })
727
1953
  ] });
728
1954
  }
729
1955
 
730
1956
  // src/hooks/useResetForm.ts
731
- var import_react10 = require("react");
1957
+ var import_react14 = require("react");
732
1958
  var import_sdk8 = require("@hook-sdk/sdk");
733
1959
  var MIN_PASSWORD3 = 12;
734
1960
  function useResetForm() {
735
1961
  const { auth } = (0, import_sdk8.useHook)();
736
- const [token, setToken] = (0, import_react10.useState)(null);
737
- const [password, setPassword] = (0, import_react10.useState)("");
738
- const [confirm, setConfirm] = (0, import_react10.useState)("");
739
- const [submitting, setSubmitting] = (0, import_react10.useState)(false);
740
- const [done, setDone] = (0, import_react10.useState)(false);
741
- const [error, setError] = (0, import_react10.useState)(null);
742
- (0, import_react10.useEffect)(() => {
1962
+ const [token, setToken] = (0, import_react14.useState)(null);
1963
+ const [password, setPassword] = (0, import_react14.useState)("");
1964
+ const [confirm, setConfirm] = (0, import_react14.useState)("");
1965
+ const [submitting, setSubmitting] = (0, import_react14.useState)(false);
1966
+ const [done, setDone] = (0, import_react14.useState)(false);
1967
+ const [error, setError] = (0, import_react14.useState)(null);
1968
+ (0, import_react14.useEffect)(() => {
743
1969
  if (typeof window === "undefined") return;
744
1970
  const params = new URLSearchParams(window.location.search);
745
1971
  const t = params.get("token");
746
1972
  setToken(t && t.length > 0 ? t : null);
747
1973
  }, []);
748
- const passwordError = (0, import_react10.useMemo)(() => {
1974
+ const passwordError = (0, import_react14.useMemo)(() => {
749
1975
  if (password.length === 0) return null;
750
1976
  if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
751
1977
  return null;
752
1978
  }, [password]);
753
- const confirmError = (0, import_react10.useMemo)(() => {
1979
+ const confirmError = (0, import_react14.useMemo)(() => {
754
1980
  if (confirm.length === 0) return null;
755
1981
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
756
1982
  return null;
757
1983
  }, [confirm, password]);
758
1984
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && passwordError === null && confirmError === null && !submitting && !done;
759
- const submit = (0, import_react10.useCallback)(async () => {
1985
+ const submit = (0, import_react14.useCallback)(async () => {
760
1986
  if (!canSubmit || token === null) return;
761
1987
  setSubmitting(true);
762
1988
  setError(null);
@@ -792,67 +2018,67 @@ function useResetForm() {
792
2018
  }
793
2019
 
794
2020
  // src/defaults/DefaultResetScreen.tsx
795
- var import_jsx_runtime13 = require("react/jsx-runtime");
2021
+ var import_jsx_runtime22 = require("react/jsx-runtime");
796
2022
  function DefaultResetScreen({ onNavigate }) {
797
2023
  const { name } = useTemplateConfig();
798
2024
  const f = useResetForm();
799
2025
  if (f.done) {
800
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
801
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h1", { children: "Senha alterada" }),
802
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: { opacity: 0.7 }, children: "Agora \xE9 s\xF3 fazer login com a nova senha." }),
803
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { "data-testid": "reset-back-login", type: "button", onClick: () => onNavigate("login"), children: "Ir pro login" })
2026
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
2027
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { children: "Senha alterada" }),
2028
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7 }, children: "Agora \xE9 s\xF3 fazer login com a nova senha." }),
2029
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "reset-back-login", type: "button", onClick: () => onNavigate("login"), children: "Ir pro login" })
804
2030
  ] });
805
2031
  }
806
2032
  if (f.token === null) {
807
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
808
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h1", { children: "Link inv\xE1lido" }),
809
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: { opacity: 0.7 }, children: "Pe\xE7a um novo link de reset." }),
810
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { "data-testid": "reset-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), children: "Pedir novo link" })
2033
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
2034
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { children: "Link inv\xE1lido" }),
2035
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7 }, children: "Pe\xE7a um novo link de reset." }),
2036
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "reset-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), children: "Pedir novo link" })
811
2037
  ] });
812
2038
  }
813
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
814
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
815
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Escolha uma nova senha" }),
816
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("form", { onSubmit: (e) => {
2039
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
2040
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
2041
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Escolha uma nova senha" }),
2042
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("form", { onSubmit: (e) => {
817
2043
  e.preventDefault();
818
2044
  void f.submit();
819
2045
  }, children: [
820
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
2046
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
821
2047
  "Nova senha",
822
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { "data-testid": "reset-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
823
- f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
2048
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("input", { "data-testid": "reset-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
2049
+ f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
824
2050
  ] }),
825
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
2051
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
826
2052
  "Confirmar senha",
827
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { "data-testid": "reset-confirm", type: "password", value: f.confirm, onChange: (e) => f.setConfirm(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
828
- f.confirmError && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("small", { style: { color: "#c00" }, children: f.confirmError })
2053
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("input", { "data-testid": "reset-confirm", type: "password", value: f.confirm, onChange: (e) => f.setConfirm(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
2054
+ f.confirmError && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { style: { color: "#c00" }, children: f.confirmError })
829
2055
  ] }),
830
- f.error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
831
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { "data-testid": "reset-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Alterando..." : "Alterar senha" })
2056
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
2057
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "reset-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Alterando..." : "Alterar senha" })
832
2058
  ] })
833
2059
  ] });
834
2060
  }
835
2061
 
836
2062
  // src/defaults/DefaultPaywall.tsx
837
- var import_react11 = require("react");
838
- var import_jsx_runtime14 = require("react/jsx-runtime");
2063
+ var import_react15 = require("react");
2064
+ var import_jsx_runtime23 = require("react/jsx-runtime");
839
2065
  function DefaultPaywall() {
840
2066
  const config = useTemplateConfig();
841
2067
  const { checkout, opening, error } = usePaywallState();
842
2068
  const p = config.subscription.paywall_config;
843
- const [cpf, setCpf] = (0, import_react11.useState)("");
2069
+ const [cpf, setCpf] = (0, import_react15.useState)("");
844
2070
  const cpfDigits = cpf.replace(/\D/g, "");
845
2071
  const canCheckout = cpfDigits.length === 11 && !opening;
846
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("main", { style: { padding: 24, maxWidth: 440, margin: "0 auto", textAlign: "center" }, children: [
847
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h1", { style: { marginBottom: 8 }, children: p.title }),
848
- p.subtitle && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: p.subtitle }),
849
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { style: { listStyle: "none", padding: 0, textAlign: "left", marginBottom: 24 }, children: p.benefits.map((b) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("li", { style: { padding: "8px 0", display: "flex", alignItems: "center" }, children: [
850
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { "aria-hidden": true, style: { marginRight: 8 }, children: "\u2713" }),
851
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: b })
2072
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("main", { style: { padding: 24, maxWidth: 440, margin: "0 auto", textAlign: "center" }, children: [
2073
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { style: { marginBottom: 8 }, children: p.title }),
2074
+ p.subtitle && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: p.subtitle }),
2075
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { style: { listStyle: "none", padding: 0, textAlign: "left", marginBottom: 24 }, children: p.benefits.map((b) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("li", { style: { padding: "8px 0", display: "flex", alignItems: "center" }, children: [
2076
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, style: { marginRight: 8 }, children: "\u2713" }),
2077
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: b })
852
2078
  ] }, b)) }),
853
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { textAlign: "left", marginBottom: 16 }, children: [
854
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { style: { display: "block", fontSize: 14, opacity: 0.7, marginBottom: 4 }, children: "Seu CPF (pra emiss\xE3o de recibo)" }),
855
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2079
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { textAlign: "left", marginBottom: 16 }, children: [
2080
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { display: "block", fontSize: 14, opacity: 0.7, marginBottom: 4 }, children: "Seu CPF (pra emiss\xE3o de recibo)" }),
2081
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
856
2082
  "input",
857
2083
  {
858
2084
  "data-testid": "paywall-cpf",
@@ -865,8 +2091,8 @@ function DefaultPaywall() {
865
2091
  }
866
2092
  )
867
2093
  ] }),
868
- error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: error.message }),
869
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2094
+ error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: error.message }),
2095
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
870
2096
  "button",
871
2097
  {
872
2098
  "data-testid": "paywall-cta",
@@ -887,21 +2113,21 @@ function DefaultPaywall() {
887
2113
  children: opening ? "Abrindo..." : p.cta
888
2114
  }
889
2115
  ),
890
- p.priceHint && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { opacity: 0.6, marginTop: 12 }, children: p.priceHint }),
891
- p.footerNote && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { opacity: 0.5, marginTop: 16, fontSize: 12 }, children: p.footerNote })
2116
+ p.priceHint && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.6, marginTop: 12 }, children: p.priceHint }),
2117
+ p.footerNote && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.5, marginTop: 16, fontSize: 12 }, children: p.footerNote })
892
2118
  ] });
893
2119
  }
894
2120
 
895
2121
  // src/AppRoot.tsx
896
- var import_jsx_runtime15 = require("react/jsx-runtime");
2122
+ var import_jsx_runtime24 = require("react/jsx-runtime");
897
2123
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
898
2124
  function PaymentReturnHandler({ children }) {
899
2125
  const { subscription } = (0, import_sdk9.useHook)();
900
- const subRef = (0, import_react12.useRef)(subscription);
2126
+ const subRef = (0, import_react16.useRef)(subscription);
901
2127
  subRef.current = subscription;
902
- const runIdRef = (0, import_react12.useRef)(0);
903
- const [state, setState] = (0, import_react12.useState)("idle");
904
- const runPoll = (0, import_react12.useCallback)(() => {
2128
+ const runIdRef = (0, import_react16.useRef)(0);
2129
+ const [state, setState] = (0, import_react16.useState)("idle");
2130
+ const runPoll = (0, import_react16.useCallback)(() => {
905
2131
  const runId = ++runIdRef.current;
906
2132
  setState("confirming");
907
2133
  let attempts = 0;
@@ -930,7 +2156,7 @@ function PaymentReturnHandler({ children }) {
930
2156
  };
931
2157
  void tick();
932
2158
  }, []);
933
- (0, import_react12.useEffect)(() => {
2159
+ (0, import_react16.useEffect)(() => {
934
2160
  if (typeof window === "undefined") return;
935
2161
  const url = new URL(window.location.href);
936
2162
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -940,20 +2166,20 @@ function PaymentReturnHandler({ children }) {
940
2166
  };
941
2167
  }, [runPoll]);
942
2168
  if (state === "confirming") {
943
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2169
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
944
2170
  "div",
945
2171
  {
946
2172
  role: "status",
947
2173
  "aria-live": "polite",
948
- style: overlayStyle,
2174
+ style: overlayStyle2,
949
2175
  children: "Confirmando pagamento\u2026"
950
2176
  }
951
2177
  );
952
2178
  }
953
2179
  if (state === "waiting") {
954
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
955
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
956
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2180
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2181
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2182
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
957
2183
  "button",
958
2184
  {
959
2185
  type: "button",
@@ -964,9 +2190,9 @@ function PaymentReturnHandler({ children }) {
964
2190
  )
965
2191
  ] }) });
966
2192
  }
967
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
2193
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children });
968
2194
  }
969
- var overlayStyle = {
2195
+ var overlayStyle2 = {
970
2196
  position: "fixed",
971
2197
  inset: 0,
972
2198
  display: "flex",
@@ -997,14 +2223,14 @@ function AppRoot({
997
2223
  Reset = DefaultResetScreen,
998
2224
  Paywall = DefaultPaywall
999
2225
  }) {
1000
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PaymentReturnHandler, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TemplateConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AuthGate, { Login, Signup, Forgot, Reset, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PersistedKeysPrefetch, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(SubscriptionGate, { Paywall, children: [
2226
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PaymentReturnHandler, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TemplateConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AuthGate, { Login, Signup, Forgot, Reset, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PersistedKeysPrefetch, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(SubscriptionGate, { Paywall, children: [
1001
2227
  children,
1002
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PushPrompt, {})
1003
- ] }) }) }) }) }) }) });
2228
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PushPrompt, {})
2229
+ ] }) }) }) }) }) }) }) });
1004
2230
  }
1005
2231
 
1006
2232
  // src/hooks/usePush.ts
1007
- var import_react13 = require("react");
2233
+ var import_react17 = require("react");
1008
2234
  var import_sdk10 = require("@hook-sdk/sdk");
1009
2235
  function detectIosNeedsInstall() {
1010
2236
  if (typeof navigator === "undefined" || typeof window === "undefined") return false;
@@ -1032,11 +2258,11 @@ function deriveState(push) {
1032
2258
  }
1033
2259
  function usePush() {
1034
2260
  const { push } = (0, import_sdk10.useHook)();
1035
- const [state, setState] = (0, import_react13.useState)(() => deriveState(push));
1036
- (0, import_react13.useEffect)(() => {
2261
+ const [state, setState] = (0, import_react17.useState)(() => deriveState(push));
2262
+ (0, import_react17.useEffect)(() => {
1037
2263
  setState(deriveState(push));
1038
2264
  }, [push]);
1039
- const subscribe = (0, import_react13.useCallback)(async () => {
2265
+ const subscribe = (0, import_react17.useCallback)(async () => {
1040
2266
  try {
1041
2267
  await push.subscribe();
1042
2268
  setState({ kind: "subscribed" });
@@ -1048,7 +2274,7 @@ function usePush() {
1048
2274
  throw e;
1049
2275
  }
1050
2276
  }, [push]);
1051
- const unsubscribe = (0, import_react13.useCallback)(async () => {
2277
+ const unsubscribe = (0, import_react17.useCallback)(async () => {
1052
2278
  try {
1053
2279
  await push.unsubscribe();
1054
2280
  setState({ kind: "prompt" });
@@ -1061,31 +2287,31 @@ function usePush() {
1061
2287
  }
1062
2288
 
1063
2289
  // src/components/PushPrompt.tsx
1064
- var import_jsx_runtime16 = require("react/jsx-runtime");
2290
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1065
2291
  function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
1066
2292
  const { state, subscribe } = usePush();
1067
2293
  if (state.kind === "subscribed") return null;
1068
2294
  if (state.kind === "ios_needs_install") {
1069
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
1070
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { children: texts.iosInstallTitle }),
1071
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: texts.iosInstallBody }),
1072
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2295
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2296
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { children: texts.iosInstallTitle }),
2297
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { children: texts.iosInstallBody }),
2298
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
1073
2299
  ] });
1074
2300
  }
1075
2301
  if (state.kind === "denied") {
1076
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
1077
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { children: texts.deniedTitle }),
1078
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: texts.deniedBody })
2302
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2303
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { children: texts.deniedTitle }),
2304
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { children: texts.deniedBody })
1079
2305
  ] });
1080
2306
  }
1081
2307
  if (state.kind === "unsupported") {
1082
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: texts.unsupportedBody }) });
2308
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { children: texts.unsupportedBody }) });
1083
2309
  }
1084
2310
  if (state.kind === "error") {
1085
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: state.message }) });
2311
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { children: state.message }) });
1086
2312
  }
1087
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, role: "region", children: [
1088
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2313
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className, role: "region", children: [
2314
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1089
2315
  "button",
1090
2316
  {
1091
2317
  type: "button",
@@ -1099,27 +2325,27 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
1099
2325
  children: texts.cta
1100
2326
  }
1101
2327
  ),
1102
- onDeclined && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2328
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
1103
2329
  ] });
1104
2330
  }
1105
2331
 
1106
2332
  // src/defaults/EmptyState.tsx
1107
- var import_jsx_runtime17 = require("react/jsx-runtime");
2333
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1108
2334
  function EmptyState({ title, description, action }) {
1109
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
1110
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
1111
- description && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: { opacity: 0.7 }, children: description }),
1112
- action && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { marginTop: 16 }, children: action })
2335
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2336
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2337
+ description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2338
+ action && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { marginTop: 16 }, children: action })
1113
2339
  ] });
1114
2340
  }
1115
2341
 
1116
2342
  // src/hooks/useAuthPrimitives.ts
1117
- var import_react14 = require("react");
2343
+ var import_react18 = require("react");
1118
2344
  var import_sdk11 = require("@hook-sdk/sdk");
1119
2345
  var warned = false;
1120
2346
  function useAuthPrimitives() {
1121
2347
  const { auth } = (0, import_sdk11.useHook)();
1122
- (0, import_react14.useEffect)(() => {
2348
+ (0, import_react18.useEffect)(() => {
1123
2349
  if (!warned && process.env.NODE_ENV !== "production") {
1124
2350
  warned = true;
1125
2351
  console.warn(
@@ -1150,14 +2376,14 @@ function useSubscription() {
1150
2376
  }
1151
2377
 
1152
2378
  // src/hooks/useReminders.ts
1153
- var import_react15 = require("react");
2379
+ var import_react19 = require("react");
1154
2380
  var import_sdk13 = require("@hook-sdk/sdk");
1155
2381
  function useReminders() {
1156
2382
  const { push } = (0, import_sdk13.useHook)();
1157
2383
  const r = push.reminders;
1158
- const [reminders, setReminders] = (0, import_react15.useState)([]);
1159
- const [loading, setLoading] = (0, import_react15.useState)(true);
1160
- const reload = (0, import_react15.useCallback)(async () => {
2384
+ const [reminders, setReminders] = (0, import_react19.useState)([]);
2385
+ const [loading, setLoading] = (0, import_react19.useState)(true);
2386
+ const reload = (0, import_react19.useCallback)(async () => {
1161
2387
  setLoading(true);
1162
2388
  try {
1163
2389
  const next = await r.list();
@@ -1166,38 +2392,38 @@ function useReminders() {
1166
2392
  setLoading(false);
1167
2393
  }
1168
2394
  }, [r]);
1169
- (0, import_react15.useEffect)(() => {
2395
+ (0, import_react19.useEffect)(() => {
1170
2396
  void reload();
1171
2397
  }, [reload]);
1172
- const setReminder = (0, import_react15.useCallback)(async (input) => {
2398
+ const setReminder = (0, import_react19.useCallback)(async (input) => {
1173
2399
  await r.set(input);
1174
2400
  await reload();
1175
2401
  }, [r, reload]);
1176
- const deleteReminder = (0, import_react15.useCallback)(async (slot) => {
2402
+ const deleteReminder = (0, import_react19.useCallback)(async (slot) => {
1177
2403
  await r.delete(slot);
1178
2404
  await reload();
1179
2405
  }, [r, reload]);
1180
- const schedule = (0, import_react15.useCallback)(async (items) => {
2406
+ const schedule = (0, import_react19.useCallback)(async (items) => {
1181
2407
  return r.schedule(items);
1182
2408
  }, [r]);
1183
- const setFallbacks = (0, import_react15.useCallback)(async (items) => {
2409
+ const setFallbacks = (0, import_react19.useCallback)(async (items) => {
1184
2410
  return r.setFallbacks(items);
1185
2411
  }, [r]);
1186
2412
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
1187
2413
  }
1188
2414
 
1189
2415
  // src/hooks/useToast.ts
1190
- var import_react16 = require("react");
2416
+ var import_react20 = require("react");
1191
2417
  function useToast() {
1192
- const [items, setItems] = (0, import_react16.useState)([]);
1193
- const show = (0, import_react16.useCallback)((message, kind = "info") => {
2418
+ const [items, setItems] = (0, import_react20.useState)([]);
2419
+ const show = (0, import_react20.useCallback)((message, kind = "info") => {
1194
2420
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1195
2421
  setItems((prev) => [...prev, { id, message, kind }]);
1196
2422
  setTimeout(() => {
1197
2423
  setItems((prev) => prev.filter((t) => t.id !== id));
1198
2424
  }, 4e3);
1199
2425
  }, []);
1200
- const dismiss = (0, import_react16.useCallback)((id) => {
2426
+ const dismiss = (0, import_react20.useCallback)((id) => {
1201
2427
  setItems((prev) => prev.filter((t) => t.id !== id));
1202
2428
  }, []);
1203
2429
  return { items, show, dismiss };
@@ -1212,11 +2438,21 @@ function useToast() {
1212
2438
  DefaultSignupScreen,
1213
2439
  EmptyState,
1214
2440
  ErrorBoundary,
2441
+ InstallGate,
2442
+ InstallSplash,
1215
2443
  LoadingState,
1216
2444
  PushPrompt,
2445
+ detectAndroidBrowser,
2446
+ detectIOSBrowser,
2447
+ detectInAppApp,
2448
+ detectPlatform,
2449
+ detectStandalone,
2450
+ shouldBlockInstall,
2451
+ shouldShowPermanentOption,
1217
2452
  useAuth,
1218
2453
  useAuthPrimitives,
1219
2454
  useForgotForm,
2455
+ useInstallPrompt,
1220
2456
  useLoginForm,
1221
2457
  usePaywallState,
1222
2458
  usePush,