@sneekin/ui 0.4.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,19 +1,20 @@
1
- // src/use-sneek-otp.ts
1
+ // src/use-sneek-login.ts
2
2
  import { useCallback, useReducer } from "react";
3
3
 
4
4
  // src/state.ts
5
- var initialOtpState = {
5
+ var initialLoginState = {
6
6
  step: "identify",
7
7
  status: "idle",
8
8
  identifier: "",
9
9
  code: "",
10
10
  requestId: "",
11
- channels: [],
12
- expiresInSeconds: 0,
11
+ channel: null,
12
+ maskedIdentifier: "",
13
+ expiresAt: "",
13
14
  error: null
14
15
  };
15
16
  var isBusy = (status) => status !== "idle";
16
- function otpReducer(state, action) {
17
+ function loginReducer(state, action) {
17
18
  switch (action.type) {
18
19
  case "set_identifier":
19
20
  return { ...state, identifier: action.value, error: null };
@@ -21,16 +22,17 @@ function otpReducer(state, action) {
21
22
  return { ...state, code: action.value, error: null };
22
23
  case "request_start":
23
24
  if (isBusy(state.status)) return state;
24
- return { ...state, status: "sending", error: null };
25
+ return { ...state, status: "requesting", error: null };
25
26
  case "request_success":
26
27
  return {
27
28
  ...state,
28
29
  step: "verify",
29
30
  status: "idle",
30
31
  code: "",
31
- requestId: action.result.requestId,
32
- channels: action.result.channels ?? [],
33
- expiresInSeconds: action.result.expiresInSeconds ?? 0,
32
+ requestId: action.request.requestId,
33
+ channel: action.request.channel ?? null,
34
+ maskedIdentifier: action.request.maskedIdentifier ?? "",
35
+ expiresAt: action.request.expiresAt ?? "",
34
36
  error: null
35
37
  };
36
38
  case "request_error":
@@ -47,12 +49,13 @@ function otpReducer(state, action) {
47
49
  status: "idle",
48
50
  code: "",
49
51
  requestId: "",
50
- channels: [],
51
- expiresInSeconds: 0,
52
+ channel: null,
53
+ maskedIdentifier: "",
54
+ expiresAt: "",
52
55
  error: null
53
56
  };
54
57
  case "reset":
55
- return { ...initialOtpState };
58
+ return { ...initialLoginState };
56
59
  default:
57
60
  return state;
58
61
  }
@@ -62,8 +65,8 @@ var CHANNEL_LABELS = {
62
65
  whatsapp: "WhatsApp",
63
66
  email: "email"
64
67
  };
65
- function formatChannels(channels) {
66
- return channels.map((c) => CHANNEL_LABELS[c] ?? c).join(", ");
68
+ function channelLabel(channel) {
69
+ return CHANNEL_LABELS[channel] ?? channel;
67
70
  }
68
71
  function toMessage(error, fallback) {
69
72
  if (error instanceof Error && error.message) return error.message;
@@ -71,12 +74,12 @@ function toMessage(error, fallback) {
71
74
  return fallback;
72
75
  }
73
76
 
74
- // src/use-sneek-otp.ts
77
+ // src/use-sneek-login.ts
75
78
  var DEFAULT_REQUEST_ERROR = "Could not send the code. Please try again.";
76
79
  var DEFAULT_VERIFY_ERROR = "That code was not correct. Please try again.";
77
- function useSneekOtp(handlers) {
78
- const [state, dispatch] = useReducer(otpReducer, initialOtpState);
79
- const { requestOtp, verifyOtp, onSuccess, onError } = handlers;
80
+ function useSneekLogin(handlers) {
81
+ const [state, dispatch] = useReducer(loginReducer, initialLoginState);
82
+ const { requestVerification, verify, onSuccess, onError } = handlers;
80
83
  const setIdentifier = useCallback((value) => {
81
84
  dispatch({ type: "set_identifier", value });
82
85
  }, []);
@@ -92,18 +95,21 @@ function useSneekOtp(handlers) {
92
95
  }
93
96
  dispatch({ type: "request_start" });
94
97
  try {
95
- const result = await requestOtp(trimmed);
96
- dispatch({ type: "request_success", result });
98
+ const request = await requestVerification(trimmed);
99
+ dispatch({ type: "request_success", request });
97
100
  } catch (error) {
98
101
  dispatch({ type: "request_error", message: toMessage(error, DEFAULT_REQUEST_ERROR) });
99
102
  onError?.(error);
100
103
  }
101
104
  },
102
- [requestOtp, onError]
105
+ [requestVerification, onError]
106
+ );
107
+ const startVerification = useCallback(
108
+ () => runRequest(state.identifier),
109
+ [runRequest, state.identifier]
103
110
  );
104
- const sendOtp = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);
105
111
  const resend = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);
106
- const verify = useCallback(async () => {
112
+ const submitCode = useCallback(async () => {
107
113
  const code = state.code.trim();
108
114
  if (!code) {
109
115
  dispatch({ type: "verify_error", message: "Enter the code you received." });
@@ -111,13 +117,13 @@ function useSneekOtp(handlers) {
111
117
  }
112
118
  dispatch({ type: "verify_start" });
113
119
  try {
114
- const result = await verifyOtp({ requestId: state.requestId, code });
120
+ const result = await verify({ requestId: state.requestId, code });
115
121
  onSuccess?.(result);
116
122
  } catch (error) {
117
123
  dispatch({ type: "verify_error", message: toMessage(error, DEFAULT_VERIFY_ERROR) });
118
124
  onError?.(error);
119
125
  }
120
- }, [verifyOtp, state.code, state.requestId, onSuccess, onError]);
126
+ }, [verify, state.code, state.requestId, onSuccess, onError]);
121
127
  const back = useCallback(() => {
122
128
  dispatch({ type: "back_to_identify" });
123
129
  }, []);
@@ -125,11 +131,11 @@ function useSneekOtp(handlers) {
125
131
  ...state,
126
132
  setIdentifier,
127
133
  setCode,
128
- sendOtp,
129
- verify,
134
+ startVerification,
135
+ submitCode,
130
136
  back,
131
137
  resend,
132
- isSending: state.status === "sending",
138
+ isRequesting: state.status === "requesting",
133
139
  isVerifying: state.status === "verifying",
134
140
  isBusy: state.status !== "idle"
135
141
  };
@@ -341,7 +347,7 @@ function CountryPicker({ country, onSelect, disabled }) {
341
347
  "button",
342
348
  {
343
349
  type: "button",
344
- className: "sneek-otp-country-chip",
350
+ className: "sneek-login-country-chip",
345
351
  onClick: () => setOpen((o) => !o),
346
352
  disabled,
347
353
  "aria-haspopup": "listbox",
@@ -480,7 +486,7 @@ function CountryPicker({ country, onSelect, disabled }) {
480
486
  }
481
487
 
482
488
  // src/theme.ts
483
- var SNEEK_STYLE_ID = "sneek-otp-styles";
489
+ var SNEEK_STYLE_ID = "sneek-login-styles";
484
490
  var SNEEK_ACCENT_DARK = "#f86513";
485
491
  var SNEEK_ACCENT_LIGHT = "#b83f06";
486
492
  function buildStyles(accent) {
@@ -512,56 +518,56 @@ function buildStyles(accent) {
512
518
  --sneek-danger: #d43a3c;
513
519
  --sneek-shadow: none;`;
514
520
  return `
515
- .sneek-otp {${light}
521
+ .sneek-login {${light}
516
522
  --sneek-ease: cubic-bezier(0, 0, 0.2, 1);
517
523
  }
518
524
  @media (prefers-color-scheme: dark) {
519
- .sneek-otp:not([data-theme="light"]) {${dark}
525
+ .sneek-login:not([data-theme="light"]) {${dark}
520
526
  }
521
527
  }
522
- .sneek-otp[data-theme="dark"] {${dark}
528
+ .sneek-login[data-theme="dark"] {${dark}
523
529
  }
524
- .sneek-otp[data-theme="light"] {${light}
530
+ .sneek-login[data-theme="light"] {${light}
525
531
  }
526
- .sneek-otp *, .sneek-otp *::before, .sneek-otp *::after { box-sizing: border-box; }
527
- .sneek-otp-input:focus-visible,
528
- .sneek-otp-button:focus-visible,
529
- .sneek-otp-link:focus-visible,
530
- .sneek-otp-country-chip:focus-visible,
531
- .sneek-otp-brand-link:focus-visible {
532
+ .sneek-login *, .sneek-login *::before, .sneek-login *::after { box-sizing: border-box; }
533
+ .sneek-login-input:focus-visible,
534
+ .sneek-login-button:focus-visible,
535
+ .sneek-login-link:focus-visible,
536
+ .sneek-login-country-chip:focus-visible,
537
+ .sneek-login-brand-link:focus-visible {
532
538
  outline: 2px solid var(--sneek-accent);
533
539
  outline-offset: 2px;
534
540
  }
535
- .sneek-otp-input:focus {
541
+ .sneek-login-input:focus {
536
542
  border-color: var(--sneek-accent);
537
543
  }
538
- .sneek-otp-phone-field:focus-within {
544
+ .sneek-login-phone-field:focus-within {
539
545
  border-color: var(--sneek-accent);
540
546
  }
541
- .sneek-otp-button:not(:disabled):hover {
547
+ .sneek-login-button:not(:disabled):hover {
542
548
  filter: brightness(1.08);
543
549
  }
544
- .sneek-otp-link:not(:disabled):hover {
550
+ .sneek-login-link:not(:disabled):hover {
545
551
  text-decoration: underline;
546
552
  }
547
- .sneek-otp-country-chip:not(:disabled):hover {
553
+ .sneek-login-country-chip:not(:disabled):hover {
548
554
  filter: brightness(1.08);
549
555
  }
550
- .sneek-otp-brand-link {
556
+ .sneek-login-brand-link {
551
557
  box-shadow: 0 1px 6px var(--sneek-accent-shadow);
552
558
  }
553
- .sneek-otp-brand-link:hover {
559
+ .sneek-login-brand-link:hover {
554
560
  box-shadow: 0 2px 10px var(--sneek-accent-shadow);
555
561
  }
556
562
  @media (prefers-reduced-motion: reduce) {
557
- .sneek-otp * { transition-duration: 0.01ms !important; }
563
+ .sneek-login * { transition-duration: 0.01ms !important; }
558
564
  }
559
- @keyframes sneek-otp-caret {
565
+ @keyframes sneek-login-caret {
560
566
  0%, 45% { opacity: 1; }
561
567
  50%, 100% { opacity: 0; }
562
568
  }
563
- .sneek-otp-caret {
564
- animation: sneek-otp-caret 1s step-end infinite;
569
+ .sneek-login-caret {
570
+ animation: sneek-login-caret 1s step-end infinite;
565
571
  }
566
572
  `;
567
573
  }
@@ -605,11 +611,11 @@ function SneekMarkBox() {
605
611
  }
606
612
  );
607
613
  }
608
- function SneekOtpLogin(props) {
614
+ function SneekLogin(props) {
609
615
  const {
610
616
  title = "Sign in",
611
617
  verifyTitle = "Enter the code",
612
- subtitle = "Enter your email or phone. We will send you a code.",
618
+ subtitle = "Enter your email or phone to continue.",
613
619
  identifierMode = "both",
614
620
  defaultCountry,
615
621
  identifierLabel,
@@ -622,7 +628,7 @@ function SneekOtpLogin(props) {
622
628
  className,
623
629
  ...handlers
624
630
  } = props;
625
- const otp = useSneekOtp(handlers);
631
+ const login = useSneekLogin(handlers);
626
632
  const uid = useId2();
627
633
  const [resendIn, setResendIn] = useState2(0);
628
634
  const [codeFocused, setCodeFocused] = useState2(false);
@@ -638,7 +644,7 @@ function SneekOtpLogin(props) {
638
644
  const statusId = `${uid}-status`;
639
645
  const onCountrySelect = (next) => {
640
646
  setCountry(next);
641
- otp.setIdentifier(`+${next.dial}${nationalNumber}`);
647
+ login.setIdentifier(`+${next.dial}${nationalNumber}`);
642
648
  };
643
649
  const onNationalNumberChange = (raw) => {
644
650
  let digits = raw.replace(/\D/g, "").slice(0, MAX_NATIONAL_DIGITS + 3);
@@ -653,12 +659,12 @@ function SneekOtpLogin(props) {
653
659
  digits = digits.slice(0, MAX_NATIONAL_DIGITS);
654
660
  if (effectiveCountry !== country) setCountry(effectiveCountry);
655
661
  setNationalNumber(digits);
656
- otp.setIdentifier(`+${effectiveCountry.dial}${digits}`);
662
+ login.setIdentifier(`+${effectiveCountry.dial}${digits}`);
657
663
  };
658
664
  const switchMode = (next) => {
659
665
  setMode(next);
660
666
  setNationalNumber("");
661
- otp.setIdentifier("");
667
+ login.setIdentifier("");
662
668
  };
663
669
  useEffect2(() => {
664
670
  if (typeof document === "undefined") return;
@@ -672,25 +678,27 @@ function SneekOtpLogin(props) {
672
678
  }, [accentColor]);
673
679
  const onIdentifySubmit = (event) => {
674
680
  event.preventDefault();
675
- void otp.sendOtp();
681
+ void login.startVerification();
676
682
  };
677
683
  const onVerifySubmit = (event) => {
678
684
  event.preventDefault();
679
- void otp.verify();
685
+ void login.submitCode();
680
686
  };
681
687
  useEffect2(() => {
682
- if (otp.step === "verify") setResendIn(RESEND_SECONDS);
683
- }, [otp.step]);
688
+ if (login.step === "verify") setResendIn(RESEND_SECONDS);
689
+ }, [login.step]);
684
690
  useEffect2(() => {
685
691
  if (resendIn <= 0) return;
686
692
  const timer = setTimeout(() => setResendIn((n) => n - 1), 1e3);
687
693
  return () => clearTimeout(timer);
688
694
  }, [resendIn]);
689
695
  useEffect2(() => {
690
- if (otp.step === "verify" && otp.code.length === CODE_LENGTH && !otp.isBusy) {
691
- void otp.verify();
696
+ if (login.step === "verify" && login.code.length === CODE_LENGTH && !login.isBusy) {
697
+ void login.submitCode();
692
698
  }
693
- }, [otp.code, otp.step]);
699
+ }, [login.code, login.step]);
700
+ const destination = login.maskedIdentifier || login.identifier;
701
+ const deliveryNotice = login.channel ? `Sent via ${channelLabel(login.channel)} to ${destination}` : `Sent to ${destination}`;
694
702
  const label = {
695
703
  display: "flex",
696
704
  flexDirection: "column",
@@ -718,8 +726,8 @@ function SneekOtpLogin(props) {
718
726
  color: "var(--sneek-accent-contrast)",
719
727
  fontSize: 15,
720
728
  fontWeight: 500,
721
- cursor: otp.isBusy ? "not-allowed" : "pointer",
722
- opacity: otp.isBusy ? 0.6 : 1,
729
+ cursor: login.isBusy ? "not-allowed" : "pointer",
730
+ opacity: login.isBusy ? 0.6 : 1,
723
731
  width: "100%",
724
732
  transition: "filter 200ms var(--sneek-ease), opacity 200ms var(--sneek-ease)"
725
733
  };
@@ -727,7 +735,7 @@ function SneekOtpLogin(props) {
727
735
  border: "none",
728
736
  background: "transparent",
729
737
  color: "var(--sneek-accent)",
730
- cursor: otp.isBusy ? "not-allowed" : "pointer",
738
+ cursor: login.isBusy ? "not-allowed" : "pointer",
731
739
  font: "inherit",
732
740
  fontSize: 14,
733
741
  padding: 0
@@ -743,7 +751,7 @@ function SneekOtpLogin(props) {
743
751
  return /* @__PURE__ */ jsxs2(
744
752
  "div",
745
753
  {
746
- className: className ? `sneek-otp ${className}` : "sneek-otp",
754
+ className: className ? `sneek-login ${className}` : "sneek-login",
747
755
  "data-theme": theme === "auto" ? void 0 : theme,
748
756
  style: {
749
757
  maxWidth: 400,
@@ -770,37 +778,10 @@ function SneekOtpLogin(props) {
770
778
  letterSpacing: "-0.01em",
771
779
  margin: "16px 0 0"
772
780
  },
773
- children: otp.step === "verify" ? verifyTitle : title
781
+ children: login.step === "verify" ? verifyTitle : title
774
782
  }
775
783
  ),
776
- otp.step === "verify" ? /* @__PURE__ */ jsxs2(
777
- "p",
778
- {
779
- style: {
780
- fontSize: 14,
781
- lineHeight: "20px",
782
- color: "var(--sneek-text-muted)",
783
- margin: "8px 0 0"
784
- },
785
- children: [
786
- "Sent to",
787
- " ",
788
- /* @__PURE__ */ jsx2("span", { style: { color: "var(--sneek-text)" }, children: otp.identifier }),
789
- " \xB7 ",
790
- /* @__PURE__ */ jsx2(
791
- "button",
792
- {
793
- type: "button",
794
- className: "sneek-otp-link",
795
- onClick: otp.back,
796
- disabled: otp.isBusy,
797
- style: { ...link, fontSize: 14 },
798
- children: "Change"
799
- }
800
- )
801
- ]
802
- }
803
- ) : subtitle ? /* @__PURE__ */ jsx2(
784
+ login.step === "identify" && subtitle ? /* @__PURE__ */ jsx2(
804
785
  "p",
805
786
  {
806
787
  style: {
@@ -812,7 +793,7 @@ function SneekOtpLogin(props) {
812
793
  children: subtitle
813
794
  }
814
795
  ) : null,
815
- /* @__PURE__ */ jsx2("div", { role: "status", "aria-live": "polite", id: statusId, style: { marginTop: 32 }, children: otp.error ? /* @__PURE__ */ jsx2(
796
+ /* @__PURE__ */ jsx2("div", { role: "status", "aria-live": "polite", id: statusId, style: { marginTop: 32 }, children: login.error ? /* @__PURE__ */ jsx2(
816
797
  "div",
817
798
  {
818
799
  role: "alert",
@@ -821,10 +802,10 @@ function SneekOtpLogin(props) {
821
802
  color: "var(--sneek-danger)",
822
803
  borderColor: "var(--sneek-danger)"
823
804
  },
824
- children: otp.error
805
+ children: login.error
825
806
  }
826
- ) : null }),
827
- otp.step === "identify" ? /* @__PURE__ */ jsxs2(
807
+ ) : login.step === "verify" ? /* @__PURE__ */ jsx2("div", { style: notice, children: deliveryNotice }) : null }),
808
+ login.step === "identify" ? /* @__PURE__ */ jsxs2(
828
809
  "form",
829
810
  {
830
811
  onSubmit: onIdentifySubmit,
@@ -836,9 +817,9 @@ function SneekOtpLogin(props) {
836
817
  "button",
837
818
  {
838
819
  type: "button",
839
- className: "sneek-otp-link",
820
+ className: "sneek-login-link",
840
821
  onClick: () => switchMode(mode === "phone" ? "email" : "phone"),
841
- disabled: otp.isBusy,
822
+ disabled: login.isBusy,
842
823
  style: { ...link, fontSize: 13 },
843
824
  children: mode === "phone" ? "Use email instead" : "Use phone instead"
844
825
  }
@@ -847,7 +828,7 @@ function SneekOtpLogin(props) {
847
828
  mode === "phone" ? /* @__PURE__ */ jsxs2(
848
829
  "div",
849
830
  {
850
- className: "sneek-otp-phone-field",
831
+ className: "sneek-login-phone-field",
851
832
  style: {
852
833
  display: "flex",
853
834
  alignItems: "stretch",
@@ -862,7 +843,7 @@ function SneekOtpLogin(props) {
862
843
  {
863
844
  country,
864
845
  onSelect: onCountrySelect,
865
- disabled: otp.isBusy
846
+ disabled: login.isBusy
866
847
  }
867
848
  ),
868
849
  /* @__PURE__ */ jsx2(
@@ -904,10 +885,10 @@ function SneekOtpLogin(props) {
904
885
  "input",
905
886
  {
906
887
  id: identifierId,
907
- className: "sneek-otp-input",
888
+ className: "sneek-login-input",
908
889
  type: "email",
909
- value: otp.identifier,
910
- onChange: (e) => otp.setIdentifier(e.target.value),
890
+ value: login.identifier,
891
+ onChange: (e) => login.setIdentifier(e.target.value),
911
892
  placeholder: identifierPlaceholder ?? "you@company.com",
912
893
  autoComplete: "email",
913
894
  autoFocus: true,
@@ -920,10 +901,10 @@ function SneekOtpLogin(props) {
920
901
  "button",
921
902
  {
922
903
  type: "submit",
923
- className: "sneek-otp-button",
924
- disabled: otp.isBusy,
904
+ className: "sneek-login-button",
905
+ disabled: login.isBusy,
925
906
  style: button,
926
- children: otp.isSending ? "Sending code\u2026" : "Send code"
907
+ children: login.isRequesting ? "Working\u2026" : "Continue"
927
908
  }
928
909
  )
929
910
  ]
@@ -943,14 +924,14 @@ function SneekOtpLogin(props) {
943
924
  "input",
944
925
  {
945
926
  id: codeId,
946
- className: "sneek-otp-code-input",
927
+ className: "sneek-login-code-input",
947
928
  type: "text",
948
929
  inputMode: "numeric",
949
930
  pattern: "[0-9]*",
950
931
  autoComplete: "one-time-code",
951
932
  maxLength: CODE_LENGTH,
952
- value: otp.code,
953
- onChange: (e) => otp.setCode(
933
+ value: login.code,
934
+ onChange: (e) => login.setCode(
954
935
  e.target.value.replace(/\D/g, "").slice(0, CODE_LENGTH)
955
936
  ),
956
937
  onFocus: () => setCodeFocused(true),
@@ -972,12 +953,12 @@ function SneekOtpLogin(props) {
972
953
  /* @__PURE__ */ jsx2(
973
954
  "div",
974
955
  {
975
- className: "sneek-otp-code-cells",
956
+ className: "sneek-login-code-cells",
976
957
  "aria-hidden": "true",
977
958
  style: { display: "flex", gap: 10 },
978
959
  children: Array.from({ length: CODE_LENGTH }).map((_, i) => {
979
- const digit = otp.code[i];
980
- const isActive = codeFocused && i === otp.code.length;
960
+ const digit = login.code[i];
961
+ const isActive = codeFocused && i === login.code.length;
981
962
  return /* @__PURE__ */ jsx2(
982
963
  "div",
983
964
  {
@@ -996,7 +977,7 @@ function SneekOtpLogin(props) {
996
977
  children: digit ?? (isActive ? /* @__PURE__ */ jsx2(
997
978
  "span",
998
979
  {
999
- className: "sneek-otp-caret",
980
+ className: "sneek-login-caret",
1000
981
  style: {
1001
982
  width: 2,
1002
983
  height: 22,
@@ -1015,39 +996,57 @@ function SneekOtpLogin(props) {
1015
996
  "button",
1016
997
  {
1017
998
  type: "submit",
1018
- className: "sneek-otp-button",
1019
- disabled: otp.isBusy || otp.code.length < CODE_LENGTH,
999
+ className: "sneek-login-button",
1000
+ disabled: login.isBusy || login.code.length < CODE_LENGTH,
1020
1001
  style: {
1021
1002
  ...button,
1022
- opacity: otp.isBusy || otp.code.length < CODE_LENGTH ? 0.6 : 1
1003
+ opacity: login.isBusy || login.code.length < CODE_LENGTH ? 0.6 : 1
1023
1004
  },
1024
- children: otp.isVerifying ? "Verifying\u2026" : "Verify"
1005
+ children: login.isVerifying ? "Verifying\u2026" : "Verify"
1025
1006
  }
1026
1007
  ),
1027
- /* @__PURE__ */ jsx2("div", { style: { textAlign: "center" }, children: resendIn > 0 ? /* @__PURE__ */ jsxs2(
1028
- "span",
1008
+ /* @__PURE__ */ jsxs2(
1009
+ "div",
1029
1010
  {
1030
1011
  style: {
1012
+ display: "flex",
1013
+ justifyContent: "center",
1014
+ alignItems: "center",
1015
+ gap: 10,
1031
1016
  fontSize: 14,
1032
1017
  color: "var(--sneek-text-muted)"
1033
1018
  },
1034
1019
  children: [
1035
- "Resend code in ",
1036
- resendIn,
1037
- "s"
1020
+ resendIn > 0 ? /* @__PURE__ */ jsxs2("span", { children: [
1021
+ "Send again in ",
1022
+ resendIn,
1023
+ "s"
1024
+ ] }) : /* @__PURE__ */ jsx2(
1025
+ "button",
1026
+ {
1027
+ type: "button",
1028
+ className: "sneek-login-link",
1029
+ onClick: () => void login.resend(),
1030
+ disabled: login.isBusy,
1031
+ style: link,
1032
+ children: "Send again"
1033
+ }
1034
+ ),
1035
+ /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "\xB7" }),
1036
+ /* @__PURE__ */ jsx2(
1037
+ "button",
1038
+ {
1039
+ type: "button",
1040
+ className: "sneek-login-link",
1041
+ onClick: login.back,
1042
+ disabled: login.isBusy,
1043
+ style: link,
1044
+ children: "Use a different email or phone"
1045
+ }
1046
+ )
1038
1047
  ]
1039
1048
  }
1040
- ) : /* @__PURE__ */ jsx2(
1041
- "button",
1042
- {
1043
- type: "button",
1044
- className: "sneek-otp-link",
1045
- onClick: () => void otp.resend(),
1046
- disabled: otp.isBusy,
1047
- style: link,
1048
- children: "Resend code"
1049
- }
1050
- ) })
1049
+ )
1051
1050
  ]
1052
1051
  }
1053
1052
  ),
@@ -1070,7 +1069,7 @@ function SneekOtpLogin(props) {
1070
1069
  href: "https://sneek.in",
1071
1070
  target: "_blank",
1072
1071
  rel: "noopener noreferrer",
1073
- className: "sneek-otp-brand-link",
1072
+ className: "sneek-login-brand-link",
1074
1073
  style: {
1075
1074
  display: "inline-block",
1076
1075
  padding: "0 5px",
@@ -1111,11 +1110,11 @@ async function postJson(url, body, options) {
1111
1110
  return await response.json();
1112
1111
  }
1113
1112
  function createFetchHandlers(options = {}) {
1114
- const requestUrl = options.requestUrl ?? "/api/auth/request-otp";
1115
- const verifyUrl = options.verifyUrl ?? "/api/auth/verify-otp";
1113
+ const requestUrl = options.requestUrl ?? "/api/auth/request";
1114
+ const verifyUrl = options.verifyUrl ?? "/api/auth/verify";
1116
1115
  return {
1117
- requestOtp: (identifier) => postJson(requestUrl, { identifier }, options),
1118
- verifyOtp: (input) => postJson(verifyUrl, input, options)
1116
+ requestVerification: (identifier) => postJson(requestUrl, { identifier }, options),
1117
+ verify: (input) => postJson(verifyUrl, input, options)
1119
1118
  };
1120
1119
  }
1121
1120
  export {
@@ -1123,15 +1122,15 @@ export {
1123
1122
  DEFAULT_COUNTRY_ISO2,
1124
1123
  SNEEK_ACCENT_DARK,
1125
1124
  SNEEK_ACCENT_LIGHT,
1126
- SneekOtpLogin,
1125
+ SneekLogin,
1126
+ channelLabel,
1127
1127
  countryByDialPrefix,
1128
1128
  countryByIso2,
1129
1129
  createFetchHandlers,
1130
1130
  detectCountryFromLocale,
1131
1131
  flagEmoji,
1132
- formatChannels,
1133
- initialOtpState,
1134
- otpReducer,
1135
- useSneekOtp
1132
+ initialLoginState,
1133
+ loginReducer,
1134
+ useSneekLogin
1136
1135
  };
1137
1136
  //# sourceMappingURL=index.mjs.map