@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/README.md +43 -19
- package/dist/component.d.ts +5 -5
- package/dist/country-picker.d.ts +1 -1
- package/dist/fetch-handlers.d.ts +10 -9
- package/dist/index.d.ts +6 -6
- package/dist/index.js +147 -148
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +147 -148
- package/dist/index.mjs.map +1 -1
- package/dist/state.d.ts +34 -21
- package/dist/theme.d.ts +2 -2
- package/dist/use-sneek-login.d.ts +44 -0
- package/package.json +1 -1
- package/dist/use-sneek-otp.d.ts +0 -40
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
// src/use-sneek-
|
|
1
|
+
// src/use-sneek-login.ts
|
|
2
2
|
import { useCallback, useReducer } from "react";
|
|
3
3
|
|
|
4
4
|
// src/state.ts
|
|
5
|
-
var
|
|
5
|
+
var initialLoginState = {
|
|
6
6
|
step: "identify",
|
|
7
7
|
status: "idle",
|
|
8
8
|
identifier: "",
|
|
9
9
|
code: "",
|
|
10
10
|
requestId: "",
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
channel: null,
|
|
12
|
+
maskedIdentifier: "",
|
|
13
|
+
expiresAt: "",
|
|
13
14
|
error: null
|
|
14
15
|
};
|
|
15
16
|
var isBusy = (status) => status !== "idle";
|
|
16
|
-
function
|
|
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: "
|
|
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.
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
+
channel: null,
|
|
53
|
+
maskedIdentifier: "",
|
|
54
|
+
expiresAt: "",
|
|
52
55
|
error: null
|
|
53
56
|
};
|
|
54
57
|
case "reset":
|
|
55
|
-
return { ...
|
|
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
|
|
66
|
-
return
|
|
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-
|
|
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
|
|
78
|
-
const [state, dispatch] = useReducer(
|
|
79
|
-
const {
|
|
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
|
|
96
|
-
dispatch({ type: "request_success",
|
|
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
|
-
[
|
|
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
|
|
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
|
|
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
|
-
}, [
|
|
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
|
-
|
|
129
|
-
|
|
134
|
+
startVerification,
|
|
135
|
+
submitCode,
|
|
130
136
|
back,
|
|
131
137
|
resend,
|
|
132
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
525
|
+
.sneek-login:not([data-theme="light"]) {${dark}
|
|
520
526
|
}
|
|
521
527
|
}
|
|
522
|
-
.sneek-
|
|
528
|
+
.sneek-login[data-theme="dark"] {${dark}
|
|
523
529
|
}
|
|
524
|
-
.sneek-
|
|
530
|
+
.sneek-login[data-theme="light"] {${light}
|
|
525
531
|
}
|
|
526
|
-
.sneek-
|
|
527
|
-
.sneek-
|
|
528
|
-
.sneek-
|
|
529
|
-
.sneek-
|
|
530
|
-
.sneek-
|
|
531
|
-
.sneek-
|
|
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-
|
|
541
|
+
.sneek-login-input:focus {
|
|
536
542
|
border-color: var(--sneek-accent);
|
|
537
543
|
}
|
|
538
|
-
.sneek-
|
|
544
|
+
.sneek-login-phone-field:focus-within {
|
|
539
545
|
border-color: var(--sneek-accent);
|
|
540
546
|
}
|
|
541
|
-
.sneek-
|
|
547
|
+
.sneek-login-button:not(:disabled):hover {
|
|
542
548
|
filter: brightness(1.08);
|
|
543
549
|
}
|
|
544
|
-
.sneek-
|
|
550
|
+
.sneek-login-link:not(:disabled):hover {
|
|
545
551
|
text-decoration: underline;
|
|
546
552
|
}
|
|
547
|
-
.sneek-
|
|
553
|
+
.sneek-login-country-chip:not(:disabled):hover {
|
|
548
554
|
filter: brightness(1.08);
|
|
549
555
|
}
|
|
550
|
-
.sneek-
|
|
556
|
+
.sneek-login-brand-link {
|
|
551
557
|
box-shadow: 0 1px 6px var(--sneek-accent-shadow);
|
|
552
558
|
}
|
|
553
|
-
.sneek-
|
|
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-
|
|
563
|
+
.sneek-login * { transition-duration: 0.01ms !important; }
|
|
558
564
|
}
|
|
559
|
-
@keyframes sneek-
|
|
565
|
+
@keyframes sneek-login-caret {
|
|
560
566
|
0%, 45% { opacity: 1; }
|
|
561
567
|
50%, 100% { opacity: 0; }
|
|
562
568
|
}
|
|
563
|
-
.sneek-
|
|
564
|
-
animation: sneek-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
662
|
+
login.setIdentifier(`+${effectiveCountry.dial}${digits}`);
|
|
657
663
|
};
|
|
658
664
|
const switchMode = (next) => {
|
|
659
665
|
setMode(next);
|
|
660
666
|
setNationalNumber("");
|
|
661
|
-
|
|
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
|
|
681
|
+
void login.startVerification();
|
|
676
682
|
};
|
|
677
683
|
const onVerifySubmit = (event) => {
|
|
678
684
|
event.preventDefault();
|
|
679
|
-
void
|
|
685
|
+
void login.submitCode();
|
|
680
686
|
};
|
|
681
687
|
useEffect2(() => {
|
|
682
|
-
if (
|
|
683
|
-
}, [
|
|
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 (
|
|
691
|
-
void
|
|
696
|
+
if (login.step === "verify" && login.code.length === CODE_LENGTH && !login.isBusy) {
|
|
697
|
+
void login.submitCode();
|
|
692
698
|
}
|
|
693
|
-
}, [
|
|
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:
|
|
722
|
-
opacity:
|
|
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:
|
|
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-
|
|
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:
|
|
781
|
+
children: login.step === "verify" ? verifyTitle : title
|
|
774
782
|
}
|
|
775
783
|
),
|
|
776
|
-
|
|
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:
|
|
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:
|
|
805
|
+
children: login.error
|
|
825
806
|
}
|
|
826
|
-
) : null }),
|
|
827
|
-
|
|
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-
|
|
820
|
+
className: "sneek-login-link",
|
|
840
821
|
onClick: () => switchMode(mode === "phone" ? "email" : "phone"),
|
|
841
|
-
disabled:
|
|
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-
|
|
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:
|
|
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-
|
|
888
|
+
className: "sneek-login-input",
|
|
908
889
|
type: "email",
|
|
909
|
-
value:
|
|
910
|
-
onChange: (e) =>
|
|
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-
|
|
924
|
-
disabled:
|
|
904
|
+
className: "sneek-login-button",
|
|
905
|
+
disabled: login.isBusy,
|
|
925
906
|
style: button,
|
|
926
|
-
children:
|
|
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-
|
|
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:
|
|
953
|
-
onChange: (e) =>
|
|
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-
|
|
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 =
|
|
980
|
-
const isActive = codeFocused && i ===
|
|
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-
|
|
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-
|
|
1019
|
-
disabled:
|
|
999
|
+
className: "sneek-login-button",
|
|
1000
|
+
disabled: login.isBusy || login.code.length < CODE_LENGTH,
|
|
1020
1001
|
style: {
|
|
1021
1002
|
...button,
|
|
1022
|
-
opacity:
|
|
1003
|
+
opacity: login.isBusy || login.code.length < CODE_LENGTH ? 0.6 : 1
|
|
1023
1004
|
},
|
|
1024
|
-
children:
|
|
1005
|
+
children: login.isVerifying ? "Verifying\u2026" : "Verify"
|
|
1025
1006
|
}
|
|
1026
1007
|
),
|
|
1027
|
-
/* @__PURE__ */
|
|
1028
|
-
"
|
|
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
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
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
|
-
)
|
|
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-
|
|
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
|
|
1115
|
-
const verifyUrl = options.verifyUrl ?? "/api/auth/verify
|
|
1113
|
+
const requestUrl = options.requestUrl ?? "/api/auth/request";
|
|
1114
|
+
const verifyUrl = options.verifyUrl ?? "/api/auth/verify";
|
|
1116
1115
|
return {
|
|
1117
|
-
|
|
1118
|
-
|
|
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
|
-
|
|
1125
|
+
SneekLogin,
|
|
1126
|
+
channelLabel,
|
|
1127
1127
|
countryByDialPrefix,
|
|
1128
1128
|
countryByIso2,
|
|
1129
1129
|
createFetchHandlers,
|
|
1130
1130
|
detectCountryFromLocale,
|
|
1131
1131
|
flagEmoji,
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
useSneekOtp
|
|
1132
|
+
initialLoginState,
|
|
1133
|
+
loginReducer,
|
|
1134
|
+
useSneekLogin
|
|
1136
1135
|
};
|
|
1137
1136
|
//# sourceMappingURL=index.mjs.map
|