@hook-sdk/template 0.3.0 → 0.4.1

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,1303 @@ 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 showIOSOtherHelp = (0, import_react5.useCallback)(() => {
462
+ track("pwa_install_ios_other_help_shown", { slug });
463
+ }, [slug]);
464
+ const copyLink = (0, import_react5.useCallback)(async () => {
465
+ if (typeof navigator === "undefined" || typeof location === "undefined") return;
466
+ try {
467
+ await navigator.clipboard?.writeText?.(location.href);
468
+ } catch {
469
+ }
470
+ }, []);
471
+ const reset = (0, import_react5.useCallback)(() => {
472
+ const storage = safeStorage();
473
+ if (storage) {
474
+ storage.removeItem(storageKey.dismissedAt(slug));
475
+ storage.removeItem(storageKey.installedAt(slug));
476
+ storage.removeItem(storageKey.skipCount(slug));
477
+ }
478
+ if (typeof sessionStorage !== "undefined") {
479
+ try {
480
+ sessionStorage.removeItem(storageKey.sessionSkip(slug));
481
+ } catch {
482
+ }
483
+ }
484
+ setIsDismissedSession(false);
485
+ setIsDismissedPermanent(false);
486
+ setSkipCount(0);
487
+ }, [slug]);
488
+ return {
489
+ platform,
490
+ iosBrowser,
491
+ androidBrowser,
492
+ inAppApp,
493
+ isInstallable,
494
+ isInstalled,
495
+ isDismissedSession,
496
+ isDismissedPermanent,
497
+ skipCount,
498
+ variant,
499
+ promptInstall,
500
+ dismissSession,
501
+ dismissPermanent,
502
+ showIOSOtherHelp,
503
+ copyLink,
504
+ reset
505
+ };
506
+ }
507
+ function shouldBlockInstall(state, now = Date.now()) {
508
+ if (state.isInstalled) return false;
509
+ if (state.variant === "none") return false;
510
+ if (state.isDismissedSession) return false;
511
+ if (state.isDismissedPermanent) {
512
+ void now;
513
+ return false;
514
+ }
515
+ if (state.platform === "desktop" && !state.isInstallable) return false;
516
+ if (state.platform === "unknown") return false;
517
+ return true;
518
+ }
519
+ function shouldShowPermanentOption(state) {
520
+ return state.skipCount >= SESSION_SKIPS_BEFORE_PERMANENT_OPTION;
521
+ }
522
+
523
+ // src/components/InstallGate/copy.ts
524
+ var INSTALL_COPY = {
525
+ android: {
526
+ native: {
527
+ title: "Instale no seu celular",
528
+ subtitle: "Acesso r\xE1pido, sem precisar do navegador",
529
+ cta: "Baixar",
530
+ skip: "Continuar no navegador",
531
+ skipPermanent: "N\xE3o me pergunte mais"
532
+ },
533
+ manual: {
534
+ title: "Instale em 2 toques",
535
+ subtitle: 'Toque no menu do navegador e escolha "Instalar aplicativo"',
536
+ step1: "Toque no menu do navegador",
537
+ step2: 'Escolha "Instalar aplicativo"',
538
+ cta: "Entendi",
539
+ skip: "Continuar no navegador",
540
+ skipPermanent: "N\xE3o me pergunte mais"
541
+ }
542
+ },
543
+ iosSafari: {
544
+ title: "Adicione \xE0 sua Tela de In\xEDcio",
545
+ subtitle: "Siga os 3 passos",
546
+ step1: {
547
+ title: "Toque em Compartilhar",
548
+ subtitle: "Na barra inferior do Safari"
549
+ },
550
+ step2: {
551
+ title: 'Role e toque em "Adicionar \xE0 Tela de In\xEDcio"',
552
+ iconLabel: "Adicionar \xE0 Tela de In\xEDcio"
553
+ },
554
+ step3: {
555
+ title: 'Toque em "Adicionar" pra confirmar',
556
+ buttonLabel: "Adicionar"
557
+ },
558
+ skip: "Continuar no Safari",
559
+ skipPermanent: "N\xE3o me pergunte mais"
560
+ },
561
+ iosOther: {
562
+ title: "Abra no Safari pra instalar",
563
+ subtitle: "No Chrome/Firefox/Edge do iPhone n\xE3o d\xE1 pra instalar PWA. Abra o link no Safari.",
564
+ ctaPrimary: "Abrir no Safari",
565
+ ctaSecondary: "Copiar link",
566
+ copiedToast: "Link copiado. Cole no Safari.",
567
+ skip: "Continuar mesmo assim",
568
+ skipPermanent: "N\xE3o me pergunte mais",
569
+ help: {
570
+ step1: {
571
+ title: "Toque em \u22EF ou no bot\xE3o compartilhar",
572
+ subtitle: "Na barra inferior ou superior do navegador"
573
+ },
574
+ step2: {
575
+ title: 'Escolha "Abrir no Safari"',
576
+ subtitle: "O app vai abrir direto no Safari"
577
+ }
578
+ }
579
+ },
580
+ inApp: {
581
+ instagram: {
582
+ title: "Pra instalar, abra fora do Instagram",
583
+ step1: "Toque em \u22EF (canto superior direito)",
584
+ step2: 'Escolha "Abrir no navegador externo"'
585
+ },
586
+ facebook: {
587
+ title: "Pra instalar, abra fora do Facebook",
588
+ step1: "Toque em \u22EE",
589
+ step2: 'Escolha "Abrir no navegador"'
590
+ },
591
+ tiktok: {
592
+ title: "Pra instalar, abra fora do TikTok",
593
+ step1: "Toque em \u22EF",
594
+ step2: 'Escolha "Abrir no Safari" (iOS) ou "Abrir no Chrome" (Android)'
595
+ },
596
+ whatsapp: {
597
+ title: "Pra instalar, abra fora do WhatsApp",
598
+ step1: "Toque longo no link",
599
+ step2: 'Escolha "Abrir no navegador"'
600
+ },
601
+ twitter: {
602
+ title: "Pra instalar, abra fora do Twitter",
603
+ step1: "Toque em \u22EF",
604
+ step2: 'Escolha "Abrir no navegador"'
605
+ },
606
+ linkedin: {
607
+ title: "Pra instalar, abra fora do LinkedIn",
608
+ step1: "Toque em \u22EF",
609
+ step2: 'Escolha "Abrir no navegador"'
610
+ },
611
+ telegram: {
612
+ title: "Pra instalar, abra fora do Telegram",
613
+ step1: "Toque em \u22EE",
614
+ step2: 'Escolha "Abrir no navegador"'
615
+ },
616
+ line: {
617
+ title: "Pra instalar, abra fora do LINE",
618
+ step1: "Toque em \u22EF",
619
+ step2: 'Escolha "Abrir no navegador"'
620
+ },
621
+ snapchat: {
622
+ title: "Pra instalar, abra fora do Snapchat",
623
+ step1: "Mantenha pressionado o link",
624
+ step2: 'Escolha "Abrir no navegador"'
625
+ },
626
+ pinterest: {
627
+ title: "Pra instalar, abra fora do Pinterest",
628
+ step1: "Toque em \u22EF",
629
+ step2: 'Escolha "Abrir no navegador"'
630
+ },
631
+ wechat: {
632
+ title: "Pra instalar, abra fora do WeChat",
633
+ step1: "Toque em \u22EF",
634
+ step2: 'Escolha "Abrir no navegador"'
635
+ },
636
+ other: {
637
+ title: "Abra no navegador do celular",
638
+ step1: "Toque no menu do app atual",
639
+ step2: 'Escolha "Abrir no Chrome" ou "Abrir no Safari"'
640
+ },
641
+ copy: "Copiar link",
642
+ copiedToast: "Link copiado. Cole no Chrome/Safari.",
643
+ skip: "Continuar aqui mesmo",
644
+ skipPermanent: "N\xE3o me pergunte mais"
645
+ },
646
+ desktop: {
647
+ title: "Instale no computador",
648
+ subtitle: "Acesso r\xE1pido",
649
+ cta: "Baixar",
650
+ close: "Fechar"
651
+ }
652
+ };
653
+
654
+ // src/components/InstallGate/InstallSplash.tsx
215
655
  var import_jsx_runtime7 = require("react/jsx-runtime");
216
- var ErrorBoundary = class extends import_react5.Component {
656
+ function InstallSplash({ children, title, subtitle }) {
657
+ const { name, theme } = useTemplateConfig();
658
+ const iconUrl = theme.icon_url || theme.logo_url || null;
659
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
660
+ "div",
661
+ {
662
+ role: "dialog",
663
+ "aria-modal": "true",
664
+ "aria-labelledby": "install-splash-title",
665
+ "aria-describedby": subtitle ? "install-splash-subtitle" : void 0,
666
+ style: overlayStyle,
667
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: cardStyle, children: [
668
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", justifyContent: "center", marginBottom: 16 }, children: iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
669
+ "img",
670
+ {
671
+ src: iconUrl,
672
+ alt: `\xCDcone de ${name}`,
673
+ style: { width: 80, height: 80, borderRadius: 20, objectFit: "cover" }
674
+ }
675
+ ) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
676
+ "div",
677
+ {
678
+ style: {
679
+ width: 80,
680
+ height: 80,
681
+ borderRadius: 20,
682
+ background: "var(--hook-color-primary)",
683
+ color: "#fff",
684
+ display: "flex",
685
+ alignItems: "center",
686
+ justifyContent: "center",
687
+ fontSize: 36,
688
+ fontWeight: 700
689
+ },
690
+ children: name.charAt(0).toUpperCase()
691
+ }
692
+ ) }),
693
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { id: "install-splash-title", style: titleStyle, children: title }),
694
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { id: "install-splash-subtitle", style: subtitleStyle, children: subtitle }),
695
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { marginTop: 24 }, children }),
696
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: footerStyle, children: "por Hook" })
697
+ ] })
698
+ }
699
+ );
700
+ }
701
+ var primaryButtonStyle = {
702
+ width: "100%",
703
+ padding: "14px 20px",
704
+ background: "var(--hook-color-primary)",
705
+ color: "#fff",
706
+ border: "none",
707
+ borderRadius: 999,
708
+ fontSize: 17,
709
+ fontWeight: 600,
710
+ cursor: "pointer",
711
+ marginBottom: 12
712
+ };
713
+ var secondaryButtonStyle = {
714
+ width: "100%",
715
+ padding: "12px 20px",
716
+ background: "transparent",
717
+ color: "var(--hook-color-primary)",
718
+ border: "1px solid var(--hook-color-primary)",
719
+ borderRadius: 999,
720
+ fontSize: 15,
721
+ fontWeight: 500,
722
+ cursor: "pointer",
723
+ marginBottom: 12
724
+ };
725
+ var skipLinkStyle = {
726
+ display: "block",
727
+ width: "100%",
728
+ padding: "10px",
729
+ marginTop: 8,
730
+ background: "transparent",
731
+ color: "#555",
732
+ border: "none",
733
+ fontSize: 14,
734
+ textDecoration: "underline",
735
+ cursor: "pointer",
736
+ textAlign: "center"
737
+ };
738
+ var skipPermanentLinkStyle = {
739
+ ...skipLinkStyle,
740
+ color: "#999",
741
+ fontSize: 13,
742
+ marginTop: 4
743
+ };
744
+ var overlayStyle = {
745
+ position: "fixed",
746
+ inset: 0,
747
+ background: "var(--hook-color-background, #fafafa)",
748
+ zIndex: 1e4,
749
+ display: "flex",
750
+ alignItems: "center",
751
+ justifyContent: "center",
752
+ padding: 20,
753
+ overflow: "auto"
754
+ };
755
+ var cardStyle = {
756
+ width: "100%",
757
+ maxWidth: 420,
758
+ padding: 24,
759
+ textAlign: "center"
760
+ };
761
+ var titleStyle = {
762
+ fontSize: 24,
763
+ fontWeight: 700,
764
+ lineHeight: 1.2,
765
+ margin: "0 0 8px 0",
766
+ color: "#111"
767
+ };
768
+ var subtitleStyle = {
769
+ fontSize: 15,
770
+ lineHeight: 1.4,
771
+ color: "#555",
772
+ margin: 0
773
+ };
774
+ var footerStyle = {
775
+ fontSize: 11,
776
+ color: "#aaa",
777
+ marginTop: 32,
778
+ letterSpacing: 0.5
779
+ };
780
+
781
+ // src/components/InstallGate/icons.tsx
782
+ var import_jsx_runtime8 = require("react/jsx-runtime");
783
+ var defaultSvgProps = (size) => ({
784
+ width: size,
785
+ height: size,
786
+ viewBox: "0 0 24 24",
787
+ fill: "none",
788
+ stroke: "currentColor",
789
+ strokeWidth: 2,
790
+ strokeLinecap: "round",
791
+ strokeLinejoin: "round"
792
+ });
793
+ function ShareIconIOS({ size = 24, style, className }) {
794
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
795
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 2L12 15" }),
796
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 6L12 2L16 6" }),
797
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 11v9a2 2 0 002 2h12a2 2 0 002-2v-9" })
798
+ ] });
799
+ }
800
+ function MenuDotsVerticalIcon({ size = 24, style, className }) {
801
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
802
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "5", r: "1.5" }),
803
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
804
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "19", r: "1.5" })
805
+ ] });
806
+ }
807
+ function MenuDotsHorizontalIcon({ size = 24, style, className }) {
808
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
809
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "5", cy: "12", r: "1.5" }),
810
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
811
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "19", cy: "12", r: "1.5" })
812
+ ] });
813
+ }
814
+ function SquarePlusIcon({ size = 24, style, className }) {
815
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
816
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
817
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 8v8" }),
818
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 12h8" })
819
+ ] });
820
+ }
821
+ function DownloadIcon({ size = 24, style, className }) {
822
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
823
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" }),
824
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "7 10 12 15 17 10" }),
825
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
826
+ ] });
827
+ }
828
+ function ExternalLinkIcon({ size = 24, style, className }) {
829
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
830
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }),
831
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "15 3 21 3 21 9" }),
832
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
833
+ ] });
834
+ }
835
+ function XIcon({ size = 20, style, className }) {
836
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
837
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
838
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
839
+ ] });
840
+ }
841
+
842
+ // src/components/InstallGate/variants/AndroidNativeVariant.tsx
843
+ var import_jsx_runtime9 = require("react/jsx-runtime");
844
+ function AndroidNativeVariant({
845
+ state,
846
+ actions
847
+ }) {
848
+ const copy = INSTALL_COPY.android.native;
849
+ const showPermanent = shouldShowPermanentOption(state);
850
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
851
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
852
+ "button",
853
+ {
854
+ "data-testid": "install-prompt-cta-android-native",
855
+ type: "button",
856
+ onClick: () => void actions.promptInstall(),
857
+ style: { ...primaryButtonStyle, display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8 },
858
+ children: [
859
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DownloadIcon, { size: 18 }),
860
+ copy.cta
861
+ ]
862
+ }
863
+ ),
864
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
865
+ "button",
866
+ {
867
+ "data-testid": "install-prompt-skip-session",
868
+ type: "button",
869
+ onClick: actions.dismissSession,
870
+ style: skipLinkStyle,
871
+ children: copy.skip
872
+ }
873
+ ),
874
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
875
+ "button",
876
+ {
877
+ "data-testid": "install-prompt-skip-permanent",
878
+ type: "button",
879
+ onClick: actions.dismissPermanent,
880
+ style: skipPermanentLinkStyle,
881
+ children: copy.skipPermanent
882
+ }
883
+ )
884
+ ] });
885
+ }
886
+
887
+ // src/components/InstallGate/variants/AndroidManualVariant.tsx
888
+ var import_jsx_runtime10 = require("react/jsx-runtime");
889
+ function AndroidManualVariant({
890
+ state,
891
+ actions
892
+ }) {
893
+ const copy = INSTALL_COPY.android.manual;
894
+ const showPermanent = shouldShowPermanentOption(state);
895
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(InstallSplash, { title: copy.title, children: [
896
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Step, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MenuDotsVerticalIcon, { size: 20 }), children: copy.step1 }),
897
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Step, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DownloadIcon, { size: 18 }), children: copy.step2 }),
898
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
899
+ "button",
900
+ {
901
+ "data-testid": "install-prompt-cta-android-manual",
902
+ type: "button",
903
+ onClick: actions.dismissSession,
904
+ style: primaryButtonStyle,
905
+ children: copy.cta
906
+ }
907
+ ),
908
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
909
+ "button",
910
+ {
911
+ "data-testid": "install-prompt-skip-session",
912
+ type: "button",
913
+ onClick: actions.dismissSession,
914
+ style: skipLinkStyle,
915
+ children: copy.skip
916
+ }
917
+ ),
918
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
919
+ "button",
920
+ {
921
+ "data-testid": "install-prompt-skip-permanent",
922
+ type: "button",
923
+ onClick: actions.dismissPermanent,
924
+ style: skipPermanentLinkStyle,
925
+ children: copy.skipPermanent
926
+ }
927
+ )
928
+ ] });
929
+ }
930
+ function Step({ n, icon, children }) {
931
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
932
+ "div",
933
+ {
934
+ style: {
935
+ display: "flex",
936
+ alignItems: "center",
937
+ gap: 12,
938
+ padding: "12px 14px",
939
+ background: "#f5f5f7",
940
+ borderRadius: 12,
941
+ marginBottom: 10,
942
+ textAlign: "left"
943
+ },
944
+ children: [
945
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
946
+ "div",
947
+ {
948
+ style: {
949
+ width: 28,
950
+ height: 28,
951
+ borderRadius: "50%",
952
+ background: "var(--hook-color-primary)",
953
+ color: "#fff",
954
+ display: "flex",
955
+ alignItems: "center",
956
+ justifyContent: "center",
957
+ fontSize: 14,
958
+ fontWeight: 700,
959
+ flexShrink: 0
960
+ },
961
+ children: n
962
+ }
963
+ ),
964
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { flex: 1, fontSize: 15, color: "#333" }, children }),
965
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
966
+ ]
967
+ }
968
+ );
969
+ }
970
+
971
+ // src/components/InstallGate/Step.tsx
972
+ var import_jsx_runtime11 = require("react/jsx-runtime");
973
+ function Step2({
974
+ n,
975
+ title,
976
+ subtitle,
977
+ visual
978
+ }) {
979
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
980
+ "div",
981
+ {
982
+ style: {
983
+ display: "flex",
984
+ alignItems: "flex-start",
985
+ gap: 12,
986
+ marginBottom: 16,
987
+ textAlign: "left"
988
+ },
989
+ children: [
990
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
991
+ "div",
992
+ {
993
+ style: {
994
+ width: 32,
995
+ height: 32,
996
+ borderRadius: 10,
997
+ background: "var(--hook-color-primary)",
998
+ color: "#fff",
999
+ display: "flex",
1000
+ alignItems: "center",
1001
+ justifyContent: "center",
1002
+ fontSize: 15,
1003
+ fontWeight: 700,
1004
+ flexShrink: 0
1005
+ },
1006
+ children: n
1007
+ }
1008
+ ),
1009
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { flex: 1 }, children: [
1010
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: 0, fontSize: 15, fontWeight: 500, color: "#111", lineHeight: 1.3 }, children: title }),
1011
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: "4px 0 0 0", fontSize: 13, color: "#777" }, children: subtitle }),
1012
+ visual
1013
+ ] })
1014
+ ]
1015
+ }
1016
+ );
1017
+ }
1018
+
1019
+ // src/components/InstallGate/variants/IOSafariVariant.tsx
1020
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1021
+ function IOSafariVariant({
1022
+ state,
1023
+ actions
1024
+ }) {
1025
+ const copy = INSTALL_COPY.iosSafari;
1026
+ const showPermanent = shouldShowPermanentOption(state);
1027
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
1028
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1029
+ Step2,
1030
+ {
1031
+ n: 1,
1032
+ title: copy.step1.title,
1033
+ subtitle: copy.step1.subtitle,
1034
+ visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1035
+ "div",
1036
+ {
1037
+ style: {
1038
+ display: "flex",
1039
+ justifyContent: "center",
1040
+ alignItems: "center",
1041
+ background: "#f5f5f7",
1042
+ borderRadius: 12,
1043
+ padding: "12px 0",
1044
+ marginTop: 8
1045
+ },
1046
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
1047
+ }
1048
+ )
1049
+ }
1050
+ ),
1051
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1052
+ Step2,
1053
+ {
1054
+ n: 2,
1055
+ title: copy.step2.title,
1056
+ visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1057
+ "div",
1058
+ {
1059
+ style: {
1060
+ display: "flex",
1061
+ alignItems: "center",
1062
+ gap: 10,
1063
+ background: "#f5f5f7",
1064
+ borderRadius: 12,
1065
+ padding: "12px 14px",
1066
+ marginTop: 8
1067
+ },
1068
+ children: [
1069
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
1070
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
1071
+ ]
1072
+ }
1073
+ )
1074
+ }
1075
+ ),
1076
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1077
+ Step2,
1078
+ {
1079
+ n: 3,
1080
+ title: copy.step3.title,
1081
+ visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1082
+ "div",
1083
+ {
1084
+ style: {
1085
+ display: "flex",
1086
+ justifyContent: "flex-end",
1087
+ background: "#f5f5f7",
1088
+ borderRadius: 12,
1089
+ padding: "10px 14px",
1090
+ marginTop: 8
1091
+ },
1092
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1093
+ "span",
1094
+ {
1095
+ style: {
1096
+ color: "var(--hook-color-primary)",
1097
+ fontSize: 15,
1098
+ fontWeight: 600
1099
+ },
1100
+ children: copy.step3.buttonLabel
1101
+ }
1102
+ )
1103
+ }
1104
+ )
1105
+ }
1106
+ ),
1107
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1108
+ "button",
1109
+ {
1110
+ "data-testid": "install-prompt-skip-session",
1111
+ type: "button",
1112
+ onClick: actions.dismissSession,
1113
+ style: { ...skipLinkStyle, marginTop: 16 },
1114
+ children: copy.skip
1115
+ }
1116
+ ),
1117
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1118
+ "button",
1119
+ {
1120
+ "data-testid": "install-prompt-skip-permanent",
1121
+ type: "button",
1122
+ onClick: actions.dismissPermanent,
1123
+ style: skipPermanentLinkStyle,
1124
+ children: copy.skipPermanent
1125
+ }
1126
+ )
1127
+ ] });
1128
+ }
1129
+
1130
+ // src/components/InstallGate/variants/IOSOtherVariant.tsx
1131
+ var import_react6 = require("react");
1132
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1133
+ function IOSOtherVariant({
1134
+ state,
1135
+ actions
1136
+ }) {
1137
+ const copy = INSTALL_COPY.iosOther;
1138
+ const showPermanent = shouldShowPermanentOption(state);
1139
+ const [copied, setCopied] = (0, import_react6.useState)(false);
1140
+ const [helpOpen, setHelpOpen] = (0, import_react6.useState)(false);
1141
+ const handleCopy = async () => {
1142
+ await actions.copyLink();
1143
+ setCopied(true);
1144
+ setTimeout(() => setCopied(false), 2e3);
1145
+ };
1146
+ const handleShowHelp = () => {
1147
+ if (!helpOpen) actions.showIOSOtherHelp();
1148
+ setHelpOpen(true);
1149
+ };
1150
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
1151
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1152
+ "button",
1153
+ {
1154
+ "data-testid": "install-prompt-cta-ios-other-primary",
1155
+ type: "button",
1156
+ onClick: handleShowHelp,
1157
+ "aria-expanded": helpOpen,
1158
+ style: primaryButtonStyle,
1159
+ children: copy.ctaPrimary
1160
+ }
1161
+ ),
1162
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1163
+ "button",
1164
+ {
1165
+ "data-testid": "install-prompt-cta-ios-other-secondary",
1166
+ type: "button",
1167
+ onClick: () => void handleCopy(),
1168
+ style: secondaryButtonStyle,
1169
+ children: copied ? copy.copiedToast : copy.ctaSecondary
1170
+ }
1171
+ ),
1172
+ helpOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1173
+ "div",
1174
+ {
1175
+ "data-testid": "install-prompt-ios-other-help",
1176
+ style: { marginTop: 20, textAlign: "left" },
1177
+ children: [
1178
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1179
+ Step2,
1180
+ {
1181
+ n: 1,
1182
+ title: copy.help.step1.title,
1183
+ subtitle: copy.help.step1.subtitle,
1184
+ visual: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1185
+ "div",
1186
+ {
1187
+ style: {
1188
+ display: "flex",
1189
+ justifyContent: "center",
1190
+ alignItems: "center",
1191
+ background: "#f5f5f7",
1192
+ borderRadius: 12,
1193
+ padding: "12px 0",
1194
+ marginTop: 8
1195
+ },
1196
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1197
+ MenuDotsHorizontalIcon,
1198
+ {
1199
+ size: 28,
1200
+ style: { color: "var(--hook-color-primary)" }
1201
+ }
1202
+ )
1203
+ }
1204
+ )
1205
+ }
1206
+ ),
1207
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1208
+ Step2,
1209
+ {
1210
+ n: 2,
1211
+ title: copy.help.step2.title,
1212
+ subtitle: copy.help.step2.subtitle,
1213
+ visual: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1214
+ "div",
1215
+ {
1216
+ style: {
1217
+ display: "flex",
1218
+ alignItems: "center",
1219
+ gap: 10,
1220
+ background: "#f5f5f7",
1221
+ borderRadius: 12,
1222
+ padding: "12px 14px",
1223
+ marginTop: 8
1224
+ },
1225
+ children: [
1226
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ExternalLinkIcon, { size: 22, style: { color: "#555" } }),
1227
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: "Abrir no Safari" })
1228
+ ]
1229
+ }
1230
+ )
1231
+ }
1232
+ )
1233
+ ]
1234
+ }
1235
+ ),
1236
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1237
+ "button",
1238
+ {
1239
+ "data-testid": "install-prompt-skip-session",
1240
+ type: "button",
1241
+ onClick: actions.dismissSession,
1242
+ style: skipLinkStyle,
1243
+ children: copy.skip
1244
+ }
1245
+ ),
1246
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1247
+ "button",
1248
+ {
1249
+ "data-testid": "install-prompt-skip-permanent",
1250
+ type: "button",
1251
+ onClick: actions.dismissPermanent,
1252
+ style: skipPermanentLinkStyle,
1253
+ children: copy.skipPermanent
1254
+ }
1255
+ )
1256
+ ] });
1257
+ }
1258
+
1259
+ // src/components/InstallGate/variants/InAppBrowserVariant.tsx
1260
+ var import_react7 = require("react");
1261
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1262
+ function InAppBrowserVariant({
1263
+ state,
1264
+ actions
1265
+ }) {
1266
+ const app = state.inAppApp ?? "other";
1267
+ const appCopy = INSTALL_COPY.inApp[app] ?? INSTALL_COPY.inApp.other;
1268
+ const copy = INSTALL_COPY.inApp;
1269
+ const showPermanent = shouldShowPermanentOption(state);
1270
+ const [copied, setCopied] = (0, import_react7.useState)(false);
1271
+ const handleCopy = async () => {
1272
+ await actions.copyLink();
1273
+ setCopied(true);
1274
+ setTimeout(() => setCopied(false), 2e3);
1275
+ };
1276
+ const DotsIcon = app === "facebook" || app === "telegram" ? MenuDotsVerticalIcon : MenuDotsHorizontalIcon;
1277
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(InstallSplash, { title: appCopy.title, children: [
1278
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Step3, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DotsIcon, { size: 20 }), children: appCopy.step1 }),
1279
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Step3, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ExternalLinkIcon, { size: 18 }), children: appCopy.step2 }),
1280
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1281
+ "button",
1282
+ {
1283
+ "data-testid": "install-prompt-cta-inapp-copy",
1284
+ type: "button",
1285
+ onClick: () => void handleCopy(),
1286
+ style: { ...primaryButtonStyle, marginTop: 8 },
1287
+ children: copied ? copy.copiedToast : copy.copy
1288
+ }
1289
+ ),
1290
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1291
+ "button",
1292
+ {
1293
+ "data-testid": "install-prompt-skip-session",
1294
+ type: "button",
1295
+ onClick: actions.dismissSession,
1296
+ style: skipLinkStyle,
1297
+ children: copy.skip
1298
+ }
1299
+ ),
1300
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1301
+ "button",
1302
+ {
1303
+ "data-testid": "install-prompt-skip-permanent",
1304
+ type: "button",
1305
+ onClick: actions.dismissPermanent,
1306
+ style: skipPermanentLinkStyle,
1307
+ children: copy.skipPermanent
1308
+ }
1309
+ )
1310
+ ] });
1311
+ }
1312
+ function Step3({
1313
+ n,
1314
+ icon,
1315
+ children
1316
+ }) {
1317
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1318
+ "div",
1319
+ {
1320
+ style: {
1321
+ display: "flex",
1322
+ alignItems: "center",
1323
+ gap: 12,
1324
+ padding: "12px 14px",
1325
+ background: "#f5f5f7",
1326
+ borderRadius: 12,
1327
+ marginBottom: 10,
1328
+ textAlign: "left"
1329
+ },
1330
+ children: [
1331
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1332
+ "div",
1333
+ {
1334
+ style: {
1335
+ width: 28,
1336
+ height: 28,
1337
+ borderRadius: "50%",
1338
+ background: "var(--hook-color-primary)",
1339
+ color: "#fff",
1340
+ display: "flex",
1341
+ alignItems: "center",
1342
+ justifyContent: "center",
1343
+ fontSize: 14,
1344
+ fontWeight: 700,
1345
+ flexShrink: 0
1346
+ },
1347
+ children: n
1348
+ }
1349
+ ),
1350
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { flex: 1, fontSize: 14, color: "#333" }, children }),
1351
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
1352
+ ]
1353
+ }
1354
+ );
1355
+ }
1356
+
1357
+ // src/components/InstallGate/variants/DesktopVariant.tsx
1358
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1359
+ function DesktopVariant({
1360
+ state,
1361
+ actions
1362
+ }) {
1363
+ const { name, theme } = useTemplateConfig();
1364
+ const copy = INSTALL_COPY.desktop;
1365
+ const iconUrl = theme.icon_url || theme.logo_url || null;
1366
+ if (!state.isInstallable) return null;
1367
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1368
+ "div",
1369
+ {
1370
+ role: "complementary",
1371
+ "aria-label": copy.title,
1372
+ style: bannerStyle,
1373
+ children: [
1374
+ iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1375
+ "img",
1376
+ {
1377
+ src: iconUrl,
1378
+ alt: "",
1379
+ style: { width: 40, height: 40, borderRadius: 10, objectFit: "cover", flexShrink: 0 }
1380
+ }
1381
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1382
+ "div",
1383
+ {
1384
+ style: {
1385
+ width: 40,
1386
+ height: 40,
1387
+ borderRadius: 10,
1388
+ background: "var(--hook-color-primary)",
1389
+ color: "#fff",
1390
+ display: "flex",
1391
+ alignItems: "center",
1392
+ justifyContent: "center",
1393
+ fontSize: 18,
1394
+ fontWeight: 700,
1395
+ flexShrink: 0
1396
+ },
1397
+ children: name.charAt(0).toUpperCase()
1398
+ }
1399
+ ),
1400
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1401
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontSize: 14, fontWeight: 600, color: "#111" }, children: copy.title }),
1402
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontSize: 12, color: "#666" }, children: copy.subtitle })
1403
+ ] }),
1404
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1405
+ "button",
1406
+ {
1407
+ "data-testid": "install-prompt-cta-desktop",
1408
+ type: "button",
1409
+ onClick: () => void actions.promptInstall(),
1410
+ style: {
1411
+ padding: "8px 14px",
1412
+ background: "var(--hook-color-primary)",
1413
+ color: "#fff",
1414
+ border: "none",
1415
+ borderRadius: 999,
1416
+ fontSize: 13,
1417
+ fontWeight: 600,
1418
+ cursor: "pointer",
1419
+ display: "inline-flex",
1420
+ alignItems: "center",
1421
+ gap: 6,
1422
+ flexShrink: 0
1423
+ },
1424
+ children: [
1425
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DownloadIcon, { size: 14 }),
1426
+ copy.cta
1427
+ ]
1428
+ }
1429
+ ),
1430
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1431
+ "button",
1432
+ {
1433
+ "data-testid": "install-prompt-desktop-close",
1434
+ type: "button",
1435
+ onClick: actions.dismissPermanent,
1436
+ "aria-label": copy.close,
1437
+ style: {
1438
+ background: "transparent",
1439
+ border: "none",
1440
+ cursor: "pointer",
1441
+ color: "#888",
1442
+ padding: 4,
1443
+ flexShrink: 0
1444
+ },
1445
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(XIcon, { size: 16 })
1446
+ }
1447
+ )
1448
+ ]
1449
+ }
1450
+ );
1451
+ }
1452
+ var bannerStyle = {
1453
+ position: "fixed",
1454
+ bottom: 24,
1455
+ right: 24,
1456
+ zIndex: 1e4,
1457
+ display: "flex",
1458
+ alignItems: "center",
1459
+ gap: 12,
1460
+ padding: "12px 16px",
1461
+ background: "#fff",
1462
+ border: "1px solid rgba(0,0,0,0.08)",
1463
+ borderRadius: 16,
1464
+ boxShadow: "0 10px 30px rgba(0,0,0,0.12)",
1465
+ maxWidth: 400
1466
+ };
1467
+
1468
+ // src/components/InstallGate/InstallGate.tsx
1469
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1470
+ function InstallGate({ children }) {
1471
+ const { slug, features_enabled } = useTemplateConfig();
1472
+ const enabled = features_enabled.includes("install_prompt");
1473
+ const installState = useInstallPrompt(slug);
1474
+ const shouldBlock = enabled && shouldBlockInstall(installState);
1475
+ const trackedRef = (0, import_react8.useRef)(null);
1476
+ (0, import_react8.useEffect)(() => {
1477
+ if (!shouldBlock) return;
1478
+ if (typeof window === "undefined") return;
1479
+ const variantKey = `${slug}:${installState.variant}`;
1480
+ if (trackedRef.current === variantKey) return;
1481
+ trackedRef.current = variantKey;
1482
+ window.posthog?.capture?.("pwa_install_splash_shown", {
1483
+ slug,
1484
+ platform: installState.platform,
1485
+ browser: installState.iosBrowser ?? installState.androidBrowser ?? null,
1486
+ in_app_app: installState.inAppApp,
1487
+ variant: installState.variant
1488
+ });
1489
+ }, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
1490
+ if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1491
+ if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1492
+ if (installState.variant === "desktop") {
1493
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1494
+ children,
1495
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DesktopVariant, { state: installState, actions: installState })
1496
+ ] });
1497
+ }
1498
+ if (!shouldBlock) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1499
+ switch (installState.variant) {
1500
+ case "android-native":
1501
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AndroidNativeVariant, { state: installState, actions: installState });
1502
+ case "android-manual":
1503
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AndroidManualVariant, { state: installState, actions: installState });
1504
+ case "ios-safari":
1505
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IOSafariVariant, { state: installState, actions: installState });
1506
+ case "ios-other":
1507
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IOSOtherVariant, { state: installState, actions: installState });
1508
+ case "in-app":
1509
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(InAppBrowserVariant, { state: installState, actions: installState });
1510
+ case "none":
1511
+ default:
1512
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1513
+ }
1514
+ }
1515
+
1516
+ // src/defaults/ErrorBoundary.tsx
1517
+ var import_react9 = require("react");
1518
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1519
+ var ErrorBoundary = class extends import_react9.Component {
217
1520
  state = { error: null };
218
1521
  static getDerivedStateFromError(error) {
219
1522
  return { error };
@@ -223,17 +1526,17 @@ var ErrorBoundary = class extends import_react5.Component {
223
1526
  }
224
1527
  render() {
225
1528
  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." })
1529
+ return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
1530
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { children: "Algo deu errado" }),
1531
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
229
1532
  ] });
230
1533
  }
231
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: this.props.children });
1534
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: this.props.children });
232
1535
  }
233
1536
  };
234
1537
 
235
1538
  // src/hooks/useLoginForm.ts
236
- var import_react6 = require("react");
1539
+ var import_react10 = require("react");
237
1540
  var import_sdk5 = require("@hook-sdk/sdk");
238
1541
 
239
1542
  // src/errors.ts
@@ -270,22 +1573,22 @@ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
270
1573
  var MIN_PASSWORD = 8;
271
1574
  function useLoginForm() {
272
1575
  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)(() => {
1576
+ const [email, setEmail] = (0, import_react10.useState)("");
1577
+ const [password, setPassword] = (0, import_react10.useState)("");
1578
+ const [submitting, setSubmitting] = (0, import_react10.useState)(false);
1579
+ const [error, setError] = (0, import_react10.useState)(null);
1580
+ const emailError = (0, import_react10.useMemo)(() => {
278
1581
  if (email.length === 0) return null;
279
1582
  if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
280
1583
  return null;
281
1584
  }, [email]);
282
- const passwordError = (0, import_react6.useMemo)(() => {
1585
+ const passwordError = (0, import_react10.useMemo)(() => {
283
1586
  if (password.length === 0) return null;
284
1587
  if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
285
1588
  return null;
286
1589
  }, [password]);
287
1590
  const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && emailError === null && passwordError === null && !submitting;
288
- const submit = (0, import_react6.useCallback)(async () => {
1591
+ const submit = (0, import_react10.useCallback)(async () => {
289
1592
  if (!canSubmit) return false;
290
1593
  setSubmitting(true);
291
1594
  setError(null);
@@ -315,13 +1618,13 @@ function useLoginForm() {
315
1618
  }
316
1619
 
317
1620
  // src/internal/GoogleSignInButton.tsx
318
- var import_jsx_runtime8 = require("react/jsx-runtime");
1621
+ var import_jsx_runtime18 = require("react/jsx-runtime");
319
1622
  function GoogleSignInButton({
320
1623
  onClick,
321
1624
  testId = "oauth-google",
322
1625
  label = "Continuar com Google"
323
1626
  }) {
324
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1627
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
325
1628
  "button",
326
1629
  {
327
1630
  "data-testid": testId,
@@ -344,36 +1647,36 @@ function GoogleSignInButton({
344
1647
  fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
345
1648
  },
346
1649
  children: [
347
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(GoogleGlyph, {}),
1650
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GoogleGlyph, {}),
348
1651
  label
349
1652
  ]
350
1653
  }
351
1654
  );
352
1655
  }
353
1656
  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)(
1657
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
1658
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
356
1659
  "path",
357
1660
  {
358
1661
  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
1662
  fill: "#4285F4"
360
1663
  }
361
1664
  ),
362
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1665
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
363
1666
  "path",
364
1667
  {
365
1668
  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
1669
  fill: "#34A853"
367
1670
  }
368
1671
  ),
369
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1672
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
370
1673
  "path",
371
1674
  {
372
1675
  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
1676
  fill: "#FBBC05"
374
1677
  }
375
1678
  ),
376
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1679
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
377
1680
  "path",
378
1681
  {
379
1682
  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 +1687,8 @@ function GoogleGlyph() {
384
1687
  }
385
1688
 
386
1689
  // src/internal/OAuthErrorBanner.tsx
387
- var import_react7 = require("react");
388
- var import_jsx_runtime9 = require("react/jsx-runtime");
1690
+ var import_react11 = require("react");
1691
+ var import_jsx_runtime19 = require("react/jsx-runtime");
389
1692
  var ERROR_MESSAGES = {
390
1693
  invalid_state: "Sess\xE3o expirou, tente de novo.",
391
1694
  access_denied: "Voc\xEA cancelou o login com Google.",
@@ -405,13 +1708,13 @@ function stripErrorFromUrl() {
405
1708
  window.history.replaceState({}, "", url.toString());
406
1709
  }
407
1710
  function OAuthErrorBanner() {
408
- const [code, setCode] = (0, import_react7.useState)(() => readErrorCode());
409
- (0, import_react7.useEffect)(() => {
1711
+ const [code, setCode] = (0, import_react11.useState)(() => readErrorCode());
1712
+ (0, import_react11.useEffect)(() => {
410
1713
  if (code !== null) stripErrorFromUrl();
411
1714
  }, [code]);
412
1715
  if (!code) return null;
413
1716
  const message = ERROR_MESSAGES[code] ?? "N\xE3o conseguimos conectar ao Google. Tente de novo.";
414
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1717
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
415
1718
  "div",
416
1719
  {
417
1720
  role: "alert",
@@ -426,7 +1729,7 @@ function OAuthErrorBanner() {
426
1729
  },
427
1730
  children: [
428
1731
  message,
429
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1732
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
430
1733
  "button",
431
1734
  {
432
1735
  type: "button",
@@ -451,16 +1754,16 @@ function OAuthErrorBanner() {
451
1754
  }
452
1755
 
453
1756
  // src/defaults/DefaultLoginScreen.tsx
454
- var import_jsx_runtime10 = require("react/jsx-runtime");
1757
+ var import_jsx_runtime20 = require("react/jsx-runtime");
455
1758
  function DefaultLoginScreen({ onNavigate }) {
456
1759
  const { name } = useTemplateConfig();
457
1760
  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)(
1761
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
1762
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
1763
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Entre na sua conta" }),
1764
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(OAuthErrorBanner, {}),
1765
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "login-oauth-google" }),
1766
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
464
1767
  "div",
465
1768
  {
466
1769
  "aria-hidden": "true",
@@ -473,19 +1776,19 @@ function DefaultLoginScreen({ onNavigate }) {
473
1776
  fontSize: 12
474
1777
  },
475
1778
  children: [
476
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
1779
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
477
1780
  "ou",
478
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
1781
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
479
1782
  ]
480
1783
  }
481
1784
  ),
482
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("form", { onSubmit: (e) => {
1785
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("form", { onSubmit: (e) => {
483
1786
  e.preventDefault();
484
1787
  void f.submit();
485
1788
  }, children: [
486
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1789
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
487
1790
  "E-mail",
488
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1791
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
489
1792
  "input",
490
1793
  {
491
1794
  "data-testid": "login-email",
@@ -495,11 +1798,11 @@ function DefaultLoginScreen({ onNavigate }) {
495
1798
  style: { display: "block", width: "100%" }
496
1799
  }
497
1800
  ),
498
- f.emailError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
1801
+ f.emailError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
499
1802
  ] }),
500
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1803
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
501
1804
  "Senha",
502
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1805
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
503
1806
  "input",
504
1807
  {
505
1808
  "data-testid": "login-password",
@@ -509,10 +1812,10 @@ function DefaultLoginScreen({ onNavigate }) {
509
1812
  style: { display: "block", width: "100%" }
510
1813
  }
511
1814
  ),
512
- f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
1815
+ f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
513
1816
  ] }),
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)(
1817
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
1818
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
516
1819
  "button",
517
1820
  {
518
1821
  "data-testid": "login-submit",
@@ -531,42 +1834,42 @@ function DefaultLoginScreen({ onNavigate }) {
531
1834
  }
532
1835
  )
533
1836
  ] }),
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" })
1837
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { marginTop: 16, display: "flex", justifyContent: "space-between" }, children: [
1838
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { "data-testid": "login-goto-signup", type: "button", onClick: () => onNavigate("signup"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Criar conta" }),
1839
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { "data-testid": "login-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Esqueci senha" })
537
1840
  ] })
538
1841
  ] });
539
1842
  }
540
1843
 
541
1844
  // src/hooks/useSignupForm.ts
542
- var import_react8 = require("react");
1845
+ var import_react12 = require("react");
543
1846
  var import_sdk6 = require("@hook-sdk/sdk");
544
1847
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
545
1848
  var MIN_PASSWORD2 = 8;
546
1849
  function useSignupForm() {
547
1850
  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)(() => {
1851
+ const [name, setName] = (0, import_react12.useState)("");
1852
+ const [email, setEmail] = (0, import_react12.useState)("");
1853
+ const [password, setPassword] = (0, import_react12.useState)("");
1854
+ const [submitting, setSubmitting] = (0, import_react12.useState)(false);
1855
+ const [error, setError] = (0, import_react12.useState)(null);
1856
+ const nameError = (0, import_react12.useMemo)(() => {
554
1857
  if (name.length === 0) return null;
555
1858
  if (name.trim().length < 2) return "Nome muito curto.";
556
1859
  return null;
557
1860
  }, [name]);
558
- const emailError = (0, import_react8.useMemo)(() => {
1861
+ const emailError = (0, import_react12.useMemo)(() => {
559
1862
  if (email.length === 0) return null;
560
1863
  if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
561
1864
  return null;
562
1865
  }, [email]);
563
- const passwordError = (0, import_react8.useMemo)(() => {
1866
+ const passwordError = (0, import_react12.useMemo)(() => {
564
1867
  if (password.length === 0) return null;
565
1868
  if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
566
1869
  return null;
567
1870
  }, [password]);
568
1871
  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 () => {
1872
+ const submit = (0, import_react12.useCallback)(async () => {
570
1873
  if (!canSubmit) return false;
571
1874
  setSubmitting(true);
572
1875
  setError(null);
@@ -599,16 +1902,16 @@ function useSignupForm() {
599
1902
  }
600
1903
 
601
1904
  // src/defaults/DefaultSignupScreen.tsx
602
- var import_jsx_runtime11 = require("react/jsx-runtime");
1905
+ var import_jsx_runtime21 = require("react/jsx-runtime");
603
1906
  function DefaultSignupScreen({ onNavigate }) {
604
1907
  const { name } = useTemplateConfig();
605
1908
  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)(
1909
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
1910
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
1911
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Criar sua conta" }),
1912
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(OAuthErrorBanner, {}),
1913
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "signup-oauth-google" }),
1914
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
612
1915
  "div",
613
1916
  {
614
1917
  "aria-hidden": "true",
@@ -621,55 +1924,55 @@ function DefaultSignupScreen({ onNavigate }) {
621
1924
  fontSize: 12
622
1925
  },
623
1926
  children: [
624
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
1927
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
625
1928
  "ou",
626
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
1929
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
627
1930
  ]
628
1931
  }
629
1932
  ),
630
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("form", { onSubmit: (e) => {
1933
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("form", { onSubmit: (e) => {
631
1934
  e.preventDefault();
632
1935
  void f.submit();
633
1936
  }, children: [
634
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1937
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
635
1938
  "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 })
1939
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { "data-testid": "signup-name", value: f.name, onChange: (e) => f.setName(e.target.value), style: { display: "block", width: "100%" } }),
1940
+ f.nameError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { style: { color: "#c00" }, children: f.nameError })
638
1941
  ] }),
639
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1942
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
640
1943
  "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 })
1944
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { "data-testid": "signup-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
1945
+ f.emailError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
643
1946
  ] }),
644
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
1947
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
645
1948
  "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 })
1949
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { "data-testid": "signup-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" } }),
1950
+ f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
648
1951
  ] }),
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" })
1952
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
1953
+ /* @__PURE__ */ (0, import_jsx_runtime21.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
1954
  ] }),
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" }) })
1955
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.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
1956
  ] });
654
1957
  }
655
1958
 
656
1959
  // src/hooks/useForgotForm.ts
657
- var import_react9 = require("react");
1960
+ var import_react13 = require("react");
658
1961
  var import_sdk7 = require("@hook-sdk/sdk");
659
1962
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
660
1963
  function useForgotForm() {
661
1964
  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)(() => {
1965
+ const [email, setEmail] = (0, import_react13.useState)("");
1966
+ const [submitting, setSubmitting] = (0, import_react13.useState)(false);
1967
+ const [sent, setSent] = (0, import_react13.useState)(false);
1968
+ const [error, setError] = (0, import_react13.useState)(null);
1969
+ const emailError = (0, import_react13.useMemo)(() => {
667
1970
  if (email.length === 0) return null;
668
1971
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
669
1972
  return null;
670
1973
  }, [email]);
671
1974
  const canSubmit = email.length > 0 && emailError === null && !submitting;
672
- const submit = (0, import_react9.useCallback)(async () => {
1975
+ const submit = (0, import_react13.useCallback)(async () => {
673
1976
  if (!canSubmit) return false;
674
1977
  setSubmitting(true);
675
1978
  setError(null);
@@ -697,66 +2000,66 @@ function useForgotForm() {
697
2000
  }
698
2001
 
699
2002
  // src/defaults/DefaultForgotScreen.tsx
700
- var import_jsx_runtime12 = require("react/jsx-runtime");
2003
+ var import_jsx_runtime22 = require("react/jsx-runtime");
701
2004
  function DefaultForgotScreen({ onNavigate }) {
702
2005
  const { name } = useTemplateConfig();
703
2006
  const f = useForgotForm();
704
2007
  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" })
2008
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
2009
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { children: "Verifique seu e-mail" }),
2010
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7 }, children: "Enviamos um link pra redefinir sua senha." }),
2011
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "forgot-back-login", type: "button", onClick: () => onNavigate("login"), children: "Voltar pro login" })
709
2012
  ] });
710
2013
  }
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) => {
2014
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
2015
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
2016
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Redefinir senha" }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("form", { onSubmit: (e) => {
715
2018
  e.preventDefault();
716
2019
  void f.submit();
717
2020
  }, children: [
718
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
2021
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
719
2022
  "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 })
2023
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("input", { "data-testid": "forgot-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
2024
+ f.emailError && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
722
2025
  ] }),
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" })
2026
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
2027
+ /* @__PURE__ */ (0, import_jsx_runtime22.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
2028
  ] }),
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" }) })
2029
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "forgot-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Voltar pro login" }) })
727
2030
  ] });
728
2031
  }
729
2032
 
730
2033
  // src/hooks/useResetForm.ts
731
- var import_react10 = require("react");
2034
+ var import_react14 = require("react");
732
2035
  var import_sdk8 = require("@hook-sdk/sdk");
733
2036
  var MIN_PASSWORD3 = 12;
734
2037
  function useResetForm() {
735
2038
  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)(() => {
2039
+ const [token, setToken] = (0, import_react14.useState)(null);
2040
+ const [password, setPassword] = (0, import_react14.useState)("");
2041
+ const [confirm, setConfirm] = (0, import_react14.useState)("");
2042
+ const [submitting, setSubmitting] = (0, import_react14.useState)(false);
2043
+ const [done, setDone] = (0, import_react14.useState)(false);
2044
+ const [error, setError] = (0, import_react14.useState)(null);
2045
+ (0, import_react14.useEffect)(() => {
743
2046
  if (typeof window === "undefined") return;
744
2047
  const params = new URLSearchParams(window.location.search);
745
2048
  const t = params.get("token");
746
2049
  setToken(t && t.length > 0 ? t : null);
747
2050
  }, []);
748
- const passwordError = (0, import_react10.useMemo)(() => {
2051
+ const passwordError = (0, import_react14.useMemo)(() => {
749
2052
  if (password.length === 0) return null;
750
2053
  if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
751
2054
  return null;
752
2055
  }, [password]);
753
- const confirmError = (0, import_react10.useMemo)(() => {
2056
+ const confirmError = (0, import_react14.useMemo)(() => {
754
2057
  if (confirm.length === 0) return null;
755
2058
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
756
2059
  return null;
757
2060
  }, [confirm, password]);
758
2061
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && passwordError === null && confirmError === null && !submitting && !done;
759
- const submit = (0, import_react10.useCallback)(async () => {
2062
+ const submit = (0, import_react14.useCallback)(async () => {
760
2063
  if (!canSubmit || token === null) return;
761
2064
  setSubmitting(true);
762
2065
  setError(null);
@@ -792,67 +2095,67 @@ function useResetForm() {
792
2095
  }
793
2096
 
794
2097
  // src/defaults/DefaultResetScreen.tsx
795
- var import_jsx_runtime13 = require("react/jsx-runtime");
2098
+ var import_jsx_runtime23 = require("react/jsx-runtime");
796
2099
  function DefaultResetScreen({ onNavigate }) {
797
2100
  const { name } = useTemplateConfig();
798
2101
  const f = useResetForm();
799
2102
  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" })
2103
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
2104
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { children: "Senha alterada" }),
2105
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7 }, children: "Agora \xE9 s\xF3 fazer login com a nova senha." }),
2106
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { "data-testid": "reset-back-login", type: "button", onClick: () => onNavigate("login"), children: "Ir pro login" })
804
2107
  ] });
805
2108
  }
806
2109
  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" })
2110
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
2111
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { children: "Link inv\xE1lido" }),
2112
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7 }, children: "Pe\xE7a um novo link de reset." }),
2113
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { "data-testid": "reset-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), children: "Pedir novo link" })
811
2114
  ] });
812
2115
  }
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) => {
2116
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
2117
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
2118
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Escolha uma nova senha" }),
2119
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("form", { onSubmit: (e) => {
817
2120
  e.preventDefault();
818
2121
  void f.submit();
819
2122
  }, children: [
820
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
2123
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
821
2124
  "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 })
2125
+ /* @__PURE__ */ (0, import_jsx_runtime23.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" }),
2126
+ f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
824
2127
  ] }),
825
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
2128
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
826
2129
  "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 })
2130
+ /* @__PURE__ */ (0, import_jsx_runtime23.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" }),
2131
+ f.confirmError && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("small", { style: { color: "#c00" }, children: f.confirmError })
829
2132
  ] }),
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" })
2133
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
2134
+ /* @__PURE__ */ (0, import_jsx_runtime23.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
2135
  ] })
833
2136
  ] });
834
2137
  }
835
2138
 
836
2139
  // src/defaults/DefaultPaywall.tsx
837
- var import_react11 = require("react");
838
- var import_jsx_runtime14 = require("react/jsx-runtime");
2140
+ var import_react15 = require("react");
2141
+ var import_jsx_runtime24 = require("react/jsx-runtime");
839
2142
  function DefaultPaywall() {
840
2143
  const config = useTemplateConfig();
841
2144
  const { checkout, opening, error } = usePaywallState();
842
2145
  const p = config.subscription.paywall_config;
843
- const [cpf, setCpf] = (0, import_react11.useState)("");
2146
+ const [cpf, setCpf] = (0, import_react15.useState)("");
844
2147
  const cpfDigits = cpf.replace(/\D/g, "");
845
2148
  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 })
2149
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("main", { style: { padding: 24, maxWidth: 440, margin: "0 auto", textAlign: "center" }, children: [
2150
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h1", { style: { marginBottom: 8 }, children: p.title }),
2151
+ p.subtitle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: p.subtitle }),
2152
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("ul", { style: { listStyle: "none", padding: 0, textAlign: "left", marginBottom: 24 }, children: p.benefits.map((b) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("li", { style: { padding: "8px 0", display: "flex", alignItems: "center" }, children: [
2153
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, style: { marginRight: 8 }, children: "\u2713" }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: b })
852
2155
  ] }, 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)(
2156
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { textAlign: "left", marginBottom: 16 }, children: [
2157
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("label", { style: { display: "block", fontSize: 14, opacity: 0.7, marginBottom: 4 }, children: "Seu CPF (pra emiss\xE3o de recibo)" }),
2158
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
856
2159
  "input",
857
2160
  {
858
2161
  "data-testid": "paywall-cpf",
@@ -865,8 +2168,8 @@ function DefaultPaywall() {
865
2168
  }
866
2169
  )
867
2170
  ] }),
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)(
2171
+ error && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: error.message }),
2172
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
870
2173
  "button",
871
2174
  {
872
2175
  "data-testid": "paywall-cta",
@@ -887,21 +2190,21 @@ function DefaultPaywall() {
887
2190
  children: opening ? "Abrindo..." : p.cta
888
2191
  }
889
2192
  ),
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 })
2193
+ p.priceHint && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { opacity: 0.6, marginTop: 12 }, children: p.priceHint }),
2194
+ p.footerNote && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { opacity: 0.5, marginTop: 16, fontSize: 12 }, children: p.footerNote })
892
2195
  ] });
893
2196
  }
894
2197
 
895
2198
  // src/AppRoot.tsx
896
- var import_jsx_runtime15 = require("react/jsx-runtime");
2199
+ var import_jsx_runtime25 = require("react/jsx-runtime");
897
2200
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
898
2201
  function PaymentReturnHandler({ children }) {
899
2202
  const { subscription } = (0, import_sdk9.useHook)();
900
- const subRef = (0, import_react12.useRef)(subscription);
2203
+ const subRef = (0, import_react16.useRef)(subscription);
901
2204
  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)(() => {
2205
+ const runIdRef = (0, import_react16.useRef)(0);
2206
+ const [state, setState] = (0, import_react16.useState)("idle");
2207
+ const runPoll = (0, import_react16.useCallback)(() => {
905
2208
  const runId = ++runIdRef.current;
906
2209
  setState("confirming");
907
2210
  let attempts = 0;
@@ -930,7 +2233,7 @@ function PaymentReturnHandler({ children }) {
930
2233
  };
931
2234
  void tick();
932
2235
  }, []);
933
- (0, import_react12.useEffect)(() => {
2236
+ (0, import_react16.useEffect)(() => {
934
2237
  if (typeof window === "undefined") return;
935
2238
  const url = new URL(window.location.href);
936
2239
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -940,20 +2243,20 @@ function PaymentReturnHandler({ children }) {
940
2243
  };
941
2244
  }, [runPoll]);
942
2245
  if (state === "confirming") {
943
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2246
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
944
2247
  "div",
945
2248
  {
946
2249
  role: "status",
947
2250
  "aria-live": "polite",
948
- style: overlayStyle,
2251
+ style: overlayStyle2,
949
2252
  children: "Confirmando pagamento\u2026"
950
2253
  }
951
2254
  );
952
2255
  }
953
2256
  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)(
2257
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2258
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2259
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
957
2260
  "button",
958
2261
  {
959
2262
  type: "button",
@@ -964,9 +2267,9 @@ function PaymentReturnHandler({ children }) {
964
2267
  )
965
2268
  ] }) });
966
2269
  }
967
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
2270
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children });
968
2271
  }
969
- var overlayStyle = {
2272
+ var overlayStyle2 = {
970
2273
  position: "fixed",
971
2274
  inset: 0,
972
2275
  display: "flex",
@@ -997,14 +2300,14 @@ function AppRoot({
997
2300
  Reset = DefaultResetScreen,
998
2301
  Paywall = DefaultPaywall
999
2302
  }) {
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: [
2303
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(PaymentReturnHandler, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TemplateConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AuthGate, { Login, Signup, Forgot, Reset, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(PersistedKeysPrefetch, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(SubscriptionGate, { Paywall, children: [
1001
2304
  children,
1002
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PushPrompt, {})
1003
- ] }) }) }) }) }) }) });
2305
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(PushPrompt, {})
2306
+ ] }) }) }) }) }) }) }) });
1004
2307
  }
1005
2308
 
1006
2309
  // src/hooks/usePush.ts
1007
- var import_react13 = require("react");
2310
+ var import_react17 = require("react");
1008
2311
  var import_sdk10 = require("@hook-sdk/sdk");
1009
2312
  function detectIosNeedsInstall() {
1010
2313
  if (typeof navigator === "undefined" || typeof window === "undefined") return false;
@@ -1032,11 +2335,11 @@ function deriveState(push) {
1032
2335
  }
1033
2336
  function usePush() {
1034
2337
  const { push } = (0, import_sdk10.useHook)();
1035
- const [state, setState] = (0, import_react13.useState)(() => deriveState(push));
1036
- (0, import_react13.useEffect)(() => {
2338
+ const [state, setState] = (0, import_react17.useState)(() => deriveState(push));
2339
+ (0, import_react17.useEffect)(() => {
1037
2340
  setState(deriveState(push));
1038
2341
  }, [push]);
1039
- const subscribe = (0, import_react13.useCallback)(async () => {
2342
+ const subscribe = (0, import_react17.useCallback)(async () => {
1040
2343
  try {
1041
2344
  await push.subscribe();
1042
2345
  setState({ kind: "subscribed" });
@@ -1048,7 +2351,7 @@ function usePush() {
1048
2351
  throw e;
1049
2352
  }
1050
2353
  }, [push]);
1051
- const unsubscribe = (0, import_react13.useCallback)(async () => {
2354
+ const unsubscribe = (0, import_react17.useCallback)(async () => {
1052
2355
  try {
1053
2356
  await push.unsubscribe();
1054
2357
  setState({ kind: "prompt" });
@@ -1061,31 +2364,31 @@ function usePush() {
1061
2364
  }
1062
2365
 
1063
2366
  // src/components/PushPrompt.tsx
1064
- var import_jsx_runtime16 = require("react/jsx-runtime");
2367
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1065
2368
  function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
1066
2369
  const { state, subscribe } = usePush();
1067
2370
  if (state.kind === "subscribed") return null;
1068
2371
  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 })
2372
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2373
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h3", { children: texts.iosInstallTitle }),
2374
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { children: texts.iosInstallBody }),
2375
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
1073
2376
  ] });
1074
2377
  }
1075
2378
  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 })
2379
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2380
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h3", { children: texts.deniedTitle }),
2381
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { children: texts.deniedBody })
1079
2382
  ] });
1080
2383
  }
1081
2384
  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 }) });
2385
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { children: texts.unsupportedBody }) });
1083
2386
  }
1084
2387
  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 }) });
2388
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { children: state.message }) });
1086
2389
  }
1087
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, role: "region", children: [
1088
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2390
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className, role: "region", children: [
2391
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1089
2392
  "button",
1090
2393
  {
1091
2394
  type: "button",
@@ -1099,27 +2402,27 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
1099
2402
  children: texts.cta
1100
2403
  }
1101
2404
  ),
1102
- onDeclined && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2405
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
1103
2406
  ] });
1104
2407
  }
1105
2408
 
1106
2409
  // src/defaults/EmptyState.tsx
1107
- var import_jsx_runtime17 = require("react/jsx-runtime");
2410
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1108
2411
  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 })
2412
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2413
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2414
+ description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2415
+ action && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { style: { marginTop: 16 }, children: action })
1113
2416
  ] });
1114
2417
  }
1115
2418
 
1116
2419
  // src/hooks/useAuthPrimitives.ts
1117
- var import_react14 = require("react");
2420
+ var import_react18 = require("react");
1118
2421
  var import_sdk11 = require("@hook-sdk/sdk");
1119
2422
  var warned = false;
1120
2423
  function useAuthPrimitives() {
1121
2424
  const { auth } = (0, import_sdk11.useHook)();
1122
- (0, import_react14.useEffect)(() => {
2425
+ (0, import_react18.useEffect)(() => {
1123
2426
  if (!warned && process.env.NODE_ENV !== "production") {
1124
2427
  warned = true;
1125
2428
  console.warn(
@@ -1150,14 +2453,14 @@ function useSubscription() {
1150
2453
  }
1151
2454
 
1152
2455
  // src/hooks/useReminders.ts
1153
- var import_react15 = require("react");
2456
+ var import_react19 = require("react");
1154
2457
  var import_sdk13 = require("@hook-sdk/sdk");
1155
2458
  function useReminders() {
1156
2459
  const { push } = (0, import_sdk13.useHook)();
1157
2460
  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 () => {
2461
+ const [reminders, setReminders] = (0, import_react19.useState)([]);
2462
+ const [loading, setLoading] = (0, import_react19.useState)(true);
2463
+ const reload = (0, import_react19.useCallback)(async () => {
1161
2464
  setLoading(true);
1162
2465
  try {
1163
2466
  const next = await r.list();
@@ -1166,38 +2469,38 @@ function useReminders() {
1166
2469
  setLoading(false);
1167
2470
  }
1168
2471
  }, [r]);
1169
- (0, import_react15.useEffect)(() => {
2472
+ (0, import_react19.useEffect)(() => {
1170
2473
  void reload();
1171
2474
  }, [reload]);
1172
- const setReminder = (0, import_react15.useCallback)(async (input) => {
2475
+ const setReminder = (0, import_react19.useCallback)(async (input) => {
1173
2476
  await r.set(input);
1174
2477
  await reload();
1175
2478
  }, [r, reload]);
1176
- const deleteReminder = (0, import_react15.useCallback)(async (slot) => {
2479
+ const deleteReminder = (0, import_react19.useCallback)(async (slot) => {
1177
2480
  await r.delete(slot);
1178
2481
  await reload();
1179
2482
  }, [r, reload]);
1180
- const schedule = (0, import_react15.useCallback)(async (items) => {
2483
+ const schedule = (0, import_react19.useCallback)(async (items) => {
1181
2484
  return r.schedule(items);
1182
2485
  }, [r]);
1183
- const setFallbacks = (0, import_react15.useCallback)(async (items) => {
2486
+ const setFallbacks = (0, import_react19.useCallback)(async (items) => {
1184
2487
  return r.setFallbacks(items);
1185
2488
  }, [r]);
1186
2489
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
1187
2490
  }
1188
2491
 
1189
2492
  // src/hooks/useToast.ts
1190
- var import_react16 = require("react");
2493
+ var import_react20 = require("react");
1191
2494
  function useToast() {
1192
- const [items, setItems] = (0, import_react16.useState)([]);
1193
- const show = (0, import_react16.useCallback)((message, kind = "info") => {
2495
+ const [items, setItems] = (0, import_react20.useState)([]);
2496
+ const show = (0, import_react20.useCallback)((message, kind = "info") => {
1194
2497
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1195
2498
  setItems((prev) => [...prev, { id, message, kind }]);
1196
2499
  setTimeout(() => {
1197
2500
  setItems((prev) => prev.filter((t) => t.id !== id));
1198
2501
  }, 4e3);
1199
2502
  }, []);
1200
- const dismiss = (0, import_react16.useCallback)((id) => {
2503
+ const dismiss = (0, import_react20.useCallback)((id) => {
1201
2504
  setItems((prev) => prev.filter((t) => t.id !== id));
1202
2505
  }, []);
1203
2506
  return { items, show, dismiss };
@@ -1212,11 +2515,21 @@ function useToast() {
1212
2515
  DefaultSignupScreen,
1213
2516
  EmptyState,
1214
2517
  ErrorBoundary,
2518
+ InstallGate,
2519
+ InstallSplash,
1215
2520
  LoadingState,
1216
2521
  PushPrompt,
2522
+ detectAndroidBrowser,
2523
+ detectIOSBrowser,
2524
+ detectInAppApp,
2525
+ detectPlatform,
2526
+ detectStandalone,
2527
+ shouldBlockInstall,
2528
+ shouldShowPermanentOption,
1217
2529
  useAuth,
1218
2530
  useAuthPrimitives,
1219
2531
  useForgotForm,
2532
+ useInstallPrompt,
1220
2533
  useLoginForm,
1221
2534
  usePaywallState,
1222
2535
  usePush,