@sneekin/ui 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/component.d.ts +4 -1
- package/dist/index.js +21 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +21 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/component.d.ts
CHANGED
|
@@ -34,7 +34,10 @@ export interface SneekOtpLoginProps<TResult = unknown> extends SneekOtpHandlers<
|
|
|
34
34
|
* which is tuned per mode for contrast.
|
|
35
35
|
*/
|
|
36
36
|
accentColor?: string;
|
|
37
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Replaces the Sneek mark above the title (which sits in a rounded,
|
|
39
|
+
* bordered box by default). Pass `null` to remove it entirely.
|
|
40
|
+
*/
|
|
38
41
|
logo?: ReactNode;
|
|
39
42
|
/** Show the "Secured by Sneek" line under the form. @default true */
|
|
40
43
|
showBranding?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -605,8 +605,8 @@ function SneekMark() {
|
|
|
605
605
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
606
606
|
"svg",
|
|
607
607
|
{
|
|
608
|
-
width: "
|
|
609
|
-
height: "
|
|
608
|
+
width: "20",
|
|
609
|
+
height: "20",
|
|
610
610
|
viewBox: "0 0 32 32",
|
|
611
611
|
fill: "none",
|
|
612
612
|
role: "img",
|
|
@@ -618,6 +618,23 @@ function SneekMark() {
|
|
|
618
618
|
}
|
|
619
619
|
);
|
|
620
620
|
}
|
|
621
|
+
function SneekMarkBox() {
|
|
622
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
623
|
+
"div",
|
|
624
|
+
{
|
|
625
|
+
style: {
|
|
626
|
+
display: "grid",
|
|
627
|
+
placeItems: "center",
|
|
628
|
+
width: 44,
|
|
629
|
+
height: 44,
|
|
630
|
+
borderRadius: 16,
|
|
631
|
+
border: "1px solid var(--sneek-border)",
|
|
632
|
+
background: "var(--sneek-surface)"
|
|
633
|
+
},
|
|
634
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SneekMark, {})
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
}
|
|
621
638
|
function SneekOtpLogin(props) {
|
|
622
639
|
const {
|
|
623
640
|
title = "Sign in",
|
|
@@ -772,9 +789,9 @@ function SneekOtpLogin(props) {
|
|
|
772
789
|
...style
|
|
773
790
|
},
|
|
774
791
|
children: [
|
|
775
|
-
logo === null ? null : logo ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
792
|
+
logo === null ? null : logo ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SneekMarkBox, {}),
|
|
776
793
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
777
|
-
"
|
|
794
|
+
"h2",
|
|
778
795
|
{
|
|
779
796
|
style: {
|
|
780
797
|
fontSize: 21,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/use-sneek-otp.ts","../src/state.ts","../src/component.tsx","../src/country-picker.tsx","../src/countries.ts","../src/theme.ts","../src/fetch-handlers.ts"],"sourcesContent":["export {\n useSneekOtp,\n type SneekOtpHandlers,\n type UseSneekOtp,\n} from './use-sneek-otp';\n\nexport {\n SneekOtpLogin,\n type SneekOtpLoginProps,\n type SneekTheme,\n type SneekIdentifierMode,\n} from './component';\n\nexport {\n SNEEK_ACCENT_DARK,\n SNEEK_ACCENT_LIGHT,\n} from './theme';\n\nexport {\n COUNTRIES,\n DEFAULT_COUNTRY_ISO2,\n flagEmoji,\n countryByIso2,\n countryByDialPrefix,\n detectCountryFromLocale,\n type Country,\n} from './countries';\n\nexport {\n createFetchHandlers,\n type FetchHandlerOptions,\n} from './fetch-handlers';\n\nexport {\n otpReducer,\n initialOtpState,\n formatChannels,\n type SneekChannel,\n type SneekOtpStep,\n type SneekOtpStatus,\n type SneekOtpState,\n type SneekOtpAction,\n type RequestOtpResult,\n} from './state';\n","import { useCallback, useReducer } from 'react';\nimport {\n initialOtpState,\n otpReducer,\n toMessage,\n type RequestOtpResult,\n type SneekOtpState,\n} from './state';\n\n/**\n * Partner-supplied transport. These call the *partner's own backend*, which in\n * turn talks to the Sneek API with the secret server-side key. The browser\n * never sees a Sneek API key — that is the whole security model of this package.\n */\nexport interface SneekOtpHandlers<TResult = unknown> {\n /** Ask the partner backend to send an OTP to `identifier`. */\n requestOtp: (identifier: string) => Promise<RequestOtpResult>;\n /** Verify the code with the partner backend; resolve with the auth result. */\n verifyOtp: (input: { requestId: string; code: string }) => Promise<TResult>;\n /** Called after a successful verification with the partner's result. */\n onSuccess?: (result: TResult) => void;\n /** Called on any error (request or verify). */\n onError?: (error: unknown) => void;\n}\n\nexport interface UseSneekOtp extends SneekOtpState {\n setIdentifier: (value: string) => void;\n setCode: (value: string) => void;\n /** Submit the identify step — triggers `requestOtp`. */\n sendOtp: () => Promise<void>;\n /** Submit the verify step — triggers `verifyOtp`. */\n verify: () => Promise<void>;\n /** Go back to the identify screen (e.g. \"use a different email\"). */\n back: () => void;\n /** Re-send the OTP to the same identifier. */\n resend: () => Promise<void>;\n /** Convenience booleans. */\n isSending: boolean;\n isVerifying: boolean;\n isBusy: boolean;\n}\n\nconst DEFAULT_REQUEST_ERROR = 'Could not send the code. Please try again.';\nconst DEFAULT_VERIFY_ERROR = 'That code was not correct. Please try again.';\n\n/**\n * Headless hook implementing the passwordless OTP login flow. Bring your own\n * markup, or use the {@link SneekOtpLogin} component for a styled default.\n */\nexport function useSneekOtp<TResult = unknown>(\n handlers: SneekOtpHandlers<TResult>,\n): UseSneekOtp {\n const [state, dispatch] = useReducer(otpReducer, initialOtpState);\n\n const { requestOtp, verifyOtp, onSuccess, onError } = handlers;\n\n const setIdentifier = useCallback((value: string) => {\n dispatch({ type: 'set_identifier', value });\n }, []);\n\n const setCode = useCallback((value: string) => {\n dispatch({ type: 'set_code', value });\n }, []);\n\n const runRequest = useCallback(\n async (identifier: string) => {\n const trimmed = identifier.trim();\n if (!trimmed) {\n dispatch({ type: 'request_error', message: 'Enter your email or mobile number.' });\n return;\n }\n dispatch({ type: 'request_start' });\n try {\n const result = await requestOtp(trimmed);\n dispatch({ type: 'request_success', result });\n } catch (error) {\n dispatch({ type: 'request_error', message: toMessage(error, DEFAULT_REQUEST_ERROR) });\n onError?.(error);\n }\n },\n [requestOtp, onError],\n );\n\n const sendOtp = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);\n\n const resend = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);\n\n const verify = useCallback(async () => {\n const code = state.code.trim();\n if (!code) {\n dispatch({ type: 'verify_error', message: 'Enter the code you received.' });\n return;\n }\n dispatch({ type: 'verify_start' });\n try {\n const result = await verifyOtp({ requestId: state.requestId, code });\n onSuccess?.(result);\n } catch (error) {\n dispatch({ type: 'verify_error', message: toMessage(error, DEFAULT_VERIFY_ERROR) });\n onError?.(error);\n }\n }, [verifyOtp, state.code, state.requestId, onSuccess, onError]);\n\n const back = useCallback(() => {\n dispatch({ type: 'back_to_identify' });\n }, []);\n\n return {\n ...state,\n setIdentifier,\n setCode,\n sendOtp,\n verify,\n back,\n resend,\n isSending: state.status === 'sending',\n isVerifying: state.status === 'verifying',\n isBusy: state.status !== 'idle',\n };\n}\n","/**\n * Framework-agnostic state machine for the Sneek passwordless OTP flow.\n *\n * Kept free of React so it can be unit-tested in isolation and reused by other\n * front-end bindings later (Vue/Svelte). The hook in `use-sneek-otp.ts` is a\n * thin wrapper around this reducer.\n */\n\nexport type SneekChannel = 'sms' | 'whatsapp' | 'email';\n\n/** Which screen of the two-step flow is showing. */\nexport type SneekOtpStep = 'identify' | 'verify';\n\n/** Async lifecycle for the in-flight request. */\nexport type SneekOtpStatus = 'idle' | 'sending' | 'verifying';\n\nexport interface SneekOtpState {\n step: SneekOtpStep;\n status: SneekOtpStatus;\n /** The email / mobile / username the user typed. */\n identifier: string;\n /** The OTP code the user typed on the verify screen. */\n code: string;\n /** Opaque id returned by the partner backend, replayed on verify. */\n requestId: string;\n /** Channels the OTP was actually delivered over. */\n channels: SneekChannel[];\n /** Seconds until the OTP expires (from the request response). */\n expiresInSeconds: number;\n /** User-facing error message, or null. */\n error: string | null;\n}\n\nexport const initialOtpState: SneekOtpState = {\n step: 'identify',\n status: 'idle',\n identifier: '',\n code: '',\n requestId: '',\n channels: [],\n expiresInSeconds: 0,\n error: null,\n};\n\nexport interface RequestOtpResult {\n requestId: string;\n channels?: SneekChannel[];\n expiresInSeconds?: number;\n}\n\nexport type SneekOtpAction =\n | { type: 'set_identifier'; value: string }\n | { type: 'set_code'; value: string }\n | { type: 'request_start' }\n | { type: 'request_success'; result: RequestOtpResult }\n | { type: 'request_error'; message: string }\n | { type: 'verify_start' }\n | { type: 'verify_error'; message: string }\n | { type: 'reset' }\n | { type: 'back_to_identify' };\n\nconst isBusy = (status: SneekOtpStatus): boolean => status !== 'idle';\n\nexport function otpReducer(\n state: SneekOtpState,\n action: SneekOtpAction,\n): SneekOtpState {\n switch (action.type) {\n case 'set_identifier':\n return { ...state, identifier: action.value, error: null };\n\n case 'set_code':\n return { ...state, code: action.value, error: null };\n\n case 'request_start':\n // Guard against double submits while a request is already in flight.\n if (isBusy(state.status)) return state;\n return { ...state, status: 'sending', error: null };\n\n case 'request_success':\n return {\n ...state,\n step: 'verify',\n status: 'idle',\n code: '',\n requestId: action.result.requestId,\n channels: action.result.channels ?? [],\n expiresInSeconds: action.result.expiresInSeconds ?? 0,\n error: null,\n };\n\n case 'request_error':\n return { ...state, status: 'idle', error: action.message };\n\n case 'verify_start':\n if (isBusy(state.status)) return state;\n return { ...state, status: 'verifying', error: null };\n\n case 'verify_error':\n return { ...state, status: 'idle', error: action.message };\n\n case 'back_to_identify':\n return {\n ...state,\n step: 'identify',\n status: 'idle',\n code: '',\n requestId: '',\n channels: [],\n expiresInSeconds: 0,\n error: null,\n };\n\n case 'reset':\n return { ...initialOtpState };\n\n default:\n return state;\n }\n}\n\nconst CHANNEL_LABELS: Record<SneekChannel, string> = {\n sms: 'SMS',\n whatsapp: 'WhatsApp',\n email: 'email',\n};\n\n/** \"SMS, WhatsApp\" — human label for the channels an OTP was sent over. */\nexport function formatChannels(channels: SneekChannel[]): string {\n return channels.map((c) => CHANNEL_LABELS[c] ?? c).join(', ');\n}\n\n/** Normalize any thrown value into a user-facing message. */\nexport function toMessage(error: unknown, fallback: string): string {\n if (error instanceof Error && error.message) return error.message;\n if (typeof error === 'string' && error) return error;\n return fallback;\n}\n","import {\n useEffect,\n useId,\n useState,\n type CSSProperties,\n type FormEvent,\n type ReactNode,\n} from 'react';\n\nimport { CountryPicker } from './country-picker';\nimport {\n countryByDialPrefix,\n countryByIso2,\n DEFAULT_COUNTRY_ISO2,\n type Country,\n} from './countries';\nimport { buildStyles, SNEEK_STYLE_ID } from './theme';\nimport { useSneekOtp, type SneekOtpHandlers } from './use-sneek-otp';\n\nexport type SneekTheme = 'auto' | 'light' | 'dark';\nexport type SneekIdentifierMode = 'phone' | 'email' | 'both';\n\n/** Digits in a Sneek code. */\nconst CODE_LENGTH = 6;\n/** Seconds before \"Resend code\" becomes tappable again. */\nconst RESEND_SECONDS = 30;\n/** E.164 allows 15 digits total; this is the remainder after a 3-digit dial code. */\nconst MAX_NATIONAL_DIGITS = 12;\n\nexport interface SneekOtpLoginProps<TResult = unknown>\n extends SneekOtpHandlers<TResult> {\n /** Heading above the form. @default 'Sign in' */\n title?: string;\n /** Heading once the code has been sent. @default 'Enter the code' */\n verifyTitle?: string;\n /** Sub-heading. Pass `null` to remove it. */\n subtitle?: ReactNode;\n /**\n * Which identifiers a visitor can sign in with. `'both'` starts on phone\n * with a country chip and offers a link to switch to email.\n * @default 'both'\n */\n identifierMode?: SneekIdentifierMode;\n /**\n * ISO 3166-1 alpha-2 country to preselect for the phone chip.\n * @default 'IN' (India)\n */\n defaultCountry?: string;\n /** Overrides the auto label (\"Mobile number\" / \"Email address\"). */\n identifierLabel?: string;\n /** Overrides the auto placeholder. Only used in email mode. */\n identifierPlaceholder?: string;\n /**\n * Colour scheme. `auto` follows the visitor's system setting.\n * @default 'auto'\n */\n theme?: SneekTheme;\n /**\n * Override the single accent colour. Leave unset to use Sneek orange,\n * which is tuned per mode for contrast.\n */\n accentColor?: string;\n /** Replaces the Sneek mark above the title. Pass `null` to remove it. */\n logo?: ReactNode;\n /** Show the \"Secured by Sneek\" line under the form. @default true */\n showBranding?: boolean;\n /** Style overrides for the outer card. */\n style?: CSSProperties;\n /** Extra class on the outer card. */\n className?: string;\n}\n\n/**\n * Sneek mark: two triangles offset on a diagonal — one pointing up on the\n * right, one pointing down on the left. Traced from the brand asset so the\n * package needs no image file and no CDN.\n */\nfunction SneekMark() {\n return (\n <svg\n width=\"36\"\n height=\"36\"\n viewBox=\"0 0 32 32\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Sneek\"\n >\n <path d=\"M21.3 1 29.3 16H13.3L21.3 1Z\" fill=\"var(--sneek-accent)\" />\n <path d=\"M2.7 17.5H18.7L10.7 31 2.7 17.5Z\" fill=\"var(--sneek-accent)\" />\n </svg>\n );\n}\n\n/**\n * Drop-in passwordless login card.\n *\n * The component never receives a Sneek API key — it calls the handlers you\n * supply, which talk to your own backend. See `createFetchHandlers` for the\n * common case.\n *\n * @example\n * ```tsx\n * <SneekOtpLogin\n * {...createFetchHandlers({ baseUrl: '/api/auth' })}\n * onSuccess={(session) => router.push('/app')}\n * />\n * ```\n */\nexport function SneekOtpLogin<TResult = unknown>(\n props: SneekOtpLoginProps<TResult>,\n): ReactNode {\n const {\n title = 'Sign in',\n verifyTitle = 'Enter the code',\n subtitle = 'Enter your email or phone. We will send you a code.',\n identifierMode = 'both',\n defaultCountry,\n identifierLabel,\n identifierPlaceholder,\n theme = 'auto',\n accentColor,\n logo,\n showBranding = true,\n style,\n className,\n ...handlers\n } = props;\n\n const otp = useSneekOtp<TResult>(handlers);\n const uid = useId();\n // Countdown before resend re-enables. Instant resend is both poor feedback\n // and an easy way to burn someone's SMS quota.\n const [resendIn, setResendIn] = useState(0);\n const [codeFocused, setCodeFocused] = useState(false);\n const [mode, setMode] = useState<'phone' | 'email'>(\n identifierMode === 'email' ? 'email' : 'phone',\n );\n const [country, setCountry] = useState<Country>(\n () => (defaultCountry && countryByIso2(defaultCountry)) || countryByIso2(DEFAULT_COUNTRY_ISO2)!,\n );\n // The digits typed into the phone field, separate from `otp.identifier`\n // (which holds the composed +<dial><digits> value actually submitted).\n const [nationalNumber, setNationalNumber] = useState('');\n const identifierId = `${uid}-identifier`;\n const codeId = `${uid}-code`;\n const statusId = `${uid}-status`;\n\n const onCountrySelect = (next: Country) => {\n setCountry(next);\n otp.setIdentifier(`+${next.dial}${nationalNumber}`);\n };\n\n const onNationalNumberChange = (raw: string) => {\n let digits = raw.replace(/\\D/g, '').slice(0, MAX_NATIONAL_DIGITS + 3);\n let effectiveCountry = country;\n // Only re-detect off an explicit leading '+' — a real, unambiguous\n // signal that this is a full international number. A plain jump in\n // digit count (paste, or a phone-autofill suggestion) is NOT enough:\n // most 10-digit local numbers coincidentally start with digits that\n // match *some* country's dial code, which would otherwise silently\n // truncate a legitimate local number.\n if (raw.trim().startsWith('+')) {\n const guess = countryByDialPrefix(digits);\n if (guess && digits.startsWith(guess.dial)) {\n effectiveCountry = guess;\n digits = digits.slice(guess.dial.length);\n }\n }\n digits = digits.slice(0, MAX_NATIONAL_DIGITS);\n if (effectiveCountry !== country) setCountry(effectiveCountry);\n setNationalNumber(digits);\n otp.setIdentifier(`+${effectiveCountry.dial}${digits}`);\n };\n\n const switchMode = (next: 'phone' | 'email') => {\n setMode(next);\n setNationalNumber('');\n otp.setIdentifier('');\n };\n\n // One <style> element for the whole page, regardless of how many cards\n // render. Injected on mount so the package stays SSR-safe.\n useEffect(() => {\n if (typeof document === 'undefined') return;\n let el = document.getElementById(SNEEK_STYLE_ID);\n if (!el) {\n el = document.createElement('style');\n el.id = SNEEK_STYLE_ID;\n document.head.appendChild(el);\n }\n el.textContent = buildStyles(accentColor);\n }, [accentColor]);\n\n const onIdentifySubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void otp.sendOtp();\n };\n\n const onVerifySubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void otp.verify();\n };\n\n // Start the cooldown whenever a code goes out.\n useEffect(() => {\n if (otp.step === 'verify') setResendIn(RESEND_SECONDS);\n }, [otp.step]);\n\n useEffect(() => {\n if (resendIn <= 0) return;\n const timer = setTimeout(() => setResendIn((n) => n - 1), 1000);\n return () => clearTimeout(timer);\n }, [resendIn]);\n\n // Submit as soon as the code looks complete — nobody should have to reach\n // for a button after typing the last digit.\n useEffect(() => {\n if (otp.step === 'verify' && otp.code.length === CODE_LENGTH && !otp.isBusy) {\n void otp.verify();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [otp.code, otp.step]);\n\n const label: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n };\n\n const input: CSSProperties = {\n padding: '12px 14px',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n color: 'var(--sneek-text)',\n fontSize: 15,\n width: '100%',\n outline: 'none',\n transition: 'border-color 200ms var(--sneek-ease)',\n };\n\n const button: CSSProperties = {\n padding: '12px 18px',\n border: 'none',\n borderRadius: 9999,\n background: 'var(--sneek-accent)',\n color: 'var(--sneek-accent-contrast)',\n fontSize: 15,\n fontWeight: 500,\n cursor: otp.isBusy ? 'not-allowed' : 'pointer',\n opacity: otp.isBusy ? 0.6 : 1,\n width: '100%',\n transition: 'filter 200ms var(--sneek-ease), opacity 200ms var(--sneek-ease)',\n };\n\n const link: CSSProperties = {\n border: 'none',\n background: 'transparent',\n color: 'var(--sneek-accent)',\n cursor: otp.isBusy ? 'not-allowed' : 'pointer',\n font: 'inherit',\n fontSize: 14,\n padding: 0,\n };\n\n const notice: CSSProperties = {\n padding: '10px 12px',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n border: '1px solid var(--sneek-border)',\n fontSize: 14,\n color: 'var(--sneek-text-muted)',\n };\n\n return (\n <div\n className={className ? `sneek-otp ${className}` : 'sneek-otp'}\n data-theme={theme === 'auto' ? undefined : theme}\n style={{\n maxWidth: 400,\n margin: '0 auto',\n padding: 24,\n border: '1px solid var(--sneek-border)',\n borderRadius: 16,\n background: 'var(--sneek-surface)',\n boxShadow: 'var(--sneek-shadow)',\n color: 'var(--sneek-text)',\n fontFamily:\n 'Inter, ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n lineHeight: 1.5,\n ...style,\n }}\n >\n {logo === null ? null : (logo ?? <SneekMark />)}\n <h1\n style={{\n fontSize: 21,\n lineHeight: '28px',\n fontWeight: 500,\n letterSpacing: '-0.01em',\n margin: '16px 0 0',\n }}\n >\n {otp.step === 'verify' ? verifyTitle : title}\n </h1>\n {otp.step === 'verify' ? (\n <p\n style={{\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n margin: '8px 0 0',\n }}\n >\n Sent to{' '}\n <span style={{ color: 'var(--sneek-text)' }}>{otp.identifier}</span>\n {' · '}\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={otp.back}\n disabled={otp.isBusy}\n style={{ ...link, fontSize: 14 }}\n >\n Change\n </button>\n </p>\n ) : subtitle ? (\n <p\n style={{\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n margin: '8px 0 0',\n }}\n >\n {subtitle}\n </p>\n ) : null}\n\n {/* Errors and channel notices are announced, not just shown. */}\n <div role=\"status\" aria-live=\"polite\" id={statusId} style={{ marginTop: 32 }}>\n {otp.error ? (\n <div\n role=\"alert\"\n style={{\n ...notice,\n color: 'var(--sneek-danger)',\n borderColor: 'var(--sneek-danger)',\n }}\n >\n {otp.error}\n </div>\n ) : null}\n </div>\n\n {otp.step === 'identify' ? (\n <form\n onSubmit={onIdentifySubmit}\n style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 16 }}\n >\n <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>\n <label style={{ ...label, gap: 0 }} htmlFor={identifierId}>\n {identifierLabel ?? (mode === 'phone' ? 'Mobile number' : 'Email address')}\n </label>\n {identifierMode === 'both' ? (\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={() => switchMode(mode === 'phone' ? 'email' : 'phone')}\n disabled={otp.isBusy}\n style={{ ...link, fontSize: 13 }}\n >\n {mode === 'phone' ? 'Use email instead' : 'Use phone instead'}\n </button>\n ) : null}\n </div>\n\n {mode === 'phone' ? (\n <div\n className=\"sneek-otp-phone-field\"\n style={{\n display: 'flex',\n alignItems: 'stretch',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n transition: 'border-color 200ms var(--sneek-ease)',\n }}\n >\n <CountryPicker\n country={country}\n onSelect={onCountrySelect}\n disabled={otp.isBusy}\n />\n <span\n aria-hidden=\"true\"\n style={{\n width: 1,\n margin: '9px 0',\n background: 'var(--sneek-border)',\n }}\n />\n <input\n id={identifierId}\n type=\"tel\"\n inputMode=\"tel\"\n autoComplete=\"tel-national\"\n value={nationalNumber}\n onChange={(e) => onNationalNumberChange(e.target.value)}\n placeholder=\"Mobile number\"\n autoFocus\n required\n aria-describedby={statusId}\n style={{\n ...input,\n flex: 1,\n border: 'none',\n background: 'transparent',\n borderRadius: 0,\n }}\n />\n </div>\n ) : (\n <input\n id={identifierId}\n className=\"sneek-otp-input\"\n type=\"email\"\n value={otp.identifier}\n onChange={(e) => otp.setIdentifier(e.target.value)}\n placeholder={identifierPlaceholder ?? 'you@company.com'}\n autoComplete=\"email\"\n autoFocus\n required\n aria-describedby={statusId}\n style={input}\n />\n )}\n\n <button\n type=\"submit\"\n className=\"sneek-otp-button\"\n disabled={otp.isBusy}\n style={button}\n >\n {otp.isSending ? 'Sending code…' : 'Send code'}\n </button>\n </form>\n ) : (\n <form\n onSubmit={onVerifySubmit}\n style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 16 }}\n >\n <label style={{ ...label, marginBottom: -8 }} htmlFor={codeId}>\n {CODE_LENGTH}-digit code\n </label>\n {/*\n * One real input captures keystrokes — paste, backspace and\n * SMS/email autofill all keep working, which six separate\n * `<input>`s make surprisingly easy to break. It sits over\n * the visible cells, transparent; the cells below just\n * mirror its value.\n */}\n <div style={{ position: 'relative' }}>\n <input\n id={codeId}\n className=\"sneek-otp-code-input\"\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n autoComplete=\"one-time-code\"\n maxLength={CODE_LENGTH}\n value={otp.code}\n onChange={(e) =>\n otp.setCode(\n e.target.value.replace(/\\D/g, '').slice(0, CODE_LENGTH),\n )\n }\n onFocus={() => setCodeFocused(true)}\n onBlur={() => setCodeFocused(false)}\n autoFocus\n required\n aria-describedby={statusId}\n style={{\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n opacity: 0,\n caretColor: 'transparent',\n cursor: 'text',\n }}\n />\n <div\n className=\"sneek-otp-code-cells\"\n aria-hidden=\"true\"\n style={{ display: 'flex', gap: 10 }}\n >\n {Array.from({ length: CODE_LENGTH }).map((_, i) => {\n const digit = otp.code[i];\n const isActive = codeFocused && i === otp.code.length;\n return (\n <div\n key={i}\n data-active={isActive}\n style={{\n flex: 1,\n height: 44,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 22,\n color: 'var(--sneek-text)',\n borderBottom: `2px solid ${\n isActive ? 'var(--sneek-accent)' : 'var(--sneek-border)'\n }`,\n transition: 'border-color 200ms var(--sneek-ease)',\n }}\n >\n {digit ?? (isActive ? (\n <span\n className=\"sneek-otp-caret\"\n style={{\n width: 2,\n height: 22,\n background: 'var(--sneek-accent)',\n }}\n />\n ) : null)}\n </div>\n );\n })}\n </div>\n </div>\n <button\n type=\"submit\"\n className=\"sneek-otp-button\"\n disabled={otp.isBusy || otp.code.length < CODE_LENGTH}\n style={{\n ...button,\n opacity:\n otp.isBusy || otp.code.length < CODE_LENGTH ? 0.6 : 1,\n }}\n >\n {otp.isVerifying ? 'Verifying…' : 'Verify'}\n </button>\n <div style={{ textAlign: 'center' }}>\n {resendIn > 0 ? (\n <span\n style={{\n fontSize: 14,\n color: 'var(--sneek-text-muted)',\n }}\n >\n Resend code in {resendIn}s\n </span>\n ) : (\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={() => void otp.resend()}\n disabled={otp.isBusy}\n style={link}\n >\n Resend code\n </button>\n )}\n </div>\n </form>\n )}\n\n {showBranding ? (\n <p\n style={{\n margin: '32px 0 0',\n textAlign: 'center',\n fontSize: 12,\n lineHeight: '16px',\n color: 'var(--sneek-text-muted)',\n }}\n >\n Secured by{' '}\n <a\n href=\"https://sneek.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"sneek-otp-brand-link\"\n style={{\n display: 'inline-block',\n padding: '0 5px',\n borderRadius: 6,\n color: 'var(--sneek-accent)',\n fontWeight: 500,\n textDecoration: 'none',\n transition: 'box-shadow 200ms var(--sneek-ease)',\n }}\n >\n Sneek\n </a>\n </p>\n ) : null}\n </div>\n );\n}\n","import {\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n} from 'react';\n\nimport { COUNTRIES, flagEmoji, type Country } from './countries';\n\nfunction ChevronDown() {\n return (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M2 3.5 5 6.5 8 3.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\nexport interface CountryPickerProps {\n country: Country;\n onSelect: (country: Country) => void;\n disabled?: boolean;\n}\n\n/**\n * The flag + dial-code chip in front of the phone number field. Opens a\n * searchable list on click; the number field itself keeps auto-detecting\n * from pasted content independently of this — this is the manual path.\n */\nexport function CountryPicker({ country, onSelect, disabled }: CountryPickerProps) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const rootRef = useRef<HTMLDivElement>(null);\n const searchRef = useRef<HTMLInputElement>(null);\n const uid = useId();\n\n useEffect(() => {\n if (!open) return;\n searchRef.current?.focus();\n const onDocPointerDown = (event: MouseEvent) => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false);\n };\n document.addEventListener('mousedown', onDocPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onDocPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open]);\n\n const q = query.trim().toLowerCase();\n const filtered = q\n ? COUNTRIES.filter(\n (c) => c.name.toLowerCase().includes(q) || c.dial.includes(q.replace(/^\\+/, '')),\n )\n : COUNTRIES;\n\n const listId = `${uid}-country-list`;\n\n return (\n <div ref={rootRef} style={{ position: 'relative', flexShrink: 0 }}>\n <button\n type=\"button\"\n className=\"sneek-otp-country-chip\"\n onClick={() => setOpen((o) => !o)}\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n height: '100%',\n padding: '0 10px 0 14px',\n border: 'none',\n borderRadius: '12px 0 0 12px',\n background: 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 15,\n cursor: disabled ? 'not-allowed' : 'pointer',\n }}\n >\n <span style={{ fontSize: 18, lineHeight: 1 }}>{flagEmoji(country.iso2)}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>+{country.dial}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>\n <ChevronDown />\n </span>\n </button>\n\n {open ? (\n <div\n role=\"presentation\"\n style={{\n position: 'absolute',\n top: 'calc(100% + 6px)',\n left: 0,\n zIndex: 10,\n width: 260,\n maxWidth: '80vw',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface)',\n boxShadow: 'var(--sneek-shadow), 0 8px 24px rgb(0 0 0 / 0.12)',\n overflow: 'hidden',\n }}\n >\n <input\n ref={searchRef}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && filtered[0]) {\n onSelect(filtered[0]);\n setOpen(false);\n setQuery('');\n }\n }}\n placeholder=\"Search country or code\"\n aria-controls={listId}\n role=\"combobox\"\n aria-expanded={open}\n style={{\n width: '100%',\n padding: '10px 12px',\n border: 'none',\n borderBottom: '1px solid var(--sneek-border)',\n background: 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 14,\n outline: 'none',\n }}\n />\n <div\n id={listId}\n role=\"listbox\"\n style={{ maxHeight: 240, overflowY: 'auto', padding: 6 }}\n >\n {filtered.length === 0 ? (\n <p\n style={{\n padding: '8px 10px',\n fontSize: 13,\n color: 'var(--sneek-text-muted)',\n }}\n >\n No match.\n </p>\n ) : (\n filtered.map((c) => {\n const optionStyle: CSSProperties = {\n display: 'flex',\n width: '100%',\n alignItems: 'center',\n gap: 10,\n padding: '8px 10px',\n border: 'none',\n borderRadius: 8,\n background:\n c.iso2 === country.iso2\n ? 'var(--sneek-surface-2)'\n : 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 14,\n textAlign: 'left',\n cursor: 'pointer',\n };\n return (\n <button\n key={c.iso2}\n type=\"button\"\n role=\"option\"\n aria-selected={c.iso2 === country.iso2}\n onClick={() => {\n onSelect(c);\n setOpen(false);\n setQuery('');\n }}\n style={optionStyle}\n >\n <span style={{ fontSize: 17, lineHeight: 1 }}>\n {flagEmoji(c.iso2)}\n </span>\n <span style={{ flex: 1 }}>{c.name}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>\n +{c.dial}\n </span>\n </button>\n );\n })\n )}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * Country calling codes for the phone-mode chip in the identify step.\n *\n * Flags are computed from the ISO 3166-1 alpha-2 code (two regional-indicator\n * codepoints) rather than hand-typed emoji, so there is no chance of a flag\n * silently drifting from its country. Where a dial code is shared by several\n * territories (+1, +7, +44, +61...), the first entry is the one auto-detect\n * and the default resolve to — the largest or best-known user of that code.\n */\nexport interface Country {\n iso2: string;\n name: string;\n dial: string;\n}\n\nfunction flagFromIso2(iso2: string): string {\n const A = 0x1f1e6;\n const codePoints = [...iso2.toUpperCase()].map((c) => A + (c.charCodeAt(0) - 65));\n return String.fromCodePoint(...codePoints);\n}\n\n/** [iso2, name, dial code without '+'] — ordered so shared-code lookups hit the expected country first. */\nconst RAW: [string, string, string][] = [\n ['US', 'United States', '1'],\n ['CA', 'Canada', '1'],\n ['GB', 'United Kingdom', '44'],\n ['IN', 'India', '91'],\n ['AU', 'Australia', '61'],\n ['DE', 'Germany', '49'],\n ['FR', 'France', '33'],\n ['IT', 'Italy', '39'],\n ['ES', 'Spain', '34'],\n ['PT', 'Portugal', '351'],\n ['NL', 'Netherlands', '31'],\n ['BE', 'Belgium', '32'],\n ['CH', 'Switzerland', '41'],\n ['AT', 'Austria', '43'],\n ['SE', 'Sweden', '46'],\n ['NO', 'Norway', '47'],\n ['DK', 'Denmark', '45'],\n ['FI', 'Finland', '358'],\n ['IE', 'Ireland', '353'],\n ['IS', 'Iceland', '354'],\n ['PL', 'Poland', '48'],\n ['CZ', 'Czechia', '420'],\n ['SK', 'Slovakia', '421'],\n ['HU', 'Hungary', '36'],\n ['RO', 'Romania', '40'],\n ['BG', 'Bulgaria', '359'],\n ['GR', 'Greece', '30'],\n ['TR', 'Turkiye', '90'],\n ['RU', 'Russia', '7'],\n ['UA', 'Ukraine', '380'],\n ['BY', 'Belarus', '375'],\n ['LT', 'Lithuania', '370'],\n ['LV', 'Latvia', '371'],\n ['EE', 'Estonia', '372'],\n ['HR', 'Croatia', '385'],\n ['RS', 'Serbia', '381'],\n ['SI', 'Slovenia', '386'],\n ['CY', 'Cyprus', '357'],\n ['MT', 'Malta', '356'],\n ['LU', 'Luxembourg', '352'],\n ['CN', 'China', '86'],\n ['JP', 'Japan', '81'],\n ['KR', 'South Korea', '82'],\n ['HK', 'Hong Kong', '852'],\n ['TW', 'Taiwan', '886'],\n ['MO', 'Macau', '853'],\n ['SG', 'Singapore', '65'],\n ['MY', 'Malaysia', '60'],\n ['ID', 'Indonesia', '62'],\n ['TH', 'Thailand', '66'],\n ['VN', 'Vietnam', '84'],\n ['PH', 'Philippines', '63'],\n ['PK', 'Pakistan', '92'],\n ['BD', 'Bangladesh', '880'],\n ['LK', 'Sri Lanka', '94'],\n ['NP', 'Nepal', '977'],\n ['MM', 'Myanmar', '95'],\n ['KH', 'Cambodia', '855'],\n ['LA', 'Laos', '856'],\n ['MN', 'Mongolia', '976'],\n ['KZ', 'Kazakhstan', '7'],\n ['UZ', 'Uzbekistan', '998'],\n ['AE', 'United Arab Emirates', '971'],\n ['SA', 'Saudi Arabia', '966'],\n ['QA', 'Qatar', '974'],\n ['KW', 'Kuwait', '965'],\n ['BH', 'Bahrain', '973'],\n ['OM', 'Oman', '968'],\n ['JO', 'Jordan', '962'],\n ['LB', 'Lebanon', '961'],\n ['IL', 'Israel', '972'],\n ['IQ', 'Iraq', '964'],\n ['IR', 'Iran', '98'],\n ['EG', 'Egypt', '20'],\n ['ZA', 'South Africa', '27'],\n ['NG', 'Nigeria', '234'],\n ['KE', 'Kenya', '254'],\n ['GH', 'Ghana', '233'],\n ['ET', 'Ethiopia', '251'],\n ['TZ', 'Tanzania', '255'],\n ['UG', 'Uganda', '256'],\n ['MA', 'Morocco', '212'],\n ['DZ', 'Algeria', '213'],\n ['TN', 'Tunisia', '216'],\n ['BR', 'Brazil', '55'],\n ['MX', 'Mexico', '52'],\n ['AR', 'Argentina', '54'],\n ['CL', 'Chile', '56'],\n ['CO', 'Colombia', '57'],\n ['PE', 'Peru', '51'],\n ['VE', 'Venezuela', '58'],\n ['EC', 'Ecuador', '593'],\n ['UY', 'Uruguay', '598'],\n ['PY', 'Paraguay', '595'],\n ['BO', 'Bolivia', '591'],\n ['CR', 'Costa Rica', '506'],\n ['PA', 'Panama', '507'],\n ['DO', 'Dominican Republic', '1'],\n ['GT', 'Guatemala', '502'],\n ['NZ', 'New Zealand', '64'],\n ['FJ', 'Fiji', '679'],\n];\n\nexport const COUNTRIES: readonly Country[] = RAW.map(([iso2, name, dial]) => ({\n iso2,\n name,\n dial,\n}));\n\nexport const DEFAULT_COUNTRY_ISO2 = 'IN';\n\nexport function flagEmoji(iso2: string): string {\n return flagFromIso2(iso2);\n}\n\nexport function countryByIso2(iso2: string): Country | undefined {\n return COUNTRIES.find((c) => c.iso2 === iso2);\n}\n\n/**\n * Longest-dial-code-first match against a digit string (no '+'). Tries 3, 2,\n * then 1-digit prefixes so e.g. \"44\" resolves to the UK rather than being cut\n * short at a 1-digit code that happens to also exist.\n */\nexport function countryByDialPrefix(digits: string): Country | undefined {\n for (const len of [3, 2, 1]) {\n const prefix = digits.slice(0, len);\n if (prefix.length < len) continue;\n const match = COUNTRIES.find((c) => c.dial === prefix);\n if (match) return match;\n }\n return undefined;\n}\n\n/** Best-effort guess from the browser's locale region, e.g. \"en-GB\" -> GB. */\nexport function detectCountryFromLocale(): Country | undefined {\n if (typeof navigator === 'undefined') return undefined;\n const locales = navigator.languages ?? [navigator.language];\n for (const locale of locales) {\n const match = /-([A-Z]{2})$/.exec(locale ?? '');\n if (match) {\n const found = countryByIso2(match[1]);\n if (found) return found;\n }\n }\n return undefined;\n}\n","/**\n * Theme for the drop-in login card.\n *\n * The package ships zero dependencies and no stylesheet, so the tokens are\n * injected once as CSS custom properties scoped to `.sneek-otp`. That buys two\n * things inline styles cannot: a `prefers-color-scheme` media query, and real\n * `:focus-visible` / `:hover` states.\n *\n * Light and dark are authored independently rather than one being an inversion\n * of the other. In dark, the page-to-card lightness delta carries depth and the\n * card needs no shadow; in light both are near-white, so the card takes a\n * visible border and a real shadow.\n */\nexport const SNEEK_STYLE_ID = 'sneek-otp-styles';\n\n/** Brand orange. The single accent — nothing else on the card is coloured. */\nexport const SNEEK_ACCENT_DARK = '#f86513';\n/** Darkened for light mode so it clears WCAG AA as text and as a button fill. */\nexport const SNEEK_ACCENT_LIGHT = '#b83f06';\n\nexport function buildStyles(accent?: string): string {\n const darkAccent = accent ?? SNEEK_ACCENT_DARK;\n const lightAccent = accent ?? SNEEK_ACCENT_LIGHT;\n\n const light = `\n --sneek-surface: #ffffff;\n --sneek-surface-2: #f4f1ed;\n --sneek-border: #e3ddd5;\n --sneek-text: #1c1917;\n --sneek-text-muted: #57534e;\n --sneek-accent: ${lightAccent};\n --sneek-accent-soft: color-mix(in srgb, ${lightAccent} 12%, transparent);\n --sneek-accent-shadow: color-mix(in srgb, ${lightAccent} 45%, transparent);\n --sneek-accent-contrast: #ffffff;\n --sneek-danger: #b0242a;\n --sneek-shadow: 0 3px 3px -2px rgb(0 0 0 / 0.10), 0 3px 4px rgb(0 0 0 / 0.07),\n 0 1px 8px rgb(0 0 0 / 0.06);`;\n\n const dark = `\n --sneek-surface: #17150f;\n --sneek-surface-2: #201d16;\n --sneek-border: rgba(255, 255, 255, 0.08);\n --sneek-text: #faf8f6;\n --sneek-text-muted: #a8a29b;\n --sneek-accent: ${darkAccent};\n --sneek-accent-soft: color-mix(in srgb, ${darkAccent} 16%, transparent);\n --sneek-accent-shadow: color-mix(in srgb, ${darkAccent} 55%, transparent);\n --sneek-accent-contrast: #1a0d04;\n --sneek-danger: #d43a3c;\n --sneek-shadow: none;`;\n\n return `\n.sneek-otp {${light}\n --sneek-ease: cubic-bezier(0, 0, 0.2, 1);\n}\n@media (prefers-color-scheme: dark) {\n .sneek-otp:not([data-theme=\"light\"]) {${dark}\n }\n}\n.sneek-otp[data-theme=\"dark\"] {${dark}\n}\n.sneek-otp[data-theme=\"light\"] {${light}\n}\n.sneek-otp *, .sneek-otp *::before, .sneek-otp *::after { box-sizing: border-box; }\n.sneek-otp-input:focus-visible,\n.sneek-otp-button:focus-visible,\n.sneek-otp-link:focus-visible,\n.sneek-otp-country-chip:focus-visible,\n.sneek-otp-brand-link:focus-visible {\n outline: 2px solid var(--sneek-accent);\n outline-offset: 2px;\n}\n.sneek-otp-input:focus {\n border-color: var(--sneek-accent);\n}\n.sneek-otp-phone-field:focus-within {\n border-color: var(--sneek-accent);\n}\n.sneek-otp-button:not(:disabled):hover {\n filter: brightness(1.08);\n}\n.sneek-otp-link:not(:disabled):hover {\n text-decoration: underline;\n}\n.sneek-otp-country-chip:not(:disabled):hover {\n filter: brightness(1.08);\n}\n.sneek-otp-brand-link {\n box-shadow: 0 1px 6px var(--sneek-accent-shadow);\n}\n.sneek-otp-brand-link:hover {\n box-shadow: 0 2px 10px var(--sneek-accent-shadow);\n}\n@media (prefers-reduced-motion: reduce) {\n .sneek-otp * { transition-duration: 0.01ms !important; }\n}\n@keyframes sneek-otp-caret {\n 0%, 45% { opacity: 1; }\n 50%, 100% { opacity: 0; }\n}\n.sneek-otp-caret {\n animation: sneek-otp-caret 1s step-end infinite;\n}\n`;\n}\n","import type { RequestOtpResult } from './state';\n\nexport interface FetchHandlerOptions {\n /**\n * Partner backend endpoint that sends an OTP. Receives `{ identifier }`,\n * must return `{ requestId, channels?, expiresInSeconds? }`.\n * @default '/api/auth/request-otp'\n */\n requestUrl?: string;\n /**\n * Partner backend endpoint that verifies an OTP. Receives\n * `{ requestId, code }`, returns whatever your app needs (session, token…).\n * @default '/api/auth/verify-otp'\n */\n verifyUrl?: string;\n /** Extra headers (e.g. CSRF token) to send on both requests. */\n headers?: Record<string, string>;\n /** Forwarded to fetch — set to 'include' if you use cookie sessions. */\n credentials?: RequestCredentials;\n}\n\nasync function postJson<T>(\n url: string,\n body: unknown,\n options: FetchHandlerOptions,\n): Promise<T> {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(options.headers ?? {}) },\n credentials: options.credentials,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n let message = `Request failed (${response.status})`;\n try {\n const data = (await response.json()) as { message?: string; error?: string };\n message = data.message || data.error || message;\n } catch {\n // non-JSON error body — keep the status-based message\n }\n throw new Error(message);\n }\n\n return (await response.json()) as T;\n}\n\n/**\n * Build {@link SneekOtpHandlers} that POST to your own backend endpoints.\n * Those endpoints call the Sneek API server-side with your secret key.\n */\nexport function createFetchHandlers<TResult = unknown>(\n options: FetchHandlerOptions = {},\n): {\n requestOtp: (identifier: string) => Promise<RequestOtpResult>;\n verifyOtp: (input: { requestId: string; code: string }) => Promise<TResult>;\n} {\n const requestUrl = options.requestUrl ?? '/api/auth/request-otp';\n const verifyUrl = options.verifyUrl ?? '/api/auth/verify-otp';\n\n return {\n requestOtp: (identifier: string) =>\n postJson<RequestOtpResult>(requestUrl, { identifier }, options),\n verifyOtp: (input: { requestId: string; code: string }) =>\n postJson<TResult>(verifyUrl, input, options),\n };\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/use-sneek-otp.ts","../src/state.ts","../src/component.tsx","../src/country-picker.tsx","../src/countries.ts","../src/theme.ts","../src/fetch-handlers.ts"],"sourcesContent":["export {\n useSneekOtp,\n type SneekOtpHandlers,\n type UseSneekOtp,\n} from './use-sneek-otp';\n\nexport {\n SneekOtpLogin,\n type SneekOtpLoginProps,\n type SneekTheme,\n type SneekIdentifierMode,\n} from './component';\n\nexport {\n SNEEK_ACCENT_DARK,\n SNEEK_ACCENT_LIGHT,\n} from './theme';\n\nexport {\n COUNTRIES,\n DEFAULT_COUNTRY_ISO2,\n flagEmoji,\n countryByIso2,\n countryByDialPrefix,\n detectCountryFromLocale,\n type Country,\n} from './countries';\n\nexport {\n createFetchHandlers,\n type FetchHandlerOptions,\n} from './fetch-handlers';\n\nexport {\n otpReducer,\n initialOtpState,\n formatChannels,\n type SneekChannel,\n type SneekOtpStep,\n type SneekOtpStatus,\n type SneekOtpState,\n type SneekOtpAction,\n type RequestOtpResult,\n} from './state';\n","import { useCallback, useReducer } from 'react';\nimport {\n initialOtpState,\n otpReducer,\n toMessage,\n type RequestOtpResult,\n type SneekOtpState,\n} from './state';\n\n/**\n * Partner-supplied transport. These call the *partner's own backend*, which in\n * turn talks to the Sneek API with the secret server-side key. The browser\n * never sees a Sneek API key — that is the whole security model of this package.\n */\nexport interface SneekOtpHandlers<TResult = unknown> {\n /** Ask the partner backend to send an OTP to `identifier`. */\n requestOtp: (identifier: string) => Promise<RequestOtpResult>;\n /** Verify the code with the partner backend; resolve with the auth result. */\n verifyOtp: (input: { requestId: string; code: string }) => Promise<TResult>;\n /** Called after a successful verification with the partner's result. */\n onSuccess?: (result: TResult) => void;\n /** Called on any error (request or verify). */\n onError?: (error: unknown) => void;\n}\n\nexport interface UseSneekOtp extends SneekOtpState {\n setIdentifier: (value: string) => void;\n setCode: (value: string) => void;\n /** Submit the identify step — triggers `requestOtp`. */\n sendOtp: () => Promise<void>;\n /** Submit the verify step — triggers `verifyOtp`. */\n verify: () => Promise<void>;\n /** Go back to the identify screen (e.g. \"use a different email\"). */\n back: () => void;\n /** Re-send the OTP to the same identifier. */\n resend: () => Promise<void>;\n /** Convenience booleans. */\n isSending: boolean;\n isVerifying: boolean;\n isBusy: boolean;\n}\n\nconst DEFAULT_REQUEST_ERROR = 'Could not send the code. Please try again.';\nconst DEFAULT_VERIFY_ERROR = 'That code was not correct. Please try again.';\n\n/**\n * Headless hook implementing the passwordless OTP login flow. Bring your own\n * markup, or use the {@link SneekOtpLogin} component for a styled default.\n */\nexport function useSneekOtp<TResult = unknown>(\n handlers: SneekOtpHandlers<TResult>,\n): UseSneekOtp {\n const [state, dispatch] = useReducer(otpReducer, initialOtpState);\n\n const { requestOtp, verifyOtp, onSuccess, onError } = handlers;\n\n const setIdentifier = useCallback((value: string) => {\n dispatch({ type: 'set_identifier', value });\n }, []);\n\n const setCode = useCallback((value: string) => {\n dispatch({ type: 'set_code', value });\n }, []);\n\n const runRequest = useCallback(\n async (identifier: string) => {\n const trimmed = identifier.trim();\n if (!trimmed) {\n dispatch({ type: 'request_error', message: 'Enter your email or mobile number.' });\n return;\n }\n dispatch({ type: 'request_start' });\n try {\n const result = await requestOtp(trimmed);\n dispatch({ type: 'request_success', result });\n } catch (error) {\n dispatch({ type: 'request_error', message: toMessage(error, DEFAULT_REQUEST_ERROR) });\n onError?.(error);\n }\n },\n [requestOtp, onError],\n );\n\n const sendOtp = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);\n\n const resend = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);\n\n const verify = useCallback(async () => {\n const code = state.code.trim();\n if (!code) {\n dispatch({ type: 'verify_error', message: 'Enter the code you received.' });\n return;\n }\n dispatch({ type: 'verify_start' });\n try {\n const result = await verifyOtp({ requestId: state.requestId, code });\n onSuccess?.(result);\n } catch (error) {\n dispatch({ type: 'verify_error', message: toMessage(error, DEFAULT_VERIFY_ERROR) });\n onError?.(error);\n }\n }, [verifyOtp, state.code, state.requestId, onSuccess, onError]);\n\n const back = useCallback(() => {\n dispatch({ type: 'back_to_identify' });\n }, []);\n\n return {\n ...state,\n setIdentifier,\n setCode,\n sendOtp,\n verify,\n back,\n resend,\n isSending: state.status === 'sending',\n isVerifying: state.status === 'verifying',\n isBusy: state.status !== 'idle',\n };\n}\n","/**\n * Framework-agnostic state machine for the Sneek passwordless OTP flow.\n *\n * Kept free of React so it can be unit-tested in isolation and reused by other\n * front-end bindings later (Vue/Svelte). The hook in `use-sneek-otp.ts` is a\n * thin wrapper around this reducer.\n */\n\nexport type SneekChannel = 'sms' | 'whatsapp' | 'email';\n\n/** Which screen of the two-step flow is showing. */\nexport type SneekOtpStep = 'identify' | 'verify';\n\n/** Async lifecycle for the in-flight request. */\nexport type SneekOtpStatus = 'idle' | 'sending' | 'verifying';\n\nexport interface SneekOtpState {\n step: SneekOtpStep;\n status: SneekOtpStatus;\n /** The email / mobile / username the user typed. */\n identifier: string;\n /** The OTP code the user typed on the verify screen. */\n code: string;\n /** Opaque id returned by the partner backend, replayed on verify. */\n requestId: string;\n /** Channels the OTP was actually delivered over. */\n channels: SneekChannel[];\n /** Seconds until the OTP expires (from the request response). */\n expiresInSeconds: number;\n /** User-facing error message, or null. */\n error: string | null;\n}\n\nexport const initialOtpState: SneekOtpState = {\n step: 'identify',\n status: 'idle',\n identifier: '',\n code: '',\n requestId: '',\n channels: [],\n expiresInSeconds: 0,\n error: null,\n};\n\nexport interface RequestOtpResult {\n requestId: string;\n channels?: SneekChannel[];\n expiresInSeconds?: number;\n}\n\nexport type SneekOtpAction =\n | { type: 'set_identifier'; value: string }\n | { type: 'set_code'; value: string }\n | { type: 'request_start' }\n | { type: 'request_success'; result: RequestOtpResult }\n | { type: 'request_error'; message: string }\n | { type: 'verify_start' }\n | { type: 'verify_error'; message: string }\n | { type: 'reset' }\n | { type: 'back_to_identify' };\n\nconst isBusy = (status: SneekOtpStatus): boolean => status !== 'idle';\n\nexport function otpReducer(\n state: SneekOtpState,\n action: SneekOtpAction,\n): SneekOtpState {\n switch (action.type) {\n case 'set_identifier':\n return { ...state, identifier: action.value, error: null };\n\n case 'set_code':\n return { ...state, code: action.value, error: null };\n\n case 'request_start':\n // Guard against double submits while a request is already in flight.\n if (isBusy(state.status)) return state;\n return { ...state, status: 'sending', error: null };\n\n case 'request_success':\n return {\n ...state,\n step: 'verify',\n status: 'idle',\n code: '',\n requestId: action.result.requestId,\n channels: action.result.channels ?? [],\n expiresInSeconds: action.result.expiresInSeconds ?? 0,\n error: null,\n };\n\n case 'request_error':\n return { ...state, status: 'idle', error: action.message };\n\n case 'verify_start':\n if (isBusy(state.status)) return state;\n return { ...state, status: 'verifying', error: null };\n\n case 'verify_error':\n return { ...state, status: 'idle', error: action.message };\n\n case 'back_to_identify':\n return {\n ...state,\n step: 'identify',\n status: 'idle',\n code: '',\n requestId: '',\n channels: [],\n expiresInSeconds: 0,\n error: null,\n };\n\n case 'reset':\n return { ...initialOtpState };\n\n default:\n return state;\n }\n}\n\nconst CHANNEL_LABELS: Record<SneekChannel, string> = {\n sms: 'SMS',\n whatsapp: 'WhatsApp',\n email: 'email',\n};\n\n/** \"SMS, WhatsApp\" — human label for the channels an OTP was sent over. */\nexport function formatChannels(channels: SneekChannel[]): string {\n return channels.map((c) => CHANNEL_LABELS[c] ?? c).join(', ');\n}\n\n/** Normalize any thrown value into a user-facing message. */\nexport function toMessage(error: unknown, fallback: string): string {\n if (error instanceof Error && error.message) return error.message;\n if (typeof error === 'string' && error) return error;\n return fallback;\n}\n","import {\n useEffect,\n useId,\n useState,\n type CSSProperties,\n type FormEvent,\n type ReactNode,\n} from 'react';\n\nimport { CountryPicker } from './country-picker';\nimport {\n countryByDialPrefix,\n countryByIso2,\n DEFAULT_COUNTRY_ISO2,\n type Country,\n} from './countries';\nimport { buildStyles, SNEEK_STYLE_ID } from './theme';\nimport { useSneekOtp, type SneekOtpHandlers } from './use-sneek-otp';\n\nexport type SneekTheme = 'auto' | 'light' | 'dark';\nexport type SneekIdentifierMode = 'phone' | 'email' | 'both';\n\n/** Digits in a Sneek code. */\nconst CODE_LENGTH = 6;\n/** Seconds before \"Resend code\" becomes tappable again. */\nconst RESEND_SECONDS = 30;\n/** E.164 allows 15 digits total; this is the remainder after a 3-digit dial code. */\nconst MAX_NATIONAL_DIGITS = 12;\n\nexport interface SneekOtpLoginProps<TResult = unknown>\n extends SneekOtpHandlers<TResult> {\n /** Heading above the form. @default 'Sign in' */\n title?: string;\n /** Heading once the code has been sent. @default 'Enter the code' */\n verifyTitle?: string;\n /** Sub-heading. Pass `null` to remove it. */\n subtitle?: ReactNode;\n /**\n * Which identifiers a visitor can sign in with. `'both'` starts on phone\n * with a country chip and offers a link to switch to email.\n * @default 'both'\n */\n identifierMode?: SneekIdentifierMode;\n /**\n * ISO 3166-1 alpha-2 country to preselect for the phone chip.\n * @default 'IN' (India)\n */\n defaultCountry?: string;\n /** Overrides the auto label (\"Mobile number\" / \"Email address\"). */\n identifierLabel?: string;\n /** Overrides the auto placeholder. Only used in email mode. */\n identifierPlaceholder?: string;\n /**\n * Colour scheme. `auto` follows the visitor's system setting.\n * @default 'auto'\n */\n theme?: SneekTheme;\n /**\n * Override the single accent colour. Leave unset to use Sneek orange,\n * which is tuned per mode for contrast.\n */\n accentColor?: string;\n /**\n * Replaces the Sneek mark above the title (which sits in a rounded,\n * bordered box by default). Pass `null` to remove it entirely.\n */\n logo?: ReactNode;\n /** Show the \"Secured by Sneek\" line under the form. @default true */\n showBranding?: boolean;\n /** Style overrides for the outer card. */\n style?: CSSProperties;\n /** Extra class on the outer card. */\n className?: string;\n}\n\n/**\n * Sneek mark: two triangles offset on a diagonal — one pointing up on the\n * right, one pointing down on the left. Traced from the brand asset so the\n * package needs no image file and no CDN.\n */\nfunction SneekMark() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 32 32\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Sneek\"\n >\n <path d=\"M21.3 1 29.3 16H13.3L21.3 1Z\" fill=\"var(--sneek-accent)\" />\n <path d=\"M2.7 17.5H18.7L10.7 31 2.7 17.5Z\" fill=\"var(--sneek-accent)\" />\n </svg>\n );\n}\n\n/**\n * The default mark sits in a rounded, bordered box — matching how the mark\n * is framed everywhere else in the product (app icon, dashboard nav) — rather\n * than floating bare on the card.\n */\nfunction SneekMarkBox() {\n return (\n <div\n style={{\n display: 'grid',\n placeItems: 'center',\n width: 44,\n height: 44,\n borderRadius: 16,\n border: '1px solid var(--sneek-border)',\n background: 'var(--sneek-surface)',\n }}\n >\n <SneekMark />\n </div>\n );\n}\n\n/**\n * Drop-in passwordless login card.\n *\n * The component never receives a Sneek API key — it calls the handlers you\n * supply, which talk to your own backend. See `createFetchHandlers` for the\n * common case.\n *\n * @example\n * ```tsx\n * <SneekOtpLogin\n * {...createFetchHandlers({ baseUrl: '/api/auth' })}\n * onSuccess={(session) => router.push('/app')}\n * />\n * ```\n */\nexport function SneekOtpLogin<TResult = unknown>(\n props: SneekOtpLoginProps<TResult>,\n): ReactNode {\n const {\n title = 'Sign in',\n verifyTitle = 'Enter the code',\n subtitle = 'Enter your email or phone. We will send you a code.',\n identifierMode = 'both',\n defaultCountry,\n identifierLabel,\n identifierPlaceholder,\n theme = 'auto',\n accentColor,\n logo,\n showBranding = true,\n style,\n className,\n ...handlers\n } = props;\n\n const otp = useSneekOtp<TResult>(handlers);\n const uid = useId();\n // Countdown before resend re-enables. Instant resend is both poor feedback\n // and an easy way to burn someone's SMS quota.\n const [resendIn, setResendIn] = useState(0);\n const [codeFocused, setCodeFocused] = useState(false);\n const [mode, setMode] = useState<'phone' | 'email'>(\n identifierMode === 'email' ? 'email' : 'phone',\n );\n const [country, setCountry] = useState<Country>(\n () => (defaultCountry && countryByIso2(defaultCountry)) || countryByIso2(DEFAULT_COUNTRY_ISO2)!,\n );\n // The digits typed into the phone field, separate from `otp.identifier`\n // (which holds the composed +<dial><digits> value actually submitted).\n const [nationalNumber, setNationalNumber] = useState('');\n const identifierId = `${uid}-identifier`;\n const codeId = `${uid}-code`;\n const statusId = `${uid}-status`;\n\n const onCountrySelect = (next: Country) => {\n setCountry(next);\n otp.setIdentifier(`+${next.dial}${nationalNumber}`);\n };\n\n const onNationalNumberChange = (raw: string) => {\n let digits = raw.replace(/\\D/g, '').slice(0, MAX_NATIONAL_DIGITS + 3);\n let effectiveCountry = country;\n // Only re-detect off an explicit leading '+' — a real, unambiguous\n // signal that this is a full international number. A plain jump in\n // digit count (paste, or a phone-autofill suggestion) is NOT enough:\n // most 10-digit local numbers coincidentally start with digits that\n // match *some* country's dial code, which would otherwise silently\n // truncate a legitimate local number.\n if (raw.trim().startsWith('+')) {\n const guess = countryByDialPrefix(digits);\n if (guess && digits.startsWith(guess.dial)) {\n effectiveCountry = guess;\n digits = digits.slice(guess.dial.length);\n }\n }\n digits = digits.slice(0, MAX_NATIONAL_DIGITS);\n if (effectiveCountry !== country) setCountry(effectiveCountry);\n setNationalNumber(digits);\n otp.setIdentifier(`+${effectiveCountry.dial}${digits}`);\n };\n\n const switchMode = (next: 'phone' | 'email') => {\n setMode(next);\n setNationalNumber('');\n otp.setIdentifier('');\n };\n\n // One <style> element for the whole page, regardless of how many cards\n // render. Injected on mount so the package stays SSR-safe.\n useEffect(() => {\n if (typeof document === 'undefined') return;\n let el = document.getElementById(SNEEK_STYLE_ID);\n if (!el) {\n el = document.createElement('style');\n el.id = SNEEK_STYLE_ID;\n document.head.appendChild(el);\n }\n el.textContent = buildStyles(accentColor);\n }, [accentColor]);\n\n const onIdentifySubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void otp.sendOtp();\n };\n\n const onVerifySubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void otp.verify();\n };\n\n // Start the cooldown whenever a code goes out.\n useEffect(() => {\n if (otp.step === 'verify') setResendIn(RESEND_SECONDS);\n }, [otp.step]);\n\n useEffect(() => {\n if (resendIn <= 0) return;\n const timer = setTimeout(() => setResendIn((n) => n - 1), 1000);\n return () => clearTimeout(timer);\n }, [resendIn]);\n\n // Submit as soon as the code looks complete — nobody should have to reach\n // for a button after typing the last digit.\n useEffect(() => {\n if (otp.step === 'verify' && otp.code.length === CODE_LENGTH && !otp.isBusy) {\n void otp.verify();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [otp.code, otp.step]);\n\n const label: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n };\n\n const input: CSSProperties = {\n padding: '12px 14px',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n color: 'var(--sneek-text)',\n fontSize: 15,\n width: '100%',\n outline: 'none',\n transition: 'border-color 200ms var(--sneek-ease)',\n };\n\n const button: CSSProperties = {\n padding: '12px 18px',\n border: 'none',\n borderRadius: 9999,\n background: 'var(--sneek-accent)',\n color: 'var(--sneek-accent-contrast)',\n fontSize: 15,\n fontWeight: 500,\n cursor: otp.isBusy ? 'not-allowed' : 'pointer',\n opacity: otp.isBusy ? 0.6 : 1,\n width: '100%',\n transition: 'filter 200ms var(--sneek-ease), opacity 200ms var(--sneek-ease)',\n };\n\n const link: CSSProperties = {\n border: 'none',\n background: 'transparent',\n color: 'var(--sneek-accent)',\n cursor: otp.isBusy ? 'not-allowed' : 'pointer',\n font: 'inherit',\n fontSize: 14,\n padding: 0,\n };\n\n const notice: CSSProperties = {\n padding: '10px 12px',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n border: '1px solid var(--sneek-border)',\n fontSize: 14,\n color: 'var(--sneek-text-muted)',\n };\n\n return (\n <div\n className={className ? `sneek-otp ${className}` : 'sneek-otp'}\n data-theme={theme === 'auto' ? undefined : theme}\n style={{\n maxWidth: 400,\n margin: '0 auto',\n padding: 24,\n border: '1px solid var(--sneek-border)',\n borderRadius: 16,\n background: 'var(--sneek-surface)',\n boxShadow: 'var(--sneek-shadow)',\n color: 'var(--sneek-text)',\n fontFamily:\n 'Inter, ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n lineHeight: 1.5,\n ...style,\n }}\n >\n {logo === null ? null : (logo ?? <SneekMarkBox />)}\n <h2\n style={{\n fontSize: 21,\n lineHeight: '28px',\n fontWeight: 500,\n letterSpacing: '-0.01em',\n margin: '16px 0 0',\n }}\n >\n {otp.step === 'verify' ? verifyTitle : title}\n </h2>\n {otp.step === 'verify' ? (\n <p\n style={{\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n margin: '8px 0 0',\n }}\n >\n Sent to{' '}\n <span style={{ color: 'var(--sneek-text)' }}>{otp.identifier}</span>\n {' · '}\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={otp.back}\n disabled={otp.isBusy}\n style={{ ...link, fontSize: 14 }}\n >\n Change\n </button>\n </p>\n ) : subtitle ? (\n <p\n style={{\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n margin: '8px 0 0',\n }}\n >\n {subtitle}\n </p>\n ) : null}\n\n {/* Errors and channel notices are announced, not just shown. */}\n <div role=\"status\" aria-live=\"polite\" id={statusId} style={{ marginTop: 32 }}>\n {otp.error ? (\n <div\n role=\"alert\"\n style={{\n ...notice,\n color: 'var(--sneek-danger)',\n borderColor: 'var(--sneek-danger)',\n }}\n >\n {otp.error}\n </div>\n ) : null}\n </div>\n\n {otp.step === 'identify' ? (\n <form\n onSubmit={onIdentifySubmit}\n style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 16 }}\n >\n <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>\n <label style={{ ...label, gap: 0 }} htmlFor={identifierId}>\n {identifierLabel ?? (mode === 'phone' ? 'Mobile number' : 'Email address')}\n </label>\n {identifierMode === 'both' ? (\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={() => switchMode(mode === 'phone' ? 'email' : 'phone')}\n disabled={otp.isBusy}\n style={{ ...link, fontSize: 13 }}\n >\n {mode === 'phone' ? 'Use email instead' : 'Use phone instead'}\n </button>\n ) : null}\n </div>\n\n {mode === 'phone' ? (\n <div\n className=\"sneek-otp-phone-field\"\n style={{\n display: 'flex',\n alignItems: 'stretch',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n transition: 'border-color 200ms var(--sneek-ease)',\n }}\n >\n <CountryPicker\n country={country}\n onSelect={onCountrySelect}\n disabled={otp.isBusy}\n />\n <span\n aria-hidden=\"true\"\n style={{\n width: 1,\n margin: '9px 0',\n background: 'var(--sneek-border)',\n }}\n />\n <input\n id={identifierId}\n type=\"tel\"\n inputMode=\"tel\"\n autoComplete=\"tel-national\"\n value={nationalNumber}\n onChange={(e) => onNationalNumberChange(e.target.value)}\n placeholder=\"Mobile number\"\n autoFocus\n required\n aria-describedby={statusId}\n style={{\n ...input,\n flex: 1,\n border: 'none',\n background: 'transparent',\n borderRadius: 0,\n }}\n />\n </div>\n ) : (\n <input\n id={identifierId}\n className=\"sneek-otp-input\"\n type=\"email\"\n value={otp.identifier}\n onChange={(e) => otp.setIdentifier(e.target.value)}\n placeholder={identifierPlaceholder ?? 'you@company.com'}\n autoComplete=\"email\"\n autoFocus\n required\n aria-describedby={statusId}\n style={input}\n />\n )}\n\n <button\n type=\"submit\"\n className=\"sneek-otp-button\"\n disabled={otp.isBusy}\n style={button}\n >\n {otp.isSending ? 'Sending code…' : 'Send code'}\n </button>\n </form>\n ) : (\n <form\n onSubmit={onVerifySubmit}\n style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 16 }}\n >\n <label style={{ ...label, marginBottom: -8 }} htmlFor={codeId}>\n {CODE_LENGTH}-digit code\n </label>\n {/*\n * One real input captures keystrokes — paste, backspace and\n * SMS/email autofill all keep working, which six separate\n * `<input>`s make surprisingly easy to break. It sits over\n * the visible cells, transparent; the cells below just\n * mirror its value.\n */}\n <div style={{ position: 'relative' }}>\n <input\n id={codeId}\n className=\"sneek-otp-code-input\"\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n autoComplete=\"one-time-code\"\n maxLength={CODE_LENGTH}\n value={otp.code}\n onChange={(e) =>\n otp.setCode(\n e.target.value.replace(/\\D/g, '').slice(0, CODE_LENGTH),\n )\n }\n onFocus={() => setCodeFocused(true)}\n onBlur={() => setCodeFocused(false)}\n autoFocus\n required\n aria-describedby={statusId}\n style={{\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n opacity: 0,\n caretColor: 'transparent',\n cursor: 'text',\n }}\n />\n <div\n className=\"sneek-otp-code-cells\"\n aria-hidden=\"true\"\n style={{ display: 'flex', gap: 10 }}\n >\n {Array.from({ length: CODE_LENGTH }).map((_, i) => {\n const digit = otp.code[i];\n const isActive = codeFocused && i === otp.code.length;\n return (\n <div\n key={i}\n data-active={isActive}\n style={{\n flex: 1,\n height: 44,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 22,\n color: 'var(--sneek-text)',\n borderBottom: `2px solid ${\n isActive ? 'var(--sneek-accent)' : 'var(--sneek-border)'\n }`,\n transition: 'border-color 200ms var(--sneek-ease)',\n }}\n >\n {digit ?? (isActive ? (\n <span\n className=\"sneek-otp-caret\"\n style={{\n width: 2,\n height: 22,\n background: 'var(--sneek-accent)',\n }}\n />\n ) : null)}\n </div>\n );\n })}\n </div>\n </div>\n <button\n type=\"submit\"\n className=\"sneek-otp-button\"\n disabled={otp.isBusy || otp.code.length < CODE_LENGTH}\n style={{\n ...button,\n opacity:\n otp.isBusy || otp.code.length < CODE_LENGTH ? 0.6 : 1,\n }}\n >\n {otp.isVerifying ? 'Verifying…' : 'Verify'}\n </button>\n <div style={{ textAlign: 'center' }}>\n {resendIn > 0 ? (\n <span\n style={{\n fontSize: 14,\n color: 'var(--sneek-text-muted)',\n }}\n >\n Resend code in {resendIn}s\n </span>\n ) : (\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={() => void otp.resend()}\n disabled={otp.isBusy}\n style={link}\n >\n Resend code\n </button>\n )}\n </div>\n </form>\n )}\n\n {showBranding ? (\n <p\n style={{\n margin: '32px 0 0',\n textAlign: 'center',\n fontSize: 12,\n lineHeight: '16px',\n color: 'var(--sneek-text-muted)',\n }}\n >\n Secured by{' '}\n <a\n href=\"https://sneek.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"sneek-otp-brand-link\"\n style={{\n display: 'inline-block',\n padding: '0 5px',\n borderRadius: 6,\n color: 'var(--sneek-accent)',\n fontWeight: 500,\n textDecoration: 'none',\n transition: 'box-shadow 200ms var(--sneek-ease)',\n }}\n >\n Sneek\n </a>\n </p>\n ) : null}\n </div>\n );\n}\n","import {\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n} from 'react';\n\nimport { COUNTRIES, flagEmoji, type Country } from './countries';\n\nfunction ChevronDown() {\n return (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M2 3.5 5 6.5 8 3.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\nexport interface CountryPickerProps {\n country: Country;\n onSelect: (country: Country) => void;\n disabled?: boolean;\n}\n\n/**\n * The flag + dial-code chip in front of the phone number field. Opens a\n * searchable list on click; the number field itself keeps auto-detecting\n * from pasted content independently of this — this is the manual path.\n */\nexport function CountryPicker({ country, onSelect, disabled }: CountryPickerProps) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const rootRef = useRef<HTMLDivElement>(null);\n const searchRef = useRef<HTMLInputElement>(null);\n const uid = useId();\n\n useEffect(() => {\n if (!open) return;\n searchRef.current?.focus();\n const onDocPointerDown = (event: MouseEvent) => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false);\n };\n document.addEventListener('mousedown', onDocPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onDocPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open]);\n\n const q = query.trim().toLowerCase();\n const filtered = q\n ? COUNTRIES.filter(\n (c) => c.name.toLowerCase().includes(q) || c.dial.includes(q.replace(/^\\+/, '')),\n )\n : COUNTRIES;\n\n const listId = `${uid}-country-list`;\n\n return (\n <div ref={rootRef} style={{ position: 'relative', flexShrink: 0 }}>\n <button\n type=\"button\"\n className=\"sneek-otp-country-chip\"\n onClick={() => setOpen((o) => !o)}\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n height: '100%',\n padding: '0 10px 0 14px',\n border: 'none',\n borderRadius: '12px 0 0 12px',\n background: 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 15,\n cursor: disabled ? 'not-allowed' : 'pointer',\n }}\n >\n <span style={{ fontSize: 18, lineHeight: 1 }}>{flagEmoji(country.iso2)}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>+{country.dial}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>\n <ChevronDown />\n </span>\n </button>\n\n {open ? (\n <div\n role=\"presentation\"\n style={{\n position: 'absolute',\n top: 'calc(100% + 6px)',\n left: 0,\n zIndex: 10,\n width: 260,\n maxWidth: '80vw',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface)',\n boxShadow: 'var(--sneek-shadow), 0 8px 24px rgb(0 0 0 / 0.12)',\n overflow: 'hidden',\n }}\n >\n <input\n ref={searchRef}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && filtered[0]) {\n onSelect(filtered[0]);\n setOpen(false);\n setQuery('');\n }\n }}\n placeholder=\"Search country or code\"\n aria-controls={listId}\n role=\"combobox\"\n aria-expanded={open}\n style={{\n width: '100%',\n padding: '10px 12px',\n border: 'none',\n borderBottom: '1px solid var(--sneek-border)',\n background: 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 14,\n outline: 'none',\n }}\n />\n <div\n id={listId}\n role=\"listbox\"\n style={{ maxHeight: 240, overflowY: 'auto', padding: 6 }}\n >\n {filtered.length === 0 ? (\n <p\n style={{\n padding: '8px 10px',\n fontSize: 13,\n color: 'var(--sneek-text-muted)',\n }}\n >\n No match.\n </p>\n ) : (\n filtered.map((c) => {\n const optionStyle: CSSProperties = {\n display: 'flex',\n width: '100%',\n alignItems: 'center',\n gap: 10,\n padding: '8px 10px',\n border: 'none',\n borderRadius: 8,\n background:\n c.iso2 === country.iso2\n ? 'var(--sneek-surface-2)'\n : 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 14,\n textAlign: 'left',\n cursor: 'pointer',\n };\n return (\n <button\n key={c.iso2}\n type=\"button\"\n role=\"option\"\n aria-selected={c.iso2 === country.iso2}\n onClick={() => {\n onSelect(c);\n setOpen(false);\n setQuery('');\n }}\n style={optionStyle}\n >\n <span style={{ fontSize: 17, lineHeight: 1 }}>\n {flagEmoji(c.iso2)}\n </span>\n <span style={{ flex: 1 }}>{c.name}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>\n +{c.dial}\n </span>\n </button>\n );\n })\n )}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * Country calling codes for the phone-mode chip in the identify step.\n *\n * Flags are computed from the ISO 3166-1 alpha-2 code (two regional-indicator\n * codepoints) rather than hand-typed emoji, so there is no chance of a flag\n * silently drifting from its country. Where a dial code is shared by several\n * territories (+1, +7, +44, +61...), the first entry is the one auto-detect\n * and the default resolve to — the largest or best-known user of that code.\n */\nexport interface Country {\n iso2: string;\n name: string;\n dial: string;\n}\n\nfunction flagFromIso2(iso2: string): string {\n const A = 0x1f1e6;\n const codePoints = [...iso2.toUpperCase()].map((c) => A + (c.charCodeAt(0) - 65));\n return String.fromCodePoint(...codePoints);\n}\n\n/** [iso2, name, dial code without '+'] — ordered so shared-code lookups hit the expected country first. */\nconst RAW: [string, string, string][] = [\n ['US', 'United States', '1'],\n ['CA', 'Canada', '1'],\n ['GB', 'United Kingdom', '44'],\n ['IN', 'India', '91'],\n ['AU', 'Australia', '61'],\n ['DE', 'Germany', '49'],\n ['FR', 'France', '33'],\n ['IT', 'Italy', '39'],\n ['ES', 'Spain', '34'],\n ['PT', 'Portugal', '351'],\n ['NL', 'Netherlands', '31'],\n ['BE', 'Belgium', '32'],\n ['CH', 'Switzerland', '41'],\n ['AT', 'Austria', '43'],\n ['SE', 'Sweden', '46'],\n ['NO', 'Norway', '47'],\n ['DK', 'Denmark', '45'],\n ['FI', 'Finland', '358'],\n ['IE', 'Ireland', '353'],\n ['IS', 'Iceland', '354'],\n ['PL', 'Poland', '48'],\n ['CZ', 'Czechia', '420'],\n ['SK', 'Slovakia', '421'],\n ['HU', 'Hungary', '36'],\n ['RO', 'Romania', '40'],\n ['BG', 'Bulgaria', '359'],\n ['GR', 'Greece', '30'],\n ['TR', 'Turkiye', '90'],\n ['RU', 'Russia', '7'],\n ['UA', 'Ukraine', '380'],\n ['BY', 'Belarus', '375'],\n ['LT', 'Lithuania', '370'],\n ['LV', 'Latvia', '371'],\n ['EE', 'Estonia', '372'],\n ['HR', 'Croatia', '385'],\n ['RS', 'Serbia', '381'],\n ['SI', 'Slovenia', '386'],\n ['CY', 'Cyprus', '357'],\n ['MT', 'Malta', '356'],\n ['LU', 'Luxembourg', '352'],\n ['CN', 'China', '86'],\n ['JP', 'Japan', '81'],\n ['KR', 'South Korea', '82'],\n ['HK', 'Hong Kong', '852'],\n ['TW', 'Taiwan', '886'],\n ['MO', 'Macau', '853'],\n ['SG', 'Singapore', '65'],\n ['MY', 'Malaysia', '60'],\n ['ID', 'Indonesia', '62'],\n ['TH', 'Thailand', '66'],\n ['VN', 'Vietnam', '84'],\n ['PH', 'Philippines', '63'],\n ['PK', 'Pakistan', '92'],\n ['BD', 'Bangladesh', '880'],\n ['LK', 'Sri Lanka', '94'],\n ['NP', 'Nepal', '977'],\n ['MM', 'Myanmar', '95'],\n ['KH', 'Cambodia', '855'],\n ['LA', 'Laos', '856'],\n ['MN', 'Mongolia', '976'],\n ['KZ', 'Kazakhstan', '7'],\n ['UZ', 'Uzbekistan', '998'],\n ['AE', 'United Arab Emirates', '971'],\n ['SA', 'Saudi Arabia', '966'],\n ['QA', 'Qatar', '974'],\n ['KW', 'Kuwait', '965'],\n ['BH', 'Bahrain', '973'],\n ['OM', 'Oman', '968'],\n ['JO', 'Jordan', '962'],\n ['LB', 'Lebanon', '961'],\n ['IL', 'Israel', '972'],\n ['IQ', 'Iraq', '964'],\n ['IR', 'Iran', '98'],\n ['EG', 'Egypt', '20'],\n ['ZA', 'South Africa', '27'],\n ['NG', 'Nigeria', '234'],\n ['KE', 'Kenya', '254'],\n ['GH', 'Ghana', '233'],\n ['ET', 'Ethiopia', '251'],\n ['TZ', 'Tanzania', '255'],\n ['UG', 'Uganda', '256'],\n ['MA', 'Morocco', '212'],\n ['DZ', 'Algeria', '213'],\n ['TN', 'Tunisia', '216'],\n ['BR', 'Brazil', '55'],\n ['MX', 'Mexico', '52'],\n ['AR', 'Argentina', '54'],\n ['CL', 'Chile', '56'],\n ['CO', 'Colombia', '57'],\n ['PE', 'Peru', '51'],\n ['VE', 'Venezuela', '58'],\n ['EC', 'Ecuador', '593'],\n ['UY', 'Uruguay', '598'],\n ['PY', 'Paraguay', '595'],\n ['BO', 'Bolivia', '591'],\n ['CR', 'Costa Rica', '506'],\n ['PA', 'Panama', '507'],\n ['DO', 'Dominican Republic', '1'],\n ['GT', 'Guatemala', '502'],\n ['NZ', 'New Zealand', '64'],\n ['FJ', 'Fiji', '679'],\n];\n\nexport const COUNTRIES: readonly Country[] = RAW.map(([iso2, name, dial]) => ({\n iso2,\n name,\n dial,\n}));\n\nexport const DEFAULT_COUNTRY_ISO2 = 'IN';\n\nexport function flagEmoji(iso2: string): string {\n return flagFromIso2(iso2);\n}\n\nexport function countryByIso2(iso2: string): Country | undefined {\n return COUNTRIES.find((c) => c.iso2 === iso2);\n}\n\n/**\n * Longest-dial-code-first match against a digit string (no '+'). Tries 3, 2,\n * then 1-digit prefixes so e.g. \"44\" resolves to the UK rather than being cut\n * short at a 1-digit code that happens to also exist.\n */\nexport function countryByDialPrefix(digits: string): Country | undefined {\n for (const len of [3, 2, 1]) {\n const prefix = digits.slice(0, len);\n if (prefix.length < len) continue;\n const match = COUNTRIES.find((c) => c.dial === prefix);\n if (match) return match;\n }\n return undefined;\n}\n\n/** Best-effort guess from the browser's locale region, e.g. \"en-GB\" -> GB. */\nexport function detectCountryFromLocale(): Country | undefined {\n if (typeof navigator === 'undefined') return undefined;\n const locales = navigator.languages ?? [navigator.language];\n for (const locale of locales) {\n const match = /-([A-Z]{2})$/.exec(locale ?? '');\n if (match) {\n const found = countryByIso2(match[1]);\n if (found) return found;\n }\n }\n return undefined;\n}\n","/**\n * Theme for the drop-in login card.\n *\n * The package ships zero dependencies and no stylesheet, so the tokens are\n * injected once as CSS custom properties scoped to `.sneek-otp`. That buys two\n * things inline styles cannot: a `prefers-color-scheme` media query, and real\n * `:focus-visible` / `:hover` states.\n *\n * Light and dark are authored independently rather than one being an inversion\n * of the other. In dark, the page-to-card lightness delta carries depth and the\n * card needs no shadow; in light both are near-white, so the card takes a\n * visible border and a real shadow.\n */\nexport const SNEEK_STYLE_ID = 'sneek-otp-styles';\n\n/** Brand orange. The single accent — nothing else on the card is coloured. */\nexport const SNEEK_ACCENT_DARK = '#f86513';\n/** Darkened for light mode so it clears WCAG AA as text and as a button fill. */\nexport const SNEEK_ACCENT_LIGHT = '#b83f06';\n\nexport function buildStyles(accent?: string): string {\n const darkAccent = accent ?? SNEEK_ACCENT_DARK;\n const lightAccent = accent ?? SNEEK_ACCENT_LIGHT;\n\n const light = `\n --sneek-surface: #ffffff;\n --sneek-surface-2: #f4f1ed;\n --sneek-border: #e3ddd5;\n --sneek-text: #1c1917;\n --sneek-text-muted: #57534e;\n --sneek-accent: ${lightAccent};\n --sneek-accent-soft: color-mix(in srgb, ${lightAccent} 12%, transparent);\n --sneek-accent-shadow: color-mix(in srgb, ${lightAccent} 45%, transparent);\n --sneek-accent-contrast: #ffffff;\n --sneek-danger: #b0242a;\n --sneek-shadow: 0 3px 3px -2px rgb(0 0 0 / 0.10), 0 3px 4px rgb(0 0 0 / 0.07),\n 0 1px 8px rgb(0 0 0 / 0.06);`;\n\n const dark = `\n --sneek-surface: #17150f;\n --sneek-surface-2: #201d16;\n --sneek-border: rgba(255, 255, 255, 0.08);\n --sneek-text: #faf8f6;\n --sneek-text-muted: #a8a29b;\n --sneek-accent: ${darkAccent};\n --sneek-accent-soft: color-mix(in srgb, ${darkAccent} 16%, transparent);\n --sneek-accent-shadow: color-mix(in srgb, ${darkAccent} 55%, transparent);\n --sneek-accent-contrast: #1a0d04;\n --sneek-danger: #d43a3c;\n --sneek-shadow: none;`;\n\n return `\n.sneek-otp {${light}\n --sneek-ease: cubic-bezier(0, 0, 0.2, 1);\n}\n@media (prefers-color-scheme: dark) {\n .sneek-otp:not([data-theme=\"light\"]) {${dark}\n }\n}\n.sneek-otp[data-theme=\"dark\"] {${dark}\n}\n.sneek-otp[data-theme=\"light\"] {${light}\n}\n.sneek-otp *, .sneek-otp *::before, .sneek-otp *::after { box-sizing: border-box; }\n.sneek-otp-input:focus-visible,\n.sneek-otp-button:focus-visible,\n.sneek-otp-link:focus-visible,\n.sneek-otp-country-chip:focus-visible,\n.sneek-otp-brand-link:focus-visible {\n outline: 2px solid var(--sneek-accent);\n outline-offset: 2px;\n}\n.sneek-otp-input:focus {\n border-color: var(--sneek-accent);\n}\n.sneek-otp-phone-field:focus-within {\n border-color: var(--sneek-accent);\n}\n.sneek-otp-button:not(:disabled):hover {\n filter: brightness(1.08);\n}\n.sneek-otp-link:not(:disabled):hover {\n text-decoration: underline;\n}\n.sneek-otp-country-chip:not(:disabled):hover {\n filter: brightness(1.08);\n}\n.sneek-otp-brand-link {\n box-shadow: 0 1px 6px var(--sneek-accent-shadow);\n}\n.sneek-otp-brand-link:hover {\n box-shadow: 0 2px 10px var(--sneek-accent-shadow);\n}\n@media (prefers-reduced-motion: reduce) {\n .sneek-otp * { transition-duration: 0.01ms !important; }\n}\n@keyframes sneek-otp-caret {\n 0%, 45% { opacity: 1; }\n 50%, 100% { opacity: 0; }\n}\n.sneek-otp-caret {\n animation: sneek-otp-caret 1s step-end infinite;\n}\n`;\n}\n","import type { RequestOtpResult } from './state';\n\nexport interface FetchHandlerOptions {\n /**\n * Partner backend endpoint that sends an OTP. Receives `{ identifier }`,\n * must return `{ requestId, channels?, expiresInSeconds? }`.\n * @default '/api/auth/request-otp'\n */\n requestUrl?: string;\n /**\n * Partner backend endpoint that verifies an OTP. Receives\n * `{ requestId, code }`, returns whatever your app needs (session, token…).\n * @default '/api/auth/verify-otp'\n */\n verifyUrl?: string;\n /** Extra headers (e.g. CSRF token) to send on both requests. */\n headers?: Record<string, string>;\n /** Forwarded to fetch — set to 'include' if you use cookie sessions. */\n credentials?: RequestCredentials;\n}\n\nasync function postJson<T>(\n url: string,\n body: unknown,\n options: FetchHandlerOptions,\n): Promise<T> {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(options.headers ?? {}) },\n credentials: options.credentials,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n let message = `Request failed (${response.status})`;\n try {\n const data = (await response.json()) as { message?: string; error?: string };\n message = data.message || data.error || message;\n } catch {\n // non-JSON error body — keep the status-based message\n }\n throw new Error(message);\n }\n\n return (await response.json()) as T;\n}\n\n/**\n * Build {@link SneekOtpHandlers} that POST to your own backend endpoints.\n * Those endpoints call the Sneek API server-side with your secret key.\n */\nexport function createFetchHandlers<TResult = unknown>(\n options: FetchHandlerOptions = {},\n): {\n requestOtp: (identifier: string) => Promise<RequestOtpResult>;\n verifyOtp: (input: { requestId: string; code: string }) => Promise<TResult>;\n} {\n const requestUrl = options.requestUrl ?? '/api/auth/request-otp';\n const verifyUrl = options.verifyUrl ?? '/api/auth/verify-otp';\n\n return {\n requestOtp: (identifier: string) =>\n postJson<RequestOtpResult>(requestUrl, { identifier }, options),\n verifyOtp: (input: { requestId: string; code: string }) =>\n postJson<TResult>(verifyUrl, input, options),\n };\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime"]}
|
package/dist/index.mjs
CHANGED
|
@@ -575,8 +575,8 @@ function SneekMark() {
|
|
|
575
575
|
return /* @__PURE__ */ jsxs2(
|
|
576
576
|
"svg",
|
|
577
577
|
{
|
|
578
|
-
width: "
|
|
579
|
-
height: "
|
|
578
|
+
width: "20",
|
|
579
|
+
height: "20",
|
|
580
580
|
viewBox: "0 0 32 32",
|
|
581
581
|
fill: "none",
|
|
582
582
|
role: "img",
|
|
@@ -588,6 +588,23 @@ function SneekMark() {
|
|
|
588
588
|
}
|
|
589
589
|
);
|
|
590
590
|
}
|
|
591
|
+
function SneekMarkBox() {
|
|
592
|
+
return /* @__PURE__ */ jsx2(
|
|
593
|
+
"div",
|
|
594
|
+
{
|
|
595
|
+
style: {
|
|
596
|
+
display: "grid",
|
|
597
|
+
placeItems: "center",
|
|
598
|
+
width: 44,
|
|
599
|
+
height: 44,
|
|
600
|
+
borderRadius: 16,
|
|
601
|
+
border: "1px solid var(--sneek-border)",
|
|
602
|
+
background: "var(--sneek-surface)"
|
|
603
|
+
},
|
|
604
|
+
children: /* @__PURE__ */ jsx2(SneekMark, {})
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
}
|
|
591
608
|
function SneekOtpLogin(props) {
|
|
592
609
|
const {
|
|
593
610
|
title = "Sign in",
|
|
@@ -742,9 +759,9 @@ function SneekOtpLogin(props) {
|
|
|
742
759
|
...style
|
|
743
760
|
},
|
|
744
761
|
children: [
|
|
745
|
-
logo === null ? null : logo ?? /* @__PURE__ */ jsx2(
|
|
762
|
+
logo === null ? null : logo ?? /* @__PURE__ */ jsx2(SneekMarkBox, {}),
|
|
746
763
|
/* @__PURE__ */ jsx2(
|
|
747
|
-
"
|
|
764
|
+
"h2",
|
|
748
765
|
{
|
|
749
766
|
style: {
|
|
750
767
|
fontSize: 21,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/use-sneek-otp.ts","../src/state.ts","../src/component.tsx","../src/country-picker.tsx","../src/countries.ts","../src/theme.ts","../src/fetch-handlers.ts"],"sourcesContent":["import { useCallback, useReducer } from 'react';\nimport {\n initialOtpState,\n otpReducer,\n toMessage,\n type RequestOtpResult,\n type SneekOtpState,\n} from './state';\n\n/**\n * Partner-supplied transport. These call the *partner's own backend*, which in\n * turn talks to the Sneek API with the secret server-side key. The browser\n * never sees a Sneek API key — that is the whole security model of this package.\n */\nexport interface SneekOtpHandlers<TResult = unknown> {\n /** Ask the partner backend to send an OTP to `identifier`. */\n requestOtp: (identifier: string) => Promise<RequestOtpResult>;\n /** Verify the code with the partner backend; resolve with the auth result. */\n verifyOtp: (input: { requestId: string; code: string }) => Promise<TResult>;\n /** Called after a successful verification with the partner's result. */\n onSuccess?: (result: TResult) => void;\n /** Called on any error (request or verify). */\n onError?: (error: unknown) => void;\n}\n\nexport interface UseSneekOtp extends SneekOtpState {\n setIdentifier: (value: string) => void;\n setCode: (value: string) => void;\n /** Submit the identify step — triggers `requestOtp`. */\n sendOtp: () => Promise<void>;\n /** Submit the verify step — triggers `verifyOtp`. */\n verify: () => Promise<void>;\n /** Go back to the identify screen (e.g. \"use a different email\"). */\n back: () => void;\n /** Re-send the OTP to the same identifier. */\n resend: () => Promise<void>;\n /** Convenience booleans. */\n isSending: boolean;\n isVerifying: boolean;\n isBusy: boolean;\n}\n\nconst DEFAULT_REQUEST_ERROR = 'Could not send the code. Please try again.';\nconst DEFAULT_VERIFY_ERROR = 'That code was not correct. Please try again.';\n\n/**\n * Headless hook implementing the passwordless OTP login flow. Bring your own\n * markup, or use the {@link SneekOtpLogin} component for a styled default.\n */\nexport function useSneekOtp<TResult = unknown>(\n handlers: SneekOtpHandlers<TResult>,\n): UseSneekOtp {\n const [state, dispatch] = useReducer(otpReducer, initialOtpState);\n\n const { requestOtp, verifyOtp, onSuccess, onError } = handlers;\n\n const setIdentifier = useCallback((value: string) => {\n dispatch({ type: 'set_identifier', value });\n }, []);\n\n const setCode = useCallback((value: string) => {\n dispatch({ type: 'set_code', value });\n }, []);\n\n const runRequest = useCallback(\n async (identifier: string) => {\n const trimmed = identifier.trim();\n if (!trimmed) {\n dispatch({ type: 'request_error', message: 'Enter your email or mobile number.' });\n return;\n }\n dispatch({ type: 'request_start' });\n try {\n const result = await requestOtp(trimmed);\n dispatch({ type: 'request_success', result });\n } catch (error) {\n dispatch({ type: 'request_error', message: toMessage(error, DEFAULT_REQUEST_ERROR) });\n onError?.(error);\n }\n },\n [requestOtp, onError],\n );\n\n const sendOtp = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);\n\n const resend = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);\n\n const verify = useCallback(async () => {\n const code = state.code.trim();\n if (!code) {\n dispatch({ type: 'verify_error', message: 'Enter the code you received.' });\n return;\n }\n dispatch({ type: 'verify_start' });\n try {\n const result = await verifyOtp({ requestId: state.requestId, code });\n onSuccess?.(result);\n } catch (error) {\n dispatch({ type: 'verify_error', message: toMessage(error, DEFAULT_VERIFY_ERROR) });\n onError?.(error);\n }\n }, [verifyOtp, state.code, state.requestId, onSuccess, onError]);\n\n const back = useCallback(() => {\n dispatch({ type: 'back_to_identify' });\n }, []);\n\n return {\n ...state,\n setIdentifier,\n setCode,\n sendOtp,\n verify,\n back,\n resend,\n isSending: state.status === 'sending',\n isVerifying: state.status === 'verifying',\n isBusy: state.status !== 'idle',\n };\n}\n","/**\n * Framework-agnostic state machine for the Sneek passwordless OTP flow.\n *\n * Kept free of React so it can be unit-tested in isolation and reused by other\n * front-end bindings later (Vue/Svelte). The hook in `use-sneek-otp.ts` is a\n * thin wrapper around this reducer.\n */\n\nexport type SneekChannel = 'sms' | 'whatsapp' | 'email';\n\n/** Which screen of the two-step flow is showing. */\nexport type SneekOtpStep = 'identify' | 'verify';\n\n/** Async lifecycle for the in-flight request. */\nexport type SneekOtpStatus = 'idle' | 'sending' | 'verifying';\n\nexport interface SneekOtpState {\n step: SneekOtpStep;\n status: SneekOtpStatus;\n /** The email / mobile / username the user typed. */\n identifier: string;\n /** The OTP code the user typed on the verify screen. */\n code: string;\n /** Opaque id returned by the partner backend, replayed on verify. */\n requestId: string;\n /** Channels the OTP was actually delivered over. */\n channels: SneekChannel[];\n /** Seconds until the OTP expires (from the request response). */\n expiresInSeconds: number;\n /** User-facing error message, or null. */\n error: string | null;\n}\n\nexport const initialOtpState: SneekOtpState = {\n step: 'identify',\n status: 'idle',\n identifier: '',\n code: '',\n requestId: '',\n channels: [],\n expiresInSeconds: 0,\n error: null,\n};\n\nexport interface RequestOtpResult {\n requestId: string;\n channels?: SneekChannel[];\n expiresInSeconds?: number;\n}\n\nexport type SneekOtpAction =\n | { type: 'set_identifier'; value: string }\n | { type: 'set_code'; value: string }\n | { type: 'request_start' }\n | { type: 'request_success'; result: RequestOtpResult }\n | { type: 'request_error'; message: string }\n | { type: 'verify_start' }\n | { type: 'verify_error'; message: string }\n | { type: 'reset' }\n | { type: 'back_to_identify' };\n\nconst isBusy = (status: SneekOtpStatus): boolean => status !== 'idle';\n\nexport function otpReducer(\n state: SneekOtpState,\n action: SneekOtpAction,\n): SneekOtpState {\n switch (action.type) {\n case 'set_identifier':\n return { ...state, identifier: action.value, error: null };\n\n case 'set_code':\n return { ...state, code: action.value, error: null };\n\n case 'request_start':\n // Guard against double submits while a request is already in flight.\n if (isBusy(state.status)) return state;\n return { ...state, status: 'sending', error: null };\n\n case 'request_success':\n return {\n ...state,\n step: 'verify',\n status: 'idle',\n code: '',\n requestId: action.result.requestId,\n channels: action.result.channels ?? [],\n expiresInSeconds: action.result.expiresInSeconds ?? 0,\n error: null,\n };\n\n case 'request_error':\n return { ...state, status: 'idle', error: action.message };\n\n case 'verify_start':\n if (isBusy(state.status)) return state;\n return { ...state, status: 'verifying', error: null };\n\n case 'verify_error':\n return { ...state, status: 'idle', error: action.message };\n\n case 'back_to_identify':\n return {\n ...state,\n step: 'identify',\n status: 'idle',\n code: '',\n requestId: '',\n channels: [],\n expiresInSeconds: 0,\n error: null,\n };\n\n case 'reset':\n return { ...initialOtpState };\n\n default:\n return state;\n }\n}\n\nconst CHANNEL_LABELS: Record<SneekChannel, string> = {\n sms: 'SMS',\n whatsapp: 'WhatsApp',\n email: 'email',\n};\n\n/** \"SMS, WhatsApp\" — human label for the channels an OTP was sent over. */\nexport function formatChannels(channels: SneekChannel[]): string {\n return channels.map((c) => CHANNEL_LABELS[c] ?? c).join(', ');\n}\n\n/** Normalize any thrown value into a user-facing message. */\nexport function toMessage(error: unknown, fallback: string): string {\n if (error instanceof Error && error.message) return error.message;\n if (typeof error === 'string' && error) return error;\n return fallback;\n}\n","import {\n useEffect,\n useId,\n useState,\n type CSSProperties,\n type FormEvent,\n type ReactNode,\n} from 'react';\n\nimport { CountryPicker } from './country-picker';\nimport {\n countryByDialPrefix,\n countryByIso2,\n DEFAULT_COUNTRY_ISO2,\n type Country,\n} from './countries';\nimport { buildStyles, SNEEK_STYLE_ID } from './theme';\nimport { useSneekOtp, type SneekOtpHandlers } from './use-sneek-otp';\n\nexport type SneekTheme = 'auto' | 'light' | 'dark';\nexport type SneekIdentifierMode = 'phone' | 'email' | 'both';\n\n/** Digits in a Sneek code. */\nconst CODE_LENGTH = 6;\n/** Seconds before \"Resend code\" becomes tappable again. */\nconst RESEND_SECONDS = 30;\n/** E.164 allows 15 digits total; this is the remainder after a 3-digit dial code. */\nconst MAX_NATIONAL_DIGITS = 12;\n\nexport interface SneekOtpLoginProps<TResult = unknown>\n extends SneekOtpHandlers<TResult> {\n /** Heading above the form. @default 'Sign in' */\n title?: string;\n /** Heading once the code has been sent. @default 'Enter the code' */\n verifyTitle?: string;\n /** Sub-heading. Pass `null` to remove it. */\n subtitle?: ReactNode;\n /**\n * Which identifiers a visitor can sign in with. `'both'` starts on phone\n * with a country chip and offers a link to switch to email.\n * @default 'both'\n */\n identifierMode?: SneekIdentifierMode;\n /**\n * ISO 3166-1 alpha-2 country to preselect for the phone chip.\n * @default 'IN' (India)\n */\n defaultCountry?: string;\n /** Overrides the auto label (\"Mobile number\" / \"Email address\"). */\n identifierLabel?: string;\n /** Overrides the auto placeholder. Only used in email mode. */\n identifierPlaceholder?: string;\n /**\n * Colour scheme. `auto` follows the visitor's system setting.\n * @default 'auto'\n */\n theme?: SneekTheme;\n /**\n * Override the single accent colour. Leave unset to use Sneek orange,\n * which is tuned per mode for contrast.\n */\n accentColor?: string;\n /** Replaces the Sneek mark above the title. Pass `null` to remove it. */\n logo?: ReactNode;\n /** Show the \"Secured by Sneek\" line under the form. @default true */\n showBranding?: boolean;\n /** Style overrides for the outer card. */\n style?: CSSProperties;\n /** Extra class on the outer card. */\n className?: string;\n}\n\n/**\n * Sneek mark: two triangles offset on a diagonal — one pointing up on the\n * right, one pointing down on the left. Traced from the brand asset so the\n * package needs no image file and no CDN.\n */\nfunction SneekMark() {\n return (\n <svg\n width=\"36\"\n height=\"36\"\n viewBox=\"0 0 32 32\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Sneek\"\n >\n <path d=\"M21.3 1 29.3 16H13.3L21.3 1Z\" fill=\"var(--sneek-accent)\" />\n <path d=\"M2.7 17.5H18.7L10.7 31 2.7 17.5Z\" fill=\"var(--sneek-accent)\" />\n </svg>\n );\n}\n\n/**\n * Drop-in passwordless login card.\n *\n * The component never receives a Sneek API key — it calls the handlers you\n * supply, which talk to your own backend. See `createFetchHandlers` for the\n * common case.\n *\n * @example\n * ```tsx\n * <SneekOtpLogin\n * {...createFetchHandlers({ baseUrl: '/api/auth' })}\n * onSuccess={(session) => router.push('/app')}\n * />\n * ```\n */\nexport function SneekOtpLogin<TResult = unknown>(\n props: SneekOtpLoginProps<TResult>,\n): ReactNode {\n const {\n title = 'Sign in',\n verifyTitle = 'Enter the code',\n subtitle = 'Enter your email or phone. We will send you a code.',\n identifierMode = 'both',\n defaultCountry,\n identifierLabel,\n identifierPlaceholder,\n theme = 'auto',\n accentColor,\n logo,\n showBranding = true,\n style,\n className,\n ...handlers\n } = props;\n\n const otp = useSneekOtp<TResult>(handlers);\n const uid = useId();\n // Countdown before resend re-enables. Instant resend is both poor feedback\n // and an easy way to burn someone's SMS quota.\n const [resendIn, setResendIn] = useState(0);\n const [codeFocused, setCodeFocused] = useState(false);\n const [mode, setMode] = useState<'phone' | 'email'>(\n identifierMode === 'email' ? 'email' : 'phone',\n );\n const [country, setCountry] = useState<Country>(\n () => (defaultCountry && countryByIso2(defaultCountry)) || countryByIso2(DEFAULT_COUNTRY_ISO2)!,\n );\n // The digits typed into the phone field, separate from `otp.identifier`\n // (which holds the composed +<dial><digits> value actually submitted).\n const [nationalNumber, setNationalNumber] = useState('');\n const identifierId = `${uid}-identifier`;\n const codeId = `${uid}-code`;\n const statusId = `${uid}-status`;\n\n const onCountrySelect = (next: Country) => {\n setCountry(next);\n otp.setIdentifier(`+${next.dial}${nationalNumber}`);\n };\n\n const onNationalNumberChange = (raw: string) => {\n let digits = raw.replace(/\\D/g, '').slice(0, MAX_NATIONAL_DIGITS + 3);\n let effectiveCountry = country;\n // Only re-detect off an explicit leading '+' — a real, unambiguous\n // signal that this is a full international number. A plain jump in\n // digit count (paste, or a phone-autofill suggestion) is NOT enough:\n // most 10-digit local numbers coincidentally start with digits that\n // match *some* country's dial code, which would otherwise silently\n // truncate a legitimate local number.\n if (raw.trim().startsWith('+')) {\n const guess = countryByDialPrefix(digits);\n if (guess && digits.startsWith(guess.dial)) {\n effectiveCountry = guess;\n digits = digits.slice(guess.dial.length);\n }\n }\n digits = digits.slice(0, MAX_NATIONAL_DIGITS);\n if (effectiveCountry !== country) setCountry(effectiveCountry);\n setNationalNumber(digits);\n otp.setIdentifier(`+${effectiveCountry.dial}${digits}`);\n };\n\n const switchMode = (next: 'phone' | 'email') => {\n setMode(next);\n setNationalNumber('');\n otp.setIdentifier('');\n };\n\n // One <style> element for the whole page, regardless of how many cards\n // render. Injected on mount so the package stays SSR-safe.\n useEffect(() => {\n if (typeof document === 'undefined') return;\n let el = document.getElementById(SNEEK_STYLE_ID);\n if (!el) {\n el = document.createElement('style');\n el.id = SNEEK_STYLE_ID;\n document.head.appendChild(el);\n }\n el.textContent = buildStyles(accentColor);\n }, [accentColor]);\n\n const onIdentifySubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void otp.sendOtp();\n };\n\n const onVerifySubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void otp.verify();\n };\n\n // Start the cooldown whenever a code goes out.\n useEffect(() => {\n if (otp.step === 'verify') setResendIn(RESEND_SECONDS);\n }, [otp.step]);\n\n useEffect(() => {\n if (resendIn <= 0) return;\n const timer = setTimeout(() => setResendIn((n) => n - 1), 1000);\n return () => clearTimeout(timer);\n }, [resendIn]);\n\n // Submit as soon as the code looks complete — nobody should have to reach\n // for a button after typing the last digit.\n useEffect(() => {\n if (otp.step === 'verify' && otp.code.length === CODE_LENGTH && !otp.isBusy) {\n void otp.verify();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [otp.code, otp.step]);\n\n const label: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n };\n\n const input: CSSProperties = {\n padding: '12px 14px',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n color: 'var(--sneek-text)',\n fontSize: 15,\n width: '100%',\n outline: 'none',\n transition: 'border-color 200ms var(--sneek-ease)',\n };\n\n const button: CSSProperties = {\n padding: '12px 18px',\n border: 'none',\n borderRadius: 9999,\n background: 'var(--sneek-accent)',\n color: 'var(--sneek-accent-contrast)',\n fontSize: 15,\n fontWeight: 500,\n cursor: otp.isBusy ? 'not-allowed' : 'pointer',\n opacity: otp.isBusy ? 0.6 : 1,\n width: '100%',\n transition: 'filter 200ms var(--sneek-ease), opacity 200ms var(--sneek-ease)',\n };\n\n const link: CSSProperties = {\n border: 'none',\n background: 'transparent',\n color: 'var(--sneek-accent)',\n cursor: otp.isBusy ? 'not-allowed' : 'pointer',\n font: 'inherit',\n fontSize: 14,\n padding: 0,\n };\n\n const notice: CSSProperties = {\n padding: '10px 12px',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n border: '1px solid var(--sneek-border)',\n fontSize: 14,\n color: 'var(--sneek-text-muted)',\n };\n\n return (\n <div\n className={className ? `sneek-otp ${className}` : 'sneek-otp'}\n data-theme={theme === 'auto' ? undefined : theme}\n style={{\n maxWidth: 400,\n margin: '0 auto',\n padding: 24,\n border: '1px solid var(--sneek-border)',\n borderRadius: 16,\n background: 'var(--sneek-surface)',\n boxShadow: 'var(--sneek-shadow)',\n color: 'var(--sneek-text)',\n fontFamily:\n 'Inter, ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n lineHeight: 1.5,\n ...style,\n }}\n >\n {logo === null ? null : (logo ?? <SneekMark />)}\n <h1\n style={{\n fontSize: 21,\n lineHeight: '28px',\n fontWeight: 500,\n letterSpacing: '-0.01em',\n margin: '16px 0 0',\n }}\n >\n {otp.step === 'verify' ? verifyTitle : title}\n </h1>\n {otp.step === 'verify' ? (\n <p\n style={{\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n margin: '8px 0 0',\n }}\n >\n Sent to{' '}\n <span style={{ color: 'var(--sneek-text)' }}>{otp.identifier}</span>\n {' · '}\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={otp.back}\n disabled={otp.isBusy}\n style={{ ...link, fontSize: 14 }}\n >\n Change\n </button>\n </p>\n ) : subtitle ? (\n <p\n style={{\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n margin: '8px 0 0',\n }}\n >\n {subtitle}\n </p>\n ) : null}\n\n {/* Errors and channel notices are announced, not just shown. */}\n <div role=\"status\" aria-live=\"polite\" id={statusId} style={{ marginTop: 32 }}>\n {otp.error ? (\n <div\n role=\"alert\"\n style={{\n ...notice,\n color: 'var(--sneek-danger)',\n borderColor: 'var(--sneek-danger)',\n }}\n >\n {otp.error}\n </div>\n ) : null}\n </div>\n\n {otp.step === 'identify' ? (\n <form\n onSubmit={onIdentifySubmit}\n style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 16 }}\n >\n <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>\n <label style={{ ...label, gap: 0 }} htmlFor={identifierId}>\n {identifierLabel ?? (mode === 'phone' ? 'Mobile number' : 'Email address')}\n </label>\n {identifierMode === 'both' ? (\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={() => switchMode(mode === 'phone' ? 'email' : 'phone')}\n disabled={otp.isBusy}\n style={{ ...link, fontSize: 13 }}\n >\n {mode === 'phone' ? 'Use email instead' : 'Use phone instead'}\n </button>\n ) : null}\n </div>\n\n {mode === 'phone' ? (\n <div\n className=\"sneek-otp-phone-field\"\n style={{\n display: 'flex',\n alignItems: 'stretch',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n transition: 'border-color 200ms var(--sneek-ease)',\n }}\n >\n <CountryPicker\n country={country}\n onSelect={onCountrySelect}\n disabled={otp.isBusy}\n />\n <span\n aria-hidden=\"true\"\n style={{\n width: 1,\n margin: '9px 0',\n background: 'var(--sneek-border)',\n }}\n />\n <input\n id={identifierId}\n type=\"tel\"\n inputMode=\"tel\"\n autoComplete=\"tel-national\"\n value={nationalNumber}\n onChange={(e) => onNationalNumberChange(e.target.value)}\n placeholder=\"Mobile number\"\n autoFocus\n required\n aria-describedby={statusId}\n style={{\n ...input,\n flex: 1,\n border: 'none',\n background: 'transparent',\n borderRadius: 0,\n }}\n />\n </div>\n ) : (\n <input\n id={identifierId}\n className=\"sneek-otp-input\"\n type=\"email\"\n value={otp.identifier}\n onChange={(e) => otp.setIdentifier(e.target.value)}\n placeholder={identifierPlaceholder ?? 'you@company.com'}\n autoComplete=\"email\"\n autoFocus\n required\n aria-describedby={statusId}\n style={input}\n />\n )}\n\n <button\n type=\"submit\"\n className=\"sneek-otp-button\"\n disabled={otp.isBusy}\n style={button}\n >\n {otp.isSending ? 'Sending code…' : 'Send code'}\n </button>\n </form>\n ) : (\n <form\n onSubmit={onVerifySubmit}\n style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 16 }}\n >\n <label style={{ ...label, marginBottom: -8 }} htmlFor={codeId}>\n {CODE_LENGTH}-digit code\n </label>\n {/*\n * One real input captures keystrokes — paste, backspace and\n * SMS/email autofill all keep working, which six separate\n * `<input>`s make surprisingly easy to break. It sits over\n * the visible cells, transparent; the cells below just\n * mirror its value.\n */}\n <div style={{ position: 'relative' }}>\n <input\n id={codeId}\n className=\"sneek-otp-code-input\"\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n autoComplete=\"one-time-code\"\n maxLength={CODE_LENGTH}\n value={otp.code}\n onChange={(e) =>\n otp.setCode(\n e.target.value.replace(/\\D/g, '').slice(0, CODE_LENGTH),\n )\n }\n onFocus={() => setCodeFocused(true)}\n onBlur={() => setCodeFocused(false)}\n autoFocus\n required\n aria-describedby={statusId}\n style={{\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n opacity: 0,\n caretColor: 'transparent',\n cursor: 'text',\n }}\n />\n <div\n className=\"sneek-otp-code-cells\"\n aria-hidden=\"true\"\n style={{ display: 'flex', gap: 10 }}\n >\n {Array.from({ length: CODE_LENGTH }).map((_, i) => {\n const digit = otp.code[i];\n const isActive = codeFocused && i === otp.code.length;\n return (\n <div\n key={i}\n data-active={isActive}\n style={{\n flex: 1,\n height: 44,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 22,\n color: 'var(--sneek-text)',\n borderBottom: `2px solid ${\n isActive ? 'var(--sneek-accent)' : 'var(--sneek-border)'\n }`,\n transition: 'border-color 200ms var(--sneek-ease)',\n }}\n >\n {digit ?? (isActive ? (\n <span\n className=\"sneek-otp-caret\"\n style={{\n width: 2,\n height: 22,\n background: 'var(--sneek-accent)',\n }}\n />\n ) : null)}\n </div>\n );\n })}\n </div>\n </div>\n <button\n type=\"submit\"\n className=\"sneek-otp-button\"\n disabled={otp.isBusy || otp.code.length < CODE_LENGTH}\n style={{\n ...button,\n opacity:\n otp.isBusy || otp.code.length < CODE_LENGTH ? 0.6 : 1,\n }}\n >\n {otp.isVerifying ? 'Verifying…' : 'Verify'}\n </button>\n <div style={{ textAlign: 'center' }}>\n {resendIn > 0 ? (\n <span\n style={{\n fontSize: 14,\n color: 'var(--sneek-text-muted)',\n }}\n >\n Resend code in {resendIn}s\n </span>\n ) : (\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={() => void otp.resend()}\n disabled={otp.isBusy}\n style={link}\n >\n Resend code\n </button>\n )}\n </div>\n </form>\n )}\n\n {showBranding ? (\n <p\n style={{\n margin: '32px 0 0',\n textAlign: 'center',\n fontSize: 12,\n lineHeight: '16px',\n color: 'var(--sneek-text-muted)',\n }}\n >\n Secured by{' '}\n <a\n href=\"https://sneek.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"sneek-otp-brand-link\"\n style={{\n display: 'inline-block',\n padding: '0 5px',\n borderRadius: 6,\n color: 'var(--sneek-accent)',\n fontWeight: 500,\n textDecoration: 'none',\n transition: 'box-shadow 200ms var(--sneek-ease)',\n }}\n >\n Sneek\n </a>\n </p>\n ) : null}\n </div>\n );\n}\n","import {\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n} from 'react';\n\nimport { COUNTRIES, flagEmoji, type Country } from './countries';\n\nfunction ChevronDown() {\n return (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M2 3.5 5 6.5 8 3.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\nexport interface CountryPickerProps {\n country: Country;\n onSelect: (country: Country) => void;\n disabled?: boolean;\n}\n\n/**\n * The flag + dial-code chip in front of the phone number field. Opens a\n * searchable list on click; the number field itself keeps auto-detecting\n * from pasted content independently of this — this is the manual path.\n */\nexport function CountryPicker({ country, onSelect, disabled }: CountryPickerProps) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const rootRef = useRef<HTMLDivElement>(null);\n const searchRef = useRef<HTMLInputElement>(null);\n const uid = useId();\n\n useEffect(() => {\n if (!open) return;\n searchRef.current?.focus();\n const onDocPointerDown = (event: MouseEvent) => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false);\n };\n document.addEventListener('mousedown', onDocPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onDocPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open]);\n\n const q = query.trim().toLowerCase();\n const filtered = q\n ? COUNTRIES.filter(\n (c) => c.name.toLowerCase().includes(q) || c.dial.includes(q.replace(/^\\+/, '')),\n )\n : COUNTRIES;\n\n const listId = `${uid}-country-list`;\n\n return (\n <div ref={rootRef} style={{ position: 'relative', flexShrink: 0 }}>\n <button\n type=\"button\"\n className=\"sneek-otp-country-chip\"\n onClick={() => setOpen((o) => !o)}\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n height: '100%',\n padding: '0 10px 0 14px',\n border: 'none',\n borderRadius: '12px 0 0 12px',\n background: 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 15,\n cursor: disabled ? 'not-allowed' : 'pointer',\n }}\n >\n <span style={{ fontSize: 18, lineHeight: 1 }}>{flagEmoji(country.iso2)}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>+{country.dial}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>\n <ChevronDown />\n </span>\n </button>\n\n {open ? (\n <div\n role=\"presentation\"\n style={{\n position: 'absolute',\n top: 'calc(100% + 6px)',\n left: 0,\n zIndex: 10,\n width: 260,\n maxWidth: '80vw',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface)',\n boxShadow: 'var(--sneek-shadow), 0 8px 24px rgb(0 0 0 / 0.12)',\n overflow: 'hidden',\n }}\n >\n <input\n ref={searchRef}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && filtered[0]) {\n onSelect(filtered[0]);\n setOpen(false);\n setQuery('');\n }\n }}\n placeholder=\"Search country or code\"\n aria-controls={listId}\n role=\"combobox\"\n aria-expanded={open}\n style={{\n width: '100%',\n padding: '10px 12px',\n border: 'none',\n borderBottom: '1px solid var(--sneek-border)',\n background: 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 14,\n outline: 'none',\n }}\n />\n <div\n id={listId}\n role=\"listbox\"\n style={{ maxHeight: 240, overflowY: 'auto', padding: 6 }}\n >\n {filtered.length === 0 ? (\n <p\n style={{\n padding: '8px 10px',\n fontSize: 13,\n color: 'var(--sneek-text-muted)',\n }}\n >\n No match.\n </p>\n ) : (\n filtered.map((c) => {\n const optionStyle: CSSProperties = {\n display: 'flex',\n width: '100%',\n alignItems: 'center',\n gap: 10,\n padding: '8px 10px',\n border: 'none',\n borderRadius: 8,\n background:\n c.iso2 === country.iso2\n ? 'var(--sneek-surface-2)'\n : 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 14,\n textAlign: 'left',\n cursor: 'pointer',\n };\n return (\n <button\n key={c.iso2}\n type=\"button\"\n role=\"option\"\n aria-selected={c.iso2 === country.iso2}\n onClick={() => {\n onSelect(c);\n setOpen(false);\n setQuery('');\n }}\n style={optionStyle}\n >\n <span style={{ fontSize: 17, lineHeight: 1 }}>\n {flagEmoji(c.iso2)}\n </span>\n <span style={{ flex: 1 }}>{c.name}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>\n +{c.dial}\n </span>\n </button>\n );\n })\n )}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * Country calling codes for the phone-mode chip in the identify step.\n *\n * Flags are computed from the ISO 3166-1 alpha-2 code (two regional-indicator\n * codepoints) rather than hand-typed emoji, so there is no chance of a flag\n * silently drifting from its country. Where a dial code is shared by several\n * territories (+1, +7, +44, +61...), the first entry is the one auto-detect\n * and the default resolve to — the largest or best-known user of that code.\n */\nexport interface Country {\n iso2: string;\n name: string;\n dial: string;\n}\n\nfunction flagFromIso2(iso2: string): string {\n const A = 0x1f1e6;\n const codePoints = [...iso2.toUpperCase()].map((c) => A + (c.charCodeAt(0) - 65));\n return String.fromCodePoint(...codePoints);\n}\n\n/** [iso2, name, dial code without '+'] — ordered so shared-code lookups hit the expected country first. */\nconst RAW: [string, string, string][] = [\n ['US', 'United States', '1'],\n ['CA', 'Canada', '1'],\n ['GB', 'United Kingdom', '44'],\n ['IN', 'India', '91'],\n ['AU', 'Australia', '61'],\n ['DE', 'Germany', '49'],\n ['FR', 'France', '33'],\n ['IT', 'Italy', '39'],\n ['ES', 'Spain', '34'],\n ['PT', 'Portugal', '351'],\n ['NL', 'Netherlands', '31'],\n ['BE', 'Belgium', '32'],\n ['CH', 'Switzerland', '41'],\n ['AT', 'Austria', '43'],\n ['SE', 'Sweden', '46'],\n ['NO', 'Norway', '47'],\n ['DK', 'Denmark', '45'],\n ['FI', 'Finland', '358'],\n ['IE', 'Ireland', '353'],\n ['IS', 'Iceland', '354'],\n ['PL', 'Poland', '48'],\n ['CZ', 'Czechia', '420'],\n ['SK', 'Slovakia', '421'],\n ['HU', 'Hungary', '36'],\n ['RO', 'Romania', '40'],\n ['BG', 'Bulgaria', '359'],\n ['GR', 'Greece', '30'],\n ['TR', 'Turkiye', '90'],\n ['RU', 'Russia', '7'],\n ['UA', 'Ukraine', '380'],\n ['BY', 'Belarus', '375'],\n ['LT', 'Lithuania', '370'],\n ['LV', 'Latvia', '371'],\n ['EE', 'Estonia', '372'],\n ['HR', 'Croatia', '385'],\n ['RS', 'Serbia', '381'],\n ['SI', 'Slovenia', '386'],\n ['CY', 'Cyprus', '357'],\n ['MT', 'Malta', '356'],\n ['LU', 'Luxembourg', '352'],\n ['CN', 'China', '86'],\n ['JP', 'Japan', '81'],\n ['KR', 'South Korea', '82'],\n ['HK', 'Hong Kong', '852'],\n ['TW', 'Taiwan', '886'],\n ['MO', 'Macau', '853'],\n ['SG', 'Singapore', '65'],\n ['MY', 'Malaysia', '60'],\n ['ID', 'Indonesia', '62'],\n ['TH', 'Thailand', '66'],\n ['VN', 'Vietnam', '84'],\n ['PH', 'Philippines', '63'],\n ['PK', 'Pakistan', '92'],\n ['BD', 'Bangladesh', '880'],\n ['LK', 'Sri Lanka', '94'],\n ['NP', 'Nepal', '977'],\n ['MM', 'Myanmar', '95'],\n ['KH', 'Cambodia', '855'],\n ['LA', 'Laos', '856'],\n ['MN', 'Mongolia', '976'],\n ['KZ', 'Kazakhstan', '7'],\n ['UZ', 'Uzbekistan', '998'],\n ['AE', 'United Arab Emirates', '971'],\n ['SA', 'Saudi Arabia', '966'],\n ['QA', 'Qatar', '974'],\n ['KW', 'Kuwait', '965'],\n ['BH', 'Bahrain', '973'],\n ['OM', 'Oman', '968'],\n ['JO', 'Jordan', '962'],\n ['LB', 'Lebanon', '961'],\n ['IL', 'Israel', '972'],\n ['IQ', 'Iraq', '964'],\n ['IR', 'Iran', '98'],\n ['EG', 'Egypt', '20'],\n ['ZA', 'South Africa', '27'],\n ['NG', 'Nigeria', '234'],\n ['KE', 'Kenya', '254'],\n ['GH', 'Ghana', '233'],\n ['ET', 'Ethiopia', '251'],\n ['TZ', 'Tanzania', '255'],\n ['UG', 'Uganda', '256'],\n ['MA', 'Morocco', '212'],\n ['DZ', 'Algeria', '213'],\n ['TN', 'Tunisia', '216'],\n ['BR', 'Brazil', '55'],\n ['MX', 'Mexico', '52'],\n ['AR', 'Argentina', '54'],\n ['CL', 'Chile', '56'],\n ['CO', 'Colombia', '57'],\n ['PE', 'Peru', '51'],\n ['VE', 'Venezuela', '58'],\n ['EC', 'Ecuador', '593'],\n ['UY', 'Uruguay', '598'],\n ['PY', 'Paraguay', '595'],\n ['BO', 'Bolivia', '591'],\n ['CR', 'Costa Rica', '506'],\n ['PA', 'Panama', '507'],\n ['DO', 'Dominican Republic', '1'],\n ['GT', 'Guatemala', '502'],\n ['NZ', 'New Zealand', '64'],\n ['FJ', 'Fiji', '679'],\n];\n\nexport const COUNTRIES: readonly Country[] = RAW.map(([iso2, name, dial]) => ({\n iso2,\n name,\n dial,\n}));\n\nexport const DEFAULT_COUNTRY_ISO2 = 'IN';\n\nexport function flagEmoji(iso2: string): string {\n return flagFromIso2(iso2);\n}\n\nexport function countryByIso2(iso2: string): Country | undefined {\n return COUNTRIES.find((c) => c.iso2 === iso2);\n}\n\n/**\n * Longest-dial-code-first match against a digit string (no '+'). Tries 3, 2,\n * then 1-digit prefixes so e.g. \"44\" resolves to the UK rather than being cut\n * short at a 1-digit code that happens to also exist.\n */\nexport function countryByDialPrefix(digits: string): Country | undefined {\n for (const len of [3, 2, 1]) {\n const prefix = digits.slice(0, len);\n if (prefix.length < len) continue;\n const match = COUNTRIES.find((c) => c.dial === prefix);\n if (match) return match;\n }\n return undefined;\n}\n\n/** Best-effort guess from the browser's locale region, e.g. \"en-GB\" -> GB. */\nexport function detectCountryFromLocale(): Country | undefined {\n if (typeof navigator === 'undefined') return undefined;\n const locales = navigator.languages ?? [navigator.language];\n for (const locale of locales) {\n const match = /-([A-Z]{2})$/.exec(locale ?? '');\n if (match) {\n const found = countryByIso2(match[1]);\n if (found) return found;\n }\n }\n return undefined;\n}\n","/**\n * Theme for the drop-in login card.\n *\n * The package ships zero dependencies and no stylesheet, so the tokens are\n * injected once as CSS custom properties scoped to `.sneek-otp`. That buys two\n * things inline styles cannot: a `prefers-color-scheme` media query, and real\n * `:focus-visible` / `:hover` states.\n *\n * Light and dark are authored independently rather than one being an inversion\n * of the other. In dark, the page-to-card lightness delta carries depth and the\n * card needs no shadow; in light both are near-white, so the card takes a\n * visible border and a real shadow.\n */\nexport const SNEEK_STYLE_ID = 'sneek-otp-styles';\n\n/** Brand orange. The single accent — nothing else on the card is coloured. */\nexport const SNEEK_ACCENT_DARK = '#f86513';\n/** Darkened for light mode so it clears WCAG AA as text and as a button fill. */\nexport const SNEEK_ACCENT_LIGHT = '#b83f06';\n\nexport function buildStyles(accent?: string): string {\n const darkAccent = accent ?? SNEEK_ACCENT_DARK;\n const lightAccent = accent ?? SNEEK_ACCENT_LIGHT;\n\n const light = `\n --sneek-surface: #ffffff;\n --sneek-surface-2: #f4f1ed;\n --sneek-border: #e3ddd5;\n --sneek-text: #1c1917;\n --sneek-text-muted: #57534e;\n --sneek-accent: ${lightAccent};\n --sneek-accent-soft: color-mix(in srgb, ${lightAccent} 12%, transparent);\n --sneek-accent-shadow: color-mix(in srgb, ${lightAccent} 45%, transparent);\n --sneek-accent-contrast: #ffffff;\n --sneek-danger: #b0242a;\n --sneek-shadow: 0 3px 3px -2px rgb(0 0 0 / 0.10), 0 3px 4px rgb(0 0 0 / 0.07),\n 0 1px 8px rgb(0 0 0 / 0.06);`;\n\n const dark = `\n --sneek-surface: #17150f;\n --sneek-surface-2: #201d16;\n --sneek-border: rgba(255, 255, 255, 0.08);\n --sneek-text: #faf8f6;\n --sneek-text-muted: #a8a29b;\n --sneek-accent: ${darkAccent};\n --sneek-accent-soft: color-mix(in srgb, ${darkAccent} 16%, transparent);\n --sneek-accent-shadow: color-mix(in srgb, ${darkAccent} 55%, transparent);\n --sneek-accent-contrast: #1a0d04;\n --sneek-danger: #d43a3c;\n --sneek-shadow: none;`;\n\n return `\n.sneek-otp {${light}\n --sneek-ease: cubic-bezier(0, 0, 0.2, 1);\n}\n@media (prefers-color-scheme: dark) {\n .sneek-otp:not([data-theme=\"light\"]) {${dark}\n }\n}\n.sneek-otp[data-theme=\"dark\"] {${dark}\n}\n.sneek-otp[data-theme=\"light\"] {${light}\n}\n.sneek-otp *, .sneek-otp *::before, .sneek-otp *::after { box-sizing: border-box; }\n.sneek-otp-input:focus-visible,\n.sneek-otp-button:focus-visible,\n.sneek-otp-link:focus-visible,\n.sneek-otp-country-chip:focus-visible,\n.sneek-otp-brand-link:focus-visible {\n outline: 2px solid var(--sneek-accent);\n outline-offset: 2px;\n}\n.sneek-otp-input:focus {\n border-color: var(--sneek-accent);\n}\n.sneek-otp-phone-field:focus-within {\n border-color: var(--sneek-accent);\n}\n.sneek-otp-button:not(:disabled):hover {\n filter: brightness(1.08);\n}\n.sneek-otp-link:not(:disabled):hover {\n text-decoration: underline;\n}\n.sneek-otp-country-chip:not(:disabled):hover {\n filter: brightness(1.08);\n}\n.sneek-otp-brand-link {\n box-shadow: 0 1px 6px var(--sneek-accent-shadow);\n}\n.sneek-otp-brand-link:hover {\n box-shadow: 0 2px 10px var(--sneek-accent-shadow);\n}\n@media (prefers-reduced-motion: reduce) {\n .sneek-otp * { transition-duration: 0.01ms !important; }\n}\n@keyframes sneek-otp-caret {\n 0%, 45% { opacity: 1; }\n 50%, 100% { opacity: 0; }\n}\n.sneek-otp-caret {\n animation: sneek-otp-caret 1s step-end infinite;\n}\n`;\n}\n","import type { RequestOtpResult } from './state';\n\nexport interface FetchHandlerOptions {\n /**\n * Partner backend endpoint that sends an OTP. Receives `{ identifier }`,\n * must return `{ requestId, channels?, expiresInSeconds? }`.\n * @default '/api/auth/request-otp'\n */\n requestUrl?: string;\n /**\n * Partner backend endpoint that verifies an OTP. Receives\n * `{ requestId, code }`, returns whatever your app needs (session, token…).\n * @default '/api/auth/verify-otp'\n */\n verifyUrl?: string;\n /** Extra headers (e.g. CSRF token) to send on both requests. */\n headers?: Record<string, string>;\n /** Forwarded to fetch — set to 'include' if you use cookie sessions. */\n credentials?: RequestCredentials;\n}\n\nasync function postJson<T>(\n url: string,\n body: unknown,\n options: FetchHandlerOptions,\n): Promise<T> {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(options.headers ?? {}) },\n credentials: options.credentials,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n let message = `Request failed (${response.status})`;\n try {\n const data = (await response.json()) as { message?: string; error?: string };\n message = data.message || data.error || message;\n } catch {\n // non-JSON error body — keep the status-based message\n }\n throw new Error(message);\n }\n\n return (await response.json()) as T;\n}\n\n/**\n * Build {@link SneekOtpHandlers} that POST to your own backend endpoints.\n * Those endpoints call the Sneek API server-side with your secret key.\n */\nexport function createFetchHandlers<TResult = unknown>(\n options: FetchHandlerOptions = {},\n): {\n requestOtp: (identifier: string) => Promise<RequestOtpResult>;\n verifyOtp: (input: { requestId: string; code: string }) => Promise<TResult>;\n} {\n const requestUrl = options.requestUrl ?? '/api/auth/request-otp';\n const verifyUrl = options.verifyUrl ?? '/api/auth/verify-otp';\n\n return {\n requestOtp: (identifier: string) =>\n postJson<RequestOtpResult>(requestUrl, { identifier }, options),\n verifyOtp: (input: { requestId: string; code: string }) =>\n postJson<TResult>(verifyUrl, input, options),\n };\n}\n"],"mappings":";AAAA,SAAS,aAAa,kBAAkB;;;ACiCjC,IAAM,kBAAiC;AAAA,EAC5C,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,WAAW;AAAA,EACX,UAAU,CAAC;AAAA,EACX,kBAAkB;AAAA,EAClB,OAAO;AACT;AAmBA,IAAM,SAAS,CAAC,WAAoC,WAAW;AAExD,SAAS,WACd,OACA,QACe;AACf,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,YAAY,OAAO,OAAO,OAAO,KAAK;AAAA,IAE3D,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,MAAM,OAAO,OAAO,OAAO,KAAK;AAAA,IAErD,KAAK;AAEH,UAAI,OAAO,MAAM,MAAM,EAAG,QAAO;AACjC,aAAO,EAAE,GAAG,OAAO,QAAQ,WAAW,OAAO,KAAK;AAAA,IAEpD,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,WAAW,OAAO,OAAO;AAAA,QACzB,UAAU,OAAO,OAAO,YAAY,CAAC;AAAA,QACrC,kBAAkB,OAAO,OAAO,oBAAoB;AAAA,QACpD,OAAO;AAAA,MACT;AAAA,IAEF,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,QAAQ,QAAQ,OAAO,OAAO,QAAQ;AAAA,IAE3D,KAAK;AACH,UAAI,OAAO,MAAM,MAAM,EAAG,QAAO;AACjC,aAAO,EAAE,GAAG,OAAO,QAAQ,aAAa,OAAO,KAAK;AAAA,IAEtD,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,QAAQ,QAAQ,OAAO,OAAO,QAAQ;AAAA,IAE3D,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,WAAW;AAAA,QACX,UAAU,CAAC;AAAA,QACX,kBAAkB;AAAA,QAClB,OAAO;AAAA,MACT;AAAA,IAEF,KAAK;AACH,aAAO,EAAE,GAAG,gBAAgB;AAAA,IAE9B;AACE,aAAO;AAAA,EACX;AACF;AAEA,IAAM,iBAA+C;AAAA,EACnD,KAAK;AAAA,EACL,UAAU;AAAA,EACV,OAAO;AACT;AAGO,SAAS,eAAe,UAAkC;AAC/D,SAAO,SAAS,IAAI,CAAC,MAAM,eAAe,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI;AAC9D;AAGO,SAAS,UAAU,OAAgB,UAA0B;AAClE,MAAI,iBAAiB,SAAS,MAAM,QAAS,QAAO,MAAM;AAC1D,MAAI,OAAO,UAAU,YAAY,MAAO,QAAO;AAC/C,SAAO;AACT;;;AD/FA,IAAM,wBAAwB;AAC9B,IAAM,uBAAuB;AAMtB,SAAS,YACd,UACa;AACb,QAAM,CAAC,OAAO,QAAQ,IAAI,WAAW,YAAY,eAAe;AAEhE,QAAM,EAAE,YAAY,WAAW,WAAW,QAAQ,IAAI;AAEtD,QAAM,gBAAgB,YAAY,CAAC,UAAkB;AACnD,aAAS,EAAE,MAAM,kBAAkB,MAAM,CAAC;AAAA,EAC5C,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,YAAY,CAAC,UAAkB;AAC7C,aAAS,EAAE,MAAM,YAAY,MAAM,CAAC;AAAA,EACtC,GAAG,CAAC,CAAC;AAEL,QAAM,aAAa;AAAA,IACjB,OAAO,eAAuB;AAC5B,YAAM,UAAU,WAAW,KAAK;AAChC,UAAI,CAAC,SAAS;AACZ,iBAAS,EAAE,MAAM,iBAAiB,SAAS,qCAAqC,CAAC;AACjF;AAAA,MACF;AACA,eAAS,EAAE,MAAM,gBAAgB,CAAC;AAClC,UAAI;AACF,cAAM,SAAS,MAAM,WAAW,OAAO;AACvC,iBAAS,EAAE,MAAM,mBAAmB,OAAO,CAAC;AAAA,MAC9C,SAAS,OAAO;AACd,iBAAS,EAAE,MAAM,iBAAiB,SAAS,UAAU,OAAO,qBAAqB,EAAE,CAAC;AACpF,kBAAU,KAAK;AAAA,MACjB;AAAA,IACF;AAAA,IACA,CAAC,YAAY,OAAO;AAAA,EACtB;AAEA,QAAM,UAAU,YAAY,MAAM,WAAW,MAAM,UAAU,GAAG,CAAC,YAAY,MAAM,UAAU,CAAC;AAE9F,QAAM,SAAS,YAAY,MAAM,WAAW,MAAM,UAAU,GAAG,CAAC,YAAY,MAAM,UAAU,CAAC;AAE7F,QAAM,SAAS,YAAY,YAAY;AACrC,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI,CAAC,MAAM;AACT,eAAS,EAAE,MAAM,gBAAgB,SAAS,+BAA+B,CAAC;AAC1E;AAAA,IACF;AACA,aAAS,EAAE,MAAM,eAAe,CAAC;AACjC,QAAI;AACF,YAAM,SAAS,MAAM,UAAU,EAAE,WAAW,MAAM,WAAW,KAAK,CAAC;AACnE,kBAAY,MAAM;AAAA,IACpB,SAAS,OAAO;AACd,eAAS,EAAE,MAAM,gBAAgB,SAAS,UAAU,OAAO,oBAAoB,EAAE,CAAC;AAClF,gBAAU,KAAK;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,WAAW,MAAM,MAAM,MAAM,WAAW,WAAW,OAAO,CAAC;AAE/D,QAAM,OAAO,YAAY,MAAM;AAC7B,aAAS,EAAE,MAAM,mBAAmB,CAAC;AAAA,EACvC,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,MAAM,WAAW;AAAA,IAC5B,aAAa,MAAM,WAAW;AAAA,IAC9B,QAAQ,MAAM,WAAW;AAAA,EAC3B;AACF;;;AEvHA;AAAA,EACI,aAAAA;AAAA,EACA,SAAAC;AAAA,EACA,YAAAC;AAAA,OAIG;;;ACPP;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEG;;;ACSP,SAAS,aAAa,MAAsB;AACxC,QAAM,IAAI;AACV,QAAM,aAAa,CAAC,GAAG,KAAK,YAAY,CAAC,EAAE,IAAI,CAAC,MAAM,KAAK,EAAE,WAAW,CAAC,IAAI,GAAG;AAChF,SAAO,OAAO,cAAc,GAAG,UAAU;AAC7C;AAGA,IAAM,MAAkC;AAAA,EACpC,CAAC,MAAM,iBAAiB,GAAG;AAAA,EAC3B,CAAC,MAAM,UAAU,GAAG;AAAA,EACpB,CAAC,MAAM,kBAAkB,IAAI;AAAA,EAC7B,CAAC,MAAM,SAAS,IAAI;AAAA,EACpB,CAAC,MAAM,aAAa,IAAI;AAAA,EACxB,CAAC,MAAM,WAAW,IAAI;AAAA,EACtB,CAAC,MAAM,UAAU,IAAI;AAAA,EACrB,CAAC,MAAM,SAAS,IAAI;AAAA,EACpB,CAAC,MAAM,SAAS,IAAI;AAAA,EACpB,CAAC,MAAM,YAAY,KAAK;AAAA,EACxB,CAAC,MAAM,eAAe,IAAI;AAAA,EAC1B,CAAC,MAAM,WAAW,IAAI;AAAA,EACtB,CAAC,MAAM,eAAe,IAAI;AAAA,EAC1B,CAAC,MAAM,WAAW,IAAI;AAAA,EACtB,CAAC,MAAM,UAAU,IAAI;AAAA,EACrB,CAAC,MAAM,UAAU,IAAI;AAAA,EACrB,CAAC,MAAM,WAAW,IAAI;AAAA,EACtB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,UAAU,IAAI;AAAA,EACrB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,YAAY,KAAK;AAAA,EACxB,CAAC,MAAM,WAAW,IAAI;AAAA,EACtB,CAAC,MAAM,WAAW,IAAI;AAAA,EACtB,CAAC,MAAM,YAAY,KAAK;AAAA,EACxB,CAAC,MAAM,UAAU,IAAI;AAAA,EACrB,CAAC,MAAM,WAAW,IAAI;AAAA,EACtB,CAAC,MAAM,UAAU,GAAG;AAAA,EACpB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,aAAa,KAAK;AAAA,EACzB,CAAC,MAAM,UAAU,KAAK;AAAA,EACtB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,UAAU,KAAK;AAAA,EACtB,CAAC,MAAM,YAAY,KAAK;AAAA,EACxB,CAAC,MAAM,UAAU,KAAK;AAAA,EACtB,CAAC,MAAM,SAAS,KAAK;AAAA,EACrB,CAAC,MAAM,cAAc,KAAK;AAAA,EAC1B,CAAC,MAAM,SAAS,IAAI;AAAA,EACpB,CAAC,MAAM,SAAS,IAAI;AAAA,EACpB,CAAC,MAAM,eAAe,IAAI;AAAA,EAC1B,CAAC,MAAM,aAAa,KAAK;AAAA,EACzB,CAAC,MAAM,UAAU,KAAK;AAAA,EACtB,CAAC,MAAM,SAAS,KAAK;AAAA,EACrB,CAAC,MAAM,aAAa,IAAI;AAAA,EACxB,CAAC,MAAM,YAAY,IAAI;AAAA,EACvB,CAAC,MAAM,aAAa,IAAI;AAAA,EACxB,CAAC,MAAM,YAAY,IAAI;AAAA,EACvB,CAAC,MAAM,WAAW,IAAI;AAAA,EACtB,CAAC,MAAM,eAAe,IAAI;AAAA,EAC1B,CAAC,MAAM,YAAY,IAAI;AAAA,EACvB,CAAC,MAAM,cAAc,KAAK;AAAA,EAC1B,CAAC,MAAM,aAAa,IAAI;AAAA,EACxB,CAAC,MAAM,SAAS,KAAK;AAAA,EACrB,CAAC,MAAM,WAAW,IAAI;AAAA,EACtB,CAAC,MAAM,YAAY,KAAK;AAAA,EACxB,CAAC,MAAM,QAAQ,KAAK;AAAA,EACpB,CAAC,MAAM,YAAY,KAAK;AAAA,EACxB,CAAC,MAAM,cAAc,GAAG;AAAA,EACxB,CAAC,MAAM,cAAc,KAAK;AAAA,EAC1B,CAAC,MAAM,wBAAwB,KAAK;AAAA,EACpC,CAAC,MAAM,gBAAgB,KAAK;AAAA,EAC5B,CAAC,MAAM,SAAS,KAAK;AAAA,EACrB,CAAC,MAAM,UAAU,KAAK;AAAA,EACtB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,QAAQ,KAAK;AAAA,EACpB,CAAC,MAAM,UAAU,KAAK;AAAA,EACtB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,UAAU,KAAK;AAAA,EACtB,CAAC,MAAM,QAAQ,KAAK;AAAA,EACpB,CAAC,MAAM,QAAQ,IAAI;AAAA,EACnB,CAAC,MAAM,SAAS,IAAI;AAAA,EACpB,CAAC,MAAM,gBAAgB,IAAI;AAAA,EAC3B,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,SAAS,KAAK;AAAA,EACrB,CAAC,MAAM,SAAS,KAAK;AAAA,EACrB,CAAC,MAAM,YAAY,KAAK;AAAA,EACxB,CAAC,MAAM,YAAY,KAAK;AAAA,EACxB,CAAC,MAAM,UAAU,KAAK;AAAA,EACtB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,UAAU,IAAI;AAAA,EACrB,CAAC,MAAM,UAAU,IAAI;AAAA,EACrB,CAAC,MAAM,aAAa,IAAI;AAAA,EACxB,CAAC,MAAM,SAAS,IAAI;AAAA,EACpB,CAAC,MAAM,YAAY,IAAI;AAAA,EACvB,CAAC,MAAM,QAAQ,IAAI;AAAA,EACnB,CAAC,MAAM,aAAa,IAAI;AAAA,EACxB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,YAAY,KAAK;AAAA,EACxB,CAAC,MAAM,WAAW,KAAK;AAAA,EACvB,CAAC,MAAM,cAAc,KAAK;AAAA,EAC1B,CAAC,MAAM,UAAU,KAAK;AAAA,EACtB,CAAC,MAAM,sBAAsB,GAAG;AAAA,EAChC,CAAC,MAAM,aAAa,KAAK;AAAA,EACzB,CAAC,MAAM,eAAe,IAAI;AAAA,EAC1B,CAAC,MAAM,QAAQ,KAAK;AACxB;AAEO,IAAM,YAAgC,IAAI,IAAI,CAAC,CAAC,MAAM,MAAM,IAAI,OAAO;AAAA,EAC1E;AAAA,EACA;AAAA,EACA;AACJ,EAAE;AAEK,IAAM,uBAAuB;AAE7B,SAAS,UAAU,MAAsB;AAC5C,SAAO,aAAa,IAAI;AAC5B;AAEO,SAAS,cAAc,MAAmC;AAC7D,SAAO,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAChD;AAOO,SAAS,oBAAoB,QAAqC;AACrE,aAAW,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG;AACzB,UAAM,SAAS,OAAO,MAAM,GAAG,GAAG;AAClC,QAAI,OAAO,SAAS,IAAK;AACzB,UAAM,QAAQ,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AACrD,QAAI,MAAO,QAAO;AAAA,EACtB;AACA,SAAO;AACX;AAGO,SAAS,0BAA+C;AAC3D,MAAI,OAAO,cAAc,YAAa,QAAO;AAC7C,QAAM,UAAU,UAAU,aAAa,CAAC,UAAU,QAAQ;AAC1D,aAAW,UAAU,SAAS;AAC1B,UAAM,QAAQ,eAAe,KAAK,UAAU,EAAE;AAC9C,QAAI,OAAO;AACP,YAAM,QAAQ,cAAc,MAAM,CAAC,CAAC;AACpC,UAAI,MAAO,QAAO;AAAA,IACtB;AAAA,EACJ;AACA,SAAO;AACX;;;AD5JY,cAiFI,YAjFJ;AAHZ,SAAS,cAAc;AACnB,SACI,oBAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACpE;AAAA,IAAC;AAAA;AAAA,MACG,GAAE;AAAA,MACF,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA;AAAA,EACnB,GACJ;AAER;AAaO,SAAS,cAAc,EAAE,SAAS,UAAU,SAAS,GAAuB;AAC/E,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,UAAU,OAAuB,IAAI;AAC3C,QAAM,YAAY,OAAyB,IAAI;AAC/C,QAAM,MAAM,MAAM;AAElB,YAAU,MAAM;AACZ,QAAI,CAAC,KAAM;AACX,cAAU,SAAS,MAAM;AACzB,UAAM,mBAAmB,CAAC,UAAsB;AAC5C,UAAI,QAAQ,WAAW,CAAC,QAAQ,QAAQ,SAAS,MAAM,MAAc,GAAG;AACpE,gBAAQ,KAAK;AAAA,MACjB;AAAA,IACJ;AACA,UAAM,YAAY,CAAC,UAAyB;AACxC,UAAI,MAAM,QAAQ,SAAU,SAAQ,KAAK;AAAA,IAC7C;AACA,aAAS,iBAAiB,aAAa,gBAAgB;AACvD,aAAS,iBAAiB,WAAW,SAAS;AAC9C,WAAO,MAAM;AACT,eAAS,oBAAoB,aAAa,gBAAgB;AAC1D,eAAS,oBAAoB,WAAW,SAAS;AAAA,IACrD;AAAA,EACJ,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,QAAM,WAAW,IACX,UAAU;AAAA,IACN,CAAC,MAAM,EAAE,KAAK,YAAY,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,SAAS,EAAE,QAAQ,OAAO,EAAE,CAAC;AAAA,EACnF,IACA;AAEN,QAAM,SAAS,GAAG,GAAG;AAErB,SACI,qBAAC,SAAI,KAAK,SAAS,OAAO,EAAE,UAAU,YAAY,YAAY,EAAE,GAC5D;AAAA;AAAA,MAAC;AAAA;AAAA,QACG,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,QAChC;AAAA,QACA,iBAAc;AAAA,QACd,iBAAe;AAAA,QACf,OAAO;AAAA,UACH,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,UAAU;AAAA,UACV,QAAQ,WAAW,gBAAgB;AAAA,QACvC;AAAA,QAEA;AAAA,8BAAC,UAAK,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,GAAI,oBAAU,QAAQ,IAAI,GAAE;AAAA,UACvE,qBAAC,UAAK,OAAO,EAAE,OAAO,0BAA0B,GAAG;AAAA;AAAA,YAAE,QAAQ;AAAA,aAAK;AAAA,UAClE,oBAAC,UAAK,OAAO,EAAE,OAAO,0BAA0B,GAC5C,8BAAC,eAAY,GACjB;AAAA;AAAA;AAAA,IACJ;AAAA,IAEC,OACG;AAAA,MAAC;AAAA;AAAA,QACG,MAAK;AAAA,QACL,OAAO;AAAA,UACH,UAAU;AAAA,UACV,KAAK;AAAA,UACL,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,WAAW;AAAA,UACX,UAAU;AAAA,QACd;AAAA,QAEA;AAAA;AAAA,YAAC;AAAA;AAAA,cACG,KAAK;AAAA,cACL,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,cACxC,WAAW,CAAC,MAAM;AACd,oBAAI,EAAE,QAAQ,WAAW,SAAS,CAAC,GAAG;AAClC,2BAAS,SAAS,CAAC,CAAC;AACpB,0BAAQ,KAAK;AACb,2BAAS,EAAE;AAAA,gBACf;AAAA,cACJ;AAAA,cACA,aAAY;AAAA,cACZ,iBAAe;AAAA,cACf,MAAK;AAAA,cACL,iBAAe;AAAA,cACf,OAAO;AAAA,gBACH,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,QAAQ;AAAA,gBACR,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,OAAO;AAAA,gBACP,UAAU;AAAA,gBACV,SAAS;AAAA,cACb;AAAA;AAAA,UACJ;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACG,IAAI;AAAA,cACJ,MAAK;AAAA,cACL,OAAO,EAAE,WAAW,KAAK,WAAW,QAAQ,SAAS,EAAE;AAAA,cAEtD,mBAAS,WAAW,IACjB;AAAA,gBAAC;AAAA;AAAA,kBACG,OAAO;AAAA,oBACH,SAAS;AAAA,oBACT,UAAU;AAAA,oBACV,OAAO;AAAA,kBACX;AAAA,kBACH;AAAA;AAAA,cAED,IAEA,SAAS,IAAI,CAAC,MAAM;AAChB,sBAAM,cAA6B;AAAA,kBAC/B,SAAS;AAAA,kBACT,OAAO;AAAA,kBACP,YAAY;AAAA,kBACZ,KAAK;AAAA,kBACL,SAAS;AAAA,kBACT,QAAQ;AAAA,kBACR,cAAc;AAAA,kBACd,YACI,EAAE,SAAS,QAAQ,OACb,2BACA;AAAA,kBACV,OAAO;AAAA,kBACP,UAAU;AAAA,kBACV,WAAW;AAAA,kBACX,QAAQ;AAAA,gBACZ;AACA,uBACI;AAAA,kBAAC;AAAA;AAAA,oBAEG,MAAK;AAAA,oBACL,MAAK;AAAA,oBACL,iBAAe,EAAE,SAAS,QAAQ;AAAA,oBAClC,SAAS,MAAM;AACX,+BAAS,CAAC;AACV,8BAAQ,KAAK;AACb,+BAAS,EAAE;AAAA,oBACf;AAAA,oBACA,OAAO;AAAA,oBAEP;AAAA,0CAAC,UAAK,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,GACtC,oBAAU,EAAE,IAAI,GACrB;AAAA,sBACA,oBAAC,UAAK,OAAO,EAAE,MAAM,EAAE,GAAI,YAAE,MAAK;AAAA,sBAClC,qBAAC,UAAK,OAAO,EAAE,OAAO,0BAA0B,GAAG;AAAA;AAAA,wBAC7C,EAAE;AAAA,yBACR;AAAA;AAAA;AAAA,kBAjBK,EAAE;AAAA,gBAkBX;AAAA,cAER,CAAC;AAAA;AAAA,UAET;AAAA;AAAA;AAAA,IACJ,IACA;AAAA,KACR;AAER;;;AEjMO,IAAM,iBAAiB;AAGvB,IAAM,oBAAoB;AAE1B,IAAM,qBAAqB;AAE3B,SAAS,YAAY,QAAyB;AACjD,QAAM,aAAa,UAAU;AAC7B,QAAM,cAAc,UAAU;AAE9B,QAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAMI,WAAW;AAAA,8CACa,WAAW;AAAA,gDACT,WAAW;AAAA;AAAA;AAAA;AAAA;AAMvD,QAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAMK,UAAU;AAAA,8CACc,UAAU;AAAA,gDACR,UAAU;AAAA;AAAA;AAAA;AAKtD,SAAO;AAAA,cACG,KAAK;AAAA;AAAA;AAAA;AAAA,0CAIuB,IAAI;AAAA;AAAA;AAAA,iCAGb,IAAI;AAAA;AAAA,kCAEH,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CvC;;;AHzBQ,SAQI,OAAAC,MARJ,QAAAC,aAAA;AAxDR,IAAM,cAAc;AAEpB,IAAM,iBAAiB;AAEvB,IAAM,sBAAsB;AAkD5B,SAAS,YAAY;AACjB,SACI,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACG,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,MAAK;AAAA,MACL,cAAW;AAAA,MAEX;AAAA,wBAAAD,KAAC,UAAK,GAAE,gCAA+B,MAAK,uBAAsB;AAAA,QAClE,gBAAAA,KAAC,UAAK,GAAE,oCAAmC,MAAK,uBAAsB;AAAA;AAAA;AAAA,EAC1E;AAER;AAiBO,SAAS,cACZ,OACS;AACT,QAAM;AAAA,IACF,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACP,IAAI;AAEJ,QAAM,MAAM,YAAqB,QAAQ;AACzC,QAAM,MAAME,OAAM;AAGlB,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAS,CAAC;AAC1C,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,KAAK;AACpD,QAAM,CAAC,MAAM,OAAO,IAAIA;AAAA,IACpB,mBAAmB,UAAU,UAAU;AAAA,EAC3C;AACA,QAAM,CAAC,SAAS,UAAU,IAAIA;AAAA,IAC1B,MAAO,kBAAkB,cAAc,cAAc,KAAM,cAAc,oBAAoB;AAAA,EACjG;AAGA,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,UAAS,EAAE;AACvD,QAAM,eAAe,GAAG,GAAG;AAC3B,QAAM,SAAS,GAAG,GAAG;AACrB,QAAM,WAAW,GAAG,GAAG;AAEvB,QAAM,kBAAkB,CAAC,SAAkB;AACvC,eAAW,IAAI;AACf,QAAI,cAAc,IAAI,KAAK,IAAI,GAAG,cAAc,EAAE;AAAA,EACtD;AAEA,QAAM,yBAAyB,CAAC,QAAgB;AAC5C,QAAI,SAAS,IAAI,QAAQ,OAAO,EAAE,EAAE,MAAM,GAAG,sBAAsB,CAAC;AACpE,QAAI,mBAAmB;AAOvB,QAAI,IAAI,KAAK,EAAE,WAAW,GAAG,GAAG;AAC5B,YAAM,QAAQ,oBAAoB,MAAM;AACxC,UAAI,SAAS,OAAO,WAAW,MAAM,IAAI,GAAG;AACxC,2BAAmB;AACnB,iBAAS,OAAO,MAAM,MAAM,KAAK,MAAM;AAAA,MAC3C;AAAA,IACJ;AACA,aAAS,OAAO,MAAM,GAAG,mBAAmB;AAC5C,QAAI,qBAAqB,QAAS,YAAW,gBAAgB;AAC7D,sBAAkB,MAAM;AACxB,QAAI,cAAc,IAAI,iBAAiB,IAAI,GAAG,MAAM,EAAE;AAAA,EAC1D;AAEA,QAAM,aAAa,CAAC,SAA4B;AAC5C,YAAQ,IAAI;AACZ,sBAAkB,EAAE;AACpB,QAAI,cAAc,EAAE;AAAA,EACxB;AAIA,EAAAC,WAAU,MAAM;AACZ,QAAI,OAAO,aAAa,YAAa;AACrC,QAAI,KAAK,SAAS,eAAe,cAAc;AAC/C,QAAI,CAAC,IAAI;AACL,WAAK,SAAS,cAAc,OAAO;AACnC,SAAG,KAAK;AACR,eAAS,KAAK,YAAY,EAAE;AAAA,IAChC;AACA,OAAG,cAAc,YAAY,WAAW;AAAA,EAC5C,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,mBAAmB,CAAC,UAAsC;AAC5D,UAAM,eAAe;AACrB,SAAK,IAAI,QAAQ;AAAA,EACrB;AAEA,QAAM,iBAAiB,CAAC,UAAsC;AAC1D,UAAM,eAAe;AACrB,SAAK,IAAI,OAAO;AAAA,EACpB;AAGA,EAAAA,WAAU,MAAM;AACZ,QAAI,IAAI,SAAS,SAAU,aAAY,cAAc;AAAA,EACzD,GAAG,CAAC,IAAI,IAAI,CAAC;AAEb,EAAAA,WAAU,MAAM;AACZ,QAAI,YAAY,EAAG;AACnB,UAAM,QAAQ,WAAW,MAAM,YAAY,CAAC,MAAM,IAAI,CAAC,GAAG,GAAI;AAC9D,WAAO,MAAM,aAAa,KAAK;AAAA,EACnC,GAAG,CAAC,QAAQ,CAAC;AAIb,EAAAA,WAAU,MAAM;AACZ,QAAI,IAAI,SAAS,YAAY,IAAI,KAAK,WAAW,eAAe,CAAC,IAAI,QAAQ;AACzE,WAAK,IAAI,OAAO;AAAA,IACpB;AAAA,EAEJ,GAAG,CAAC,IAAI,MAAM,IAAI,IAAI,CAAC;AAEvB,QAAM,QAAuB;AAAA,IACzB,SAAS;AAAA,IACT,eAAe;AAAA,IACf,KAAK;AAAA,IACL,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,OAAO;AAAA,EACX;AAEA,QAAM,QAAuB;AAAA,IACzB,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,EAChB;AAEA,QAAM,SAAwB;AAAA,IAC1B,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,QAAQ,IAAI,SAAS,gBAAgB;AAAA,IACrC,SAAS,IAAI,SAAS,MAAM;AAAA,IAC5B,OAAO;AAAA,IACP,YAAY;AAAA,EAChB;AAEA,QAAM,OAAsB;AAAA,IACxB,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ,IAAI,SAAS,gBAAgB;AAAA,IACrC,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,EACb;AAEA,QAAM,SAAwB;AAAA,IAC1B,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,OAAO;AAAA,EACX;AAEA,SACI,gBAAAH;AAAA,IAAC;AAAA;AAAA,MACG,WAAW,YAAY,aAAa,SAAS,KAAK;AAAA,MAClD,cAAY,UAAU,SAAS,SAAY;AAAA,MAC3C,OAAO;AAAA,QACH,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,OAAO;AAAA,QACP,YACI;AAAA,QACJ,YAAY;AAAA,QACZ,GAAG;AAAA,MACP;AAAA,MAEC;AAAA,iBAAS,OAAO,OAAQ,QAAQ,gBAAAD,KAAC,aAAU;AAAA,QAC5C,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACG,OAAO;AAAA,cACH,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,QAAQ;AAAA,YACZ;AAAA,YAEC,cAAI,SAAS,WAAW,cAAc;AAAA;AAAA,QAC3C;AAAA,QACC,IAAI,SAAS,WACV,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACG,OAAO;AAAA,cACH,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,OAAO;AAAA,cACP,QAAQ;AAAA,YACZ;AAAA,YACH;AAAA;AAAA,cACW;AAAA,cACR,gBAAAD,KAAC,UAAK,OAAO,EAAE,OAAO,oBAAoB,GAAI,cAAI,YAAW;AAAA,cAC5D;AAAA,cACD,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACG,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,SAAS,IAAI;AAAA,kBACb,UAAU,IAAI;AAAA,kBACd,OAAO,EAAE,GAAG,MAAM,UAAU,GAAG;AAAA,kBAClC;AAAA;AAAA,cAED;AAAA;AAAA;AAAA,QACJ,IACA,WACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACG,OAAO;AAAA,cACH,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,OAAO;AAAA,cACP,QAAQ;AAAA,YACZ;AAAA,YAEC;AAAA;AAAA,QACL,IACA;AAAA,QAGJ,gBAAAA,KAAC,SAAI,MAAK,UAAS,aAAU,UAAS,IAAI,UAAU,OAAO,EAAE,WAAW,GAAG,GACtE,cAAI,QACD,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACG,MAAK;AAAA,YACL,OAAO;AAAA,cACH,GAAG;AAAA,cACH,OAAO;AAAA,cACP,aAAa;AAAA,YACjB;AAAA,YAEC,cAAI;AAAA;AAAA,QACT,IACA,MACR;AAAA,QAEC,IAAI,SAAS,aACV,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACG,UAAU;AAAA,YACV,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,IAAI,WAAW,GAAG;AAAA,YAE1E;AAAA,8BAAAA,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,YAAY,gBAAgB,gBAAgB,GACnF;AAAA,gCAAAD,KAAC,WAAM,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,GAAG,SAAS,cACxC,8BAAoB,SAAS,UAAU,kBAAkB,kBAC9D;AAAA,gBACC,mBAAmB,SAChB,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACG,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS,MAAM,WAAW,SAAS,UAAU,UAAU,OAAO;AAAA,oBAC9D,UAAU,IAAI;AAAA,oBACd,OAAO,EAAE,GAAG,MAAM,UAAU,GAAG;AAAA,oBAE9B,mBAAS,UAAU,sBAAsB;AAAA;AAAA,gBAC9C,IACA;AAAA,iBACR;AAAA,cAEC,SAAS,UACN,gBAAAC;AAAA,gBAAC;AAAA;AAAA,kBACG,WAAU;AAAA,kBACV,OAAO;AAAA,oBACH,SAAS;AAAA,oBACT,YAAY;AAAA,oBACZ,QAAQ;AAAA,oBACR,cAAc;AAAA,oBACd,YAAY;AAAA,oBACZ,YAAY;AAAA,kBAChB;AAAA,kBAEA;AAAA,oCAAAD;AAAA,sBAAC;AAAA;AAAA,wBACG;AAAA,wBACA,UAAU;AAAA,wBACV,UAAU,IAAI;AAAA;AAAA,oBAClB;AAAA,oBACA,gBAAAA;AAAA,sBAAC;AAAA;AAAA,wBACG,eAAY;AAAA,wBACZ,OAAO;AAAA,0BACH,OAAO;AAAA,0BACP,QAAQ;AAAA,0BACR,YAAY;AAAA,wBAChB;AAAA;AAAA,oBACJ;AAAA,oBACA,gBAAAA;AAAA,sBAAC;AAAA;AAAA,wBACG,IAAI;AAAA,wBACJ,MAAK;AAAA,wBACL,WAAU;AAAA,wBACV,cAAa;AAAA,wBACb,OAAO;AAAA,wBACP,UAAU,CAAC,MAAM,uBAAuB,EAAE,OAAO,KAAK;AAAA,wBACtD,aAAY;AAAA,wBACZ,WAAS;AAAA,wBACT,UAAQ;AAAA,wBACR,oBAAkB;AAAA,wBAClB,OAAO;AAAA,0BACH,GAAG;AAAA,0BACH,MAAM;AAAA,0BACN,QAAQ;AAAA,0BACR,YAAY;AAAA,0BACZ,cAAc;AAAA,wBAClB;AAAA;AAAA,oBACJ;AAAA;AAAA;AAAA,cACJ,IAEA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACG,IAAI;AAAA,kBACJ,WAAU;AAAA,kBACV,MAAK;AAAA,kBACL,OAAO,IAAI;AAAA,kBACX,UAAU,CAAC,MAAM,IAAI,cAAc,EAAE,OAAO,KAAK;AAAA,kBACjD,aAAa,yBAAyB;AAAA,kBACtC,cAAa;AAAA,kBACb,WAAS;AAAA,kBACT,UAAQ;AAAA,kBACR,oBAAkB;AAAA,kBAClB,OAAO;AAAA;AAAA,cACX;AAAA,cAGJ,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACG,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,UAAU,IAAI;AAAA,kBACd,OAAO;AAAA,kBAEN,cAAI,YAAY,uBAAkB;AAAA;AAAA,cACvC;AAAA;AAAA;AAAA,QACJ,IAEA,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACG,UAAU;AAAA,YACV,OAAO,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,IAAI,WAAW,GAAG;AAAA,YAE1E;AAAA,8BAAAA,MAAC,WAAM,OAAO,EAAE,GAAG,OAAO,cAAc,GAAG,GAAG,SAAS,QAClD;AAAA;AAAA,gBAAY;AAAA,iBACjB;AAAA,cAQA,gBAAAA,MAAC,SAAI,OAAO,EAAE,UAAU,WAAW,GAC/B;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACG,IAAI;AAAA,oBACJ,WAAU;AAAA,oBACV,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAQ;AAAA,oBACR,cAAa;AAAA,oBACb,WAAW;AAAA,oBACX,OAAO,IAAI;AAAA,oBACX,UAAU,CAAC,MACP,IAAI;AAAA,sBACA,EAAE,OAAO,MAAM,QAAQ,OAAO,EAAE,EAAE,MAAM,GAAG,WAAW;AAAA,oBAC1D;AAAA,oBAEJ,SAAS,MAAM,eAAe,IAAI;AAAA,oBAClC,QAAQ,MAAM,eAAe,KAAK;AAAA,oBAClC,WAAS;AAAA,oBACT,UAAQ;AAAA,oBACR,oBAAkB;AAAA,oBAClB,OAAO;AAAA,sBACH,UAAU;AAAA,sBACV,OAAO;AAAA,sBACP,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,SAAS;AAAA,sBACT,YAAY;AAAA,sBACZ,QAAQ;AAAA,oBACZ;AAAA;AAAA,gBACJ;AAAA,gBACA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACG,WAAU;AAAA,oBACV,eAAY;AAAA,oBACZ,OAAO,EAAE,SAAS,QAAQ,KAAK,GAAG;AAAA,oBAEjC,gBAAM,KAAK,EAAE,QAAQ,YAAY,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM;AAC/C,4BAAM,QAAQ,IAAI,KAAK,CAAC;AACxB,4BAAM,WAAW,eAAe,MAAM,IAAI,KAAK;AAC/C,6BACI,gBAAAA;AAAA,wBAAC;AAAA;AAAA,0BAEG,eAAa;AAAA,0BACb,OAAO;AAAA,4BACH,MAAM;AAAA,4BACN,QAAQ;AAAA,4BACR,SAAS;AAAA,4BACT,YAAY;AAAA,4BACZ,gBAAgB;AAAA,4BAChB,UAAU;AAAA,4BACV,OAAO;AAAA,4BACP,cAAc,aACV,WAAW,wBAAwB,qBACvC;AAAA,4BACA,YAAY;AAAA,0BAChB;AAAA,0BAEC,oBAAU,WACP,gBAAAA;AAAA,4BAAC;AAAA;AAAA,8BACG,WAAU;AAAA,8BACV,OAAO;AAAA,gCACH,OAAO;AAAA,gCACP,QAAQ;AAAA,gCACR,YAAY;AAAA,8BAChB;AAAA;AAAA,0BACJ,IACA;AAAA;AAAA,wBAzBC;AAAA,sBA0BT;AAAA,oBAER,CAAC;AAAA;AAAA,gBACL;AAAA,iBACJ;AAAA,cACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACG,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,UAAU,IAAI,UAAU,IAAI,KAAK,SAAS;AAAA,kBAC1C,OAAO;AAAA,oBACH,GAAG;AAAA,oBACH,SACI,IAAI,UAAU,IAAI,KAAK,SAAS,cAAc,MAAM;AAAA,kBAC5D;AAAA,kBAEC,cAAI,cAAc,oBAAe;AAAA;AAAA,cACtC;AAAA,cACA,gBAAAA,KAAC,SAAI,OAAO,EAAE,WAAW,SAAS,GAC7B,qBAAW,IACR,gBAAAC;AAAA,gBAAC;AAAA;AAAA,kBACG,OAAO;AAAA,oBACH,UAAU;AAAA,oBACV,OAAO;AAAA,kBACX;AAAA,kBACH;AAAA;AAAA,oBACmB;AAAA,oBAAS;AAAA;AAAA;AAAA,cAC7B,IAEA,gBAAAD;AAAA,gBAAC;AAAA;AAAA,kBACG,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,SAAS,MAAM,KAAK,IAAI,OAAO;AAAA,kBAC/B,UAAU,IAAI;AAAA,kBACd,OAAO;AAAA,kBACV;AAAA;AAAA,cAED,GAER;AAAA;AAAA;AAAA,QACJ;AAAA,QAGH,eACG,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACG,OAAO;AAAA,cACH,QAAQ;AAAA,cACR,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,OAAO;AAAA,YACX;AAAA,YACH;AAAA;AAAA,cACc;AAAA,cACX,gBAAAD;AAAA,gBAAC;AAAA;AAAA,kBACG,MAAK;AAAA,kBACL,QAAO;AAAA,kBACP,KAAI;AAAA,kBACJ,WAAU;AAAA,kBACV,OAAO;AAAA,oBACH,SAAS;AAAA,oBACT,SAAS;AAAA,oBACT,cAAc;AAAA,oBACd,OAAO;AAAA,oBACP,YAAY;AAAA,oBACZ,gBAAgB;AAAA,oBAChB,YAAY;AAAA,kBAChB;AAAA,kBACH;AAAA;AAAA,cAED;AAAA;AAAA;AAAA,QACJ,IACA;AAAA;AAAA;AAAA,EACR;AAER;;;AIzkBA,eAAe,SACb,KACA,MACA,SACY;AACZ,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oBAAoB,GAAI,QAAQ,WAAW,CAAC,EAAG;AAAA,IAC1E,aAAa,QAAQ;AAAA,IACrB,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,UAAU,mBAAmB,SAAS,MAAM;AAChD,QAAI;AACF,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,gBAAU,KAAK,WAAW,KAAK,SAAS;AAAA,IAC1C,QAAQ;AAAA,IAER;AACA,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAMO,SAAS,oBACd,UAA+B,CAAC,GAIhC;AACA,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,YAAY,QAAQ,aAAa;AAEvC,SAAO;AAAA,IACL,YAAY,CAAC,eACX,SAA2B,YAAY,EAAE,WAAW,GAAG,OAAO;AAAA,IAChE,WAAW,CAAC,UACV,SAAkB,WAAW,OAAO,OAAO;AAAA,EAC/C;AACF;","names":["useEffect","useId","useState","jsx","jsxs","useId","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/use-sneek-otp.ts","../src/state.ts","../src/component.tsx","../src/country-picker.tsx","../src/countries.ts","../src/theme.ts","../src/fetch-handlers.ts"],"sourcesContent":["import { useCallback, useReducer } from 'react';\nimport {\n initialOtpState,\n otpReducer,\n toMessage,\n type RequestOtpResult,\n type SneekOtpState,\n} from './state';\n\n/**\n * Partner-supplied transport. These call the *partner's own backend*, which in\n * turn talks to the Sneek API with the secret server-side key. The browser\n * never sees a Sneek API key — that is the whole security model of this package.\n */\nexport interface SneekOtpHandlers<TResult = unknown> {\n /** Ask the partner backend to send an OTP to `identifier`. */\n requestOtp: (identifier: string) => Promise<RequestOtpResult>;\n /** Verify the code with the partner backend; resolve with the auth result. */\n verifyOtp: (input: { requestId: string; code: string }) => Promise<TResult>;\n /** Called after a successful verification with the partner's result. */\n onSuccess?: (result: TResult) => void;\n /** Called on any error (request or verify). */\n onError?: (error: unknown) => void;\n}\n\nexport interface UseSneekOtp extends SneekOtpState {\n setIdentifier: (value: string) => void;\n setCode: (value: string) => void;\n /** Submit the identify step — triggers `requestOtp`. */\n sendOtp: () => Promise<void>;\n /** Submit the verify step — triggers `verifyOtp`. */\n verify: () => Promise<void>;\n /** Go back to the identify screen (e.g. \"use a different email\"). */\n back: () => void;\n /** Re-send the OTP to the same identifier. */\n resend: () => Promise<void>;\n /** Convenience booleans. */\n isSending: boolean;\n isVerifying: boolean;\n isBusy: boolean;\n}\n\nconst DEFAULT_REQUEST_ERROR = 'Could not send the code. Please try again.';\nconst DEFAULT_VERIFY_ERROR = 'That code was not correct. Please try again.';\n\n/**\n * Headless hook implementing the passwordless OTP login flow. Bring your own\n * markup, or use the {@link SneekOtpLogin} component for a styled default.\n */\nexport function useSneekOtp<TResult = unknown>(\n handlers: SneekOtpHandlers<TResult>,\n): UseSneekOtp {\n const [state, dispatch] = useReducer(otpReducer, initialOtpState);\n\n const { requestOtp, verifyOtp, onSuccess, onError } = handlers;\n\n const setIdentifier = useCallback((value: string) => {\n dispatch({ type: 'set_identifier', value });\n }, []);\n\n const setCode = useCallback((value: string) => {\n dispatch({ type: 'set_code', value });\n }, []);\n\n const runRequest = useCallback(\n async (identifier: string) => {\n const trimmed = identifier.trim();\n if (!trimmed) {\n dispatch({ type: 'request_error', message: 'Enter your email or mobile number.' });\n return;\n }\n dispatch({ type: 'request_start' });\n try {\n const result = await requestOtp(trimmed);\n dispatch({ type: 'request_success', result });\n } catch (error) {\n dispatch({ type: 'request_error', message: toMessage(error, DEFAULT_REQUEST_ERROR) });\n onError?.(error);\n }\n },\n [requestOtp, onError],\n );\n\n const sendOtp = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);\n\n const resend = useCallback(() => runRequest(state.identifier), [runRequest, state.identifier]);\n\n const verify = useCallback(async () => {\n const code = state.code.trim();\n if (!code) {\n dispatch({ type: 'verify_error', message: 'Enter the code you received.' });\n return;\n }\n dispatch({ type: 'verify_start' });\n try {\n const result = await verifyOtp({ requestId: state.requestId, code });\n onSuccess?.(result);\n } catch (error) {\n dispatch({ type: 'verify_error', message: toMessage(error, DEFAULT_VERIFY_ERROR) });\n onError?.(error);\n }\n }, [verifyOtp, state.code, state.requestId, onSuccess, onError]);\n\n const back = useCallback(() => {\n dispatch({ type: 'back_to_identify' });\n }, []);\n\n return {\n ...state,\n setIdentifier,\n setCode,\n sendOtp,\n verify,\n back,\n resend,\n isSending: state.status === 'sending',\n isVerifying: state.status === 'verifying',\n isBusy: state.status !== 'idle',\n };\n}\n","/**\n * Framework-agnostic state machine for the Sneek passwordless OTP flow.\n *\n * Kept free of React so it can be unit-tested in isolation and reused by other\n * front-end bindings later (Vue/Svelte). The hook in `use-sneek-otp.ts` is a\n * thin wrapper around this reducer.\n */\n\nexport type SneekChannel = 'sms' | 'whatsapp' | 'email';\n\n/** Which screen of the two-step flow is showing. */\nexport type SneekOtpStep = 'identify' | 'verify';\n\n/** Async lifecycle for the in-flight request. */\nexport type SneekOtpStatus = 'idle' | 'sending' | 'verifying';\n\nexport interface SneekOtpState {\n step: SneekOtpStep;\n status: SneekOtpStatus;\n /** The email / mobile / username the user typed. */\n identifier: string;\n /** The OTP code the user typed on the verify screen. */\n code: string;\n /** Opaque id returned by the partner backend, replayed on verify. */\n requestId: string;\n /** Channels the OTP was actually delivered over. */\n channels: SneekChannel[];\n /** Seconds until the OTP expires (from the request response). */\n expiresInSeconds: number;\n /** User-facing error message, or null. */\n error: string | null;\n}\n\nexport const initialOtpState: SneekOtpState = {\n step: 'identify',\n status: 'idle',\n identifier: '',\n code: '',\n requestId: '',\n channels: [],\n expiresInSeconds: 0,\n error: null,\n};\n\nexport interface RequestOtpResult {\n requestId: string;\n channels?: SneekChannel[];\n expiresInSeconds?: number;\n}\n\nexport type SneekOtpAction =\n | { type: 'set_identifier'; value: string }\n | { type: 'set_code'; value: string }\n | { type: 'request_start' }\n | { type: 'request_success'; result: RequestOtpResult }\n | { type: 'request_error'; message: string }\n | { type: 'verify_start' }\n | { type: 'verify_error'; message: string }\n | { type: 'reset' }\n | { type: 'back_to_identify' };\n\nconst isBusy = (status: SneekOtpStatus): boolean => status !== 'idle';\n\nexport function otpReducer(\n state: SneekOtpState,\n action: SneekOtpAction,\n): SneekOtpState {\n switch (action.type) {\n case 'set_identifier':\n return { ...state, identifier: action.value, error: null };\n\n case 'set_code':\n return { ...state, code: action.value, error: null };\n\n case 'request_start':\n // Guard against double submits while a request is already in flight.\n if (isBusy(state.status)) return state;\n return { ...state, status: 'sending', error: null };\n\n case 'request_success':\n return {\n ...state,\n step: 'verify',\n status: 'idle',\n code: '',\n requestId: action.result.requestId,\n channels: action.result.channels ?? [],\n expiresInSeconds: action.result.expiresInSeconds ?? 0,\n error: null,\n };\n\n case 'request_error':\n return { ...state, status: 'idle', error: action.message };\n\n case 'verify_start':\n if (isBusy(state.status)) return state;\n return { ...state, status: 'verifying', error: null };\n\n case 'verify_error':\n return { ...state, status: 'idle', error: action.message };\n\n case 'back_to_identify':\n return {\n ...state,\n step: 'identify',\n status: 'idle',\n code: '',\n requestId: '',\n channels: [],\n expiresInSeconds: 0,\n error: null,\n };\n\n case 'reset':\n return { ...initialOtpState };\n\n default:\n return state;\n }\n}\n\nconst CHANNEL_LABELS: Record<SneekChannel, string> = {\n sms: 'SMS',\n whatsapp: 'WhatsApp',\n email: 'email',\n};\n\n/** \"SMS, WhatsApp\" — human label for the channels an OTP was sent over. */\nexport function formatChannels(channels: SneekChannel[]): string {\n return channels.map((c) => CHANNEL_LABELS[c] ?? c).join(', ');\n}\n\n/** Normalize any thrown value into a user-facing message. */\nexport function toMessage(error: unknown, fallback: string): string {\n if (error instanceof Error && error.message) return error.message;\n if (typeof error === 'string' && error) return error;\n return fallback;\n}\n","import {\n useEffect,\n useId,\n useState,\n type CSSProperties,\n type FormEvent,\n type ReactNode,\n} from 'react';\n\nimport { CountryPicker } from './country-picker';\nimport {\n countryByDialPrefix,\n countryByIso2,\n DEFAULT_COUNTRY_ISO2,\n type Country,\n} from './countries';\nimport { buildStyles, SNEEK_STYLE_ID } from './theme';\nimport { useSneekOtp, type SneekOtpHandlers } from './use-sneek-otp';\n\nexport type SneekTheme = 'auto' | 'light' | 'dark';\nexport type SneekIdentifierMode = 'phone' | 'email' | 'both';\n\n/** Digits in a Sneek code. */\nconst CODE_LENGTH = 6;\n/** Seconds before \"Resend code\" becomes tappable again. */\nconst RESEND_SECONDS = 30;\n/** E.164 allows 15 digits total; this is the remainder after a 3-digit dial code. */\nconst MAX_NATIONAL_DIGITS = 12;\n\nexport interface SneekOtpLoginProps<TResult = unknown>\n extends SneekOtpHandlers<TResult> {\n /** Heading above the form. @default 'Sign in' */\n title?: string;\n /** Heading once the code has been sent. @default 'Enter the code' */\n verifyTitle?: string;\n /** Sub-heading. Pass `null` to remove it. */\n subtitle?: ReactNode;\n /**\n * Which identifiers a visitor can sign in with. `'both'` starts on phone\n * with a country chip and offers a link to switch to email.\n * @default 'both'\n */\n identifierMode?: SneekIdentifierMode;\n /**\n * ISO 3166-1 alpha-2 country to preselect for the phone chip.\n * @default 'IN' (India)\n */\n defaultCountry?: string;\n /** Overrides the auto label (\"Mobile number\" / \"Email address\"). */\n identifierLabel?: string;\n /** Overrides the auto placeholder. Only used in email mode. */\n identifierPlaceholder?: string;\n /**\n * Colour scheme. `auto` follows the visitor's system setting.\n * @default 'auto'\n */\n theme?: SneekTheme;\n /**\n * Override the single accent colour. Leave unset to use Sneek orange,\n * which is tuned per mode for contrast.\n */\n accentColor?: string;\n /**\n * Replaces the Sneek mark above the title (which sits in a rounded,\n * bordered box by default). Pass `null` to remove it entirely.\n */\n logo?: ReactNode;\n /** Show the \"Secured by Sneek\" line under the form. @default true */\n showBranding?: boolean;\n /** Style overrides for the outer card. */\n style?: CSSProperties;\n /** Extra class on the outer card. */\n className?: string;\n}\n\n/**\n * Sneek mark: two triangles offset on a diagonal — one pointing up on the\n * right, one pointing down on the left. Traced from the brand asset so the\n * package needs no image file and no CDN.\n */\nfunction SneekMark() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 32 32\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Sneek\"\n >\n <path d=\"M21.3 1 29.3 16H13.3L21.3 1Z\" fill=\"var(--sneek-accent)\" />\n <path d=\"M2.7 17.5H18.7L10.7 31 2.7 17.5Z\" fill=\"var(--sneek-accent)\" />\n </svg>\n );\n}\n\n/**\n * The default mark sits in a rounded, bordered box — matching how the mark\n * is framed everywhere else in the product (app icon, dashboard nav) — rather\n * than floating bare on the card.\n */\nfunction SneekMarkBox() {\n return (\n <div\n style={{\n display: 'grid',\n placeItems: 'center',\n width: 44,\n height: 44,\n borderRadius: 16,\n border: '1px solid var(--sneek-border)',\n background: 'var(--sneek-surface)',\n }}\n >\n <SneekMark />\n </div>\n );\n}\n\n/**\n * Drop-in passwordless login card.\n *\n * The component never receives a Sneek API key — it calls the handlers you\n * supply, which talk to your own backend. See `createFetchHandlers` for the\n * common case.\n *\n * @example\n * ```tsx\n * <SneekOtpLogin\n * {...createFetchHandlers({ baseUrl: '/api/auth' })}\n * onSuccess={(session) => router.push('/app')}\n * />\n * ```\n */\nexport function SneekOtpLogin<TResult = unknown>(\n props: SneekOtpLoginProps<TResult>,\n): ReactNode {\n const {\n title = 'Sign in',\n verifyTitle = 'Enter the code',\n subtitle = 'Enter your email or phone. We will send you a code.',\n identifierMode = 'both',\n defaultCountry,\n identifierLabel,\n identifierPlaceholder,\n theme = 'auto',\n accentColor,\n logo,\n showBranding = true,\n style,\n className,\n ...handlers\n } = props;\n\n const otp = useSneekOtp<TResult>(handlers);\n const uid = useId();\n // Countdown before resend re-enables. Instant resend is both poor feedback\n // and an easy way to burn someone's SMS quota.\n const [resendIn, setResendIn] = useState(0);\n const [codeFocused, setCodeFocused] = useState(false);\n const [mode, setMode] = useState<'phone' | 'email'>(\n identifierMode === 'email' ? 'email' : 'phone',\n );\n const [country, setCountry] = useState<Country>(\n () => (defaultCountry && countryByIso2(defaultCountry)) || countryByIso2(DEFAULT_COUNTRY_ISO2)!,\n );\n // The digits typed into the phone field, separate from `otp.identifier`\n // (which holds the composed +<dial><digits> value actually submitted).\n const [nationalNumber, setNationalNumber] = useState('');\n const identifierId = `${uid}-identifier`;\n const codeId = `${uid}-code`;\n const statusId = `${uid}-status`;\n\n const onCountrySelect = (next: Country) => {\n setCountry(next);\n otp.setIdentifier(`+${next.dial}${nationalNumber}`);\n };\n\n const onNationalNumberChange = (raw: string) => {\n let digits = raw.replace(/\\D/g, '').slice(0, MAX_NATIONAL_DIGITS + 3);\n let effectiveCountry = country;\n // Only re-detect off an explicit leading '+' — a real, unambiguous\n // signal that this is a full international number. A plain jump in\n // digit count (paste, or a phone-autofill suggestion) is NOT enough:\n // most 10-digit local numbers coincidentally start with digits that\n // match *some* country's dial code, which would otherwise silently\n // truncate a legitimate local number.\n if (raw.trim().startsWith('+')) {\n const guess = countryByDialPrefix(digits);\n if (guess && digits.startsWith(guess.dial)) {\n effectiveCountry = guess;\n digits = digits.slice(guess.dial.length);\n }\n }\n digits = digits.slice(0, MAX_NATIONAL_DIGITS);\n if (effectiveCountry !== country) setCountry(effectiveCountry);\n setNationalNumber(digits);\n otp.setIdentifier(`+${effectiveCountry.dial}${digits}`);\n };\n\n const switchMode = (next: 'phone' | 'email') => {\n setMode(next);\n setNationalNumber('');\n otp.setIdentifier('');\n };\n\n // One <style> element for the whole page, regardless of how many cards\n // render. Injected on mount so the package stays SSR-safe.\n useEffect(() => {\n if (typeof document === 'undefined') return;\n let el = document.getElementById(SNEEK_STYLE_ID);\n if (!el) {\n el = document.createElement('style');\n el.id = SNEEK_STYLE_ID;\n document.head.appendChild(el);\n }\n el.textContent = buildStyles(accentColor);\n }, [accentColor]);\n\n const onIdentifySubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void otp.sendOtp();\n };\n\n const onVerifySubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void otp.verify();\n };\n\n // Start the cooldown whenever a code goes out.\n useEffect(() => {\n if (otp.step === 'verify') setResendIn(RESEND_SECONDS);\n }, [otp.step]);\n\n useEffect(() => {\n if (resendIn <= 0) return;\n const timer = setTimeout(() => setResendIn((n) => n - 1), 1000);\n return () => clearTimeout(timer);\n }, [resendIn]);\n\n // Submit as soon as the code looks complete — nobody should have to reach\n // for a button after typing the last digit.\n useEffect(() => {\n if (otp.step === 'verify' && otp.code.length === CODE_LENGTH && !otp.isBusy) {\n void otp.verify();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [otp.code, otp.step]);\n\n const label: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n };\n\n const input: CSSProperties = {\n padding: '12px 14px',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n color: 'var(--sneek-text)',\n fontSize: 15,\n width: '100%',\n outline: 'none',\n transition: 'border-color 200ms var(--sneek-ease)',\n };\n\n const button: CSSProperties = {\n padding: '12px 18px',\n border: 'none',\n borderRadius: 9999,\n background: 'var(--sneek-accent)',\n color: 'var(--sneek-accent-contrast)',\n fontSize: 15,\n fontWeight: 500,\n cursor: otp.isBusy ? 'not-allowed' : 'pointer',\n opacity: otp.isBusy ? 0.6 : 1,\n width: '100%',\n transition: 'filter 200ms var(--sneek-ease), opacity 200ms var(--sneek-ease)',\n };\n\n const link: CSSProperties = {\n border: 'none',\n background: 'transparent',\n color: 'var(--sneek-accent)',\n cursor: otp.isBusy ? 'not-allowed' : 'pointer',\n font: 'inherit',\n fontSize: 14,\n padding: 0,\n };\n\n const notice: CSSProperties = {\n padding: '10px 12px',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n border: '1px solid var(--sneek-border)',\n fontSize: 14,\n color: 'var(--sneek-text-muted)',\n };\n\n return (\n <div\n className={className ? `sneek-otp ${className}` : 'sneek-otp'}\n data-theme={theme === 'auto' ? undefined : theme}\n style={{\n maxWidth: 400,\n margin: '0 auto',\n padding: 24,\n border: '1px solid var(--sneek-border)',\n borderRadius: 16,\n background: 'var(--sneek-surface)',\n boxShadow: 'var(--sneek-shadow)',\n color: 'var(--sneek-text)',\n fontFamily:\n 'Inter, ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n lineHeight: 1.5,\n ...style,\n }}\n >\n {logo === null ? null : (logo ?? <SneekMarkBox />)}\n <h2\n style={{\n fontSize: 21,\n lineHeight: '28px',\n fontWeight: 500,\n letterSpacing: '-0.01em',\n margin: '16px 0 0',\n }}\n >\n {otp.step === 'verify' ? verifyTitle : title}\n </h2>\n {otp.step === 'verify' ? (\n <p\n style={{\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n margin: '8px 0 0',\n }}\n >\n Sent to{' '}\n <span style={{ color: 'var(--sneek-text)' }}>{otp.identifier}</span>\n {' · '}\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={otp.back}\n disabled={otp.isBusy}\n style={{ ...link, fontSize: 14 }}\n >\n Change\n </button>\n </p>\n ) : subtitle ? (\n <p\n style={{\n fontSize: 14,\n lineHeight: '20px',\n color: 'var(--sneek-text-muted)',\n margin: '8px 0 0',\n }}\n >\n {subtitle}\n </p>\n ) : null}\n\n {/* Errors and channel notices are announced, not just shown. */}\n <div role=\"status\" aria-live=\"polite\" id={statusId} style={{ marginTop: 32 }}>\n {otp.error ? (\n <div\n role=\"alert\"\n style={{\n ...notice,\n color: 'var(--sneek-danger)',\n borderColor: 'var(--sneek-danger)',\n }}\n >\n {otp.error}\n </div>\n ) : null}\n </div>\n\n {otp.step === 'identify' ? (\n <form\n onSubmit={onIdentifySubmit}\n style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 16 }}\n >\n <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>\n <label style={{ ...label, gap: 0 }} htmlFor={identifierId}>\n {identifierLabel ?? (mode === 'phone' ? 'Mobile number' : 'Email address')}\n </label>\n {identifierMode === 'both' ? (\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={() => switchMode(mode === 'phone' ? 'email' : 'phone')}\n disabled={otp.isBusy}\n style={{ ...link, fontSize: 13 }}\n >\n {mode === 'phone' ? 'Use email instead' : 'Use phone instead'}\n </button>\n ) : null}\n </div>\n\n {mode === 'phone' ? (\n <div\n className=\"sneek-otp-phone-field\"\n style={{\n display: 'flex',\n alignItems: 'stretch',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface-2)',\n transition: 'border-color 200ms var(--sneek-ease)',\n }}\n >\n <CountryPicker\n country={country}\n onSelect={onCountrySelect}\n disabled={otp.isBusy}\n />\n <span\n aria-hidden=\"true\"\n style={{\n width: 1,\n margin: '9px 0',\n background: 'var(--sneek-border)',\n }}\n />\n <input\n id={identifierId}\n type=\"tel\"\n inputMode=\"tel\"\n autoComplete=\"tel-national\"\n value={nationalNumber}\n onChange={(e) => onNationalNumberChange(e.target.value)}\n placeholder=\"Mobile number\"\n autoFocus\n required\n aria-describedby={statusId}\n style={{\n ...input,\n flex: 1,\n border: 'none',\n background: 'transparent',\n borderRadius: 0,\n }}\n />\n </div>\n ) : (\n <input\n id={identifierId}\n className=\"sneek-otp-input\"\n type=\"email\"\n value={otp.identifier}\n onChange={(e) => otp.setIdentifier(e.target.value)}\n placeholder={identifierPlaceholder ?? 'you@company.com'}\n autoComplete=\"email\"\n autoFocus\n required\n aria-describedby={statusId}\n style={input}\n />\n )}\n\n <button\n type=\"submit\"\n className=\"sneek-otp-button\"\n disabled={otp.isBusy}\n style={button}\n >\n {otp.isSending ? 'Sending code…' : 'Send code'}\n </button>\n </form>\n ) : (\n <form\n onSubmit={onVerifySubmit}\n style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 16 }}\n >\n <label style={{ ...label, marginBottom: -8 }} htmlFor={codeId}>\n {CODE_LENGTH}-digit code\n </label>\n {/*\n * One real input captures keystrokes — paste, backspace and\n * SMS/email autofill all keep working, which six separate\n * `<input>`s make surprisingly easy to break. It sits over\n * the visible cells, transparent; the cells below just\n * mirror its value.\n */}\n <div style={{ position: 'relative' }}>\n <input\n id={codeId}\n className=\"sneek-otp-code-input\"\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n autoComplete=\"one-time-code\"\n maxLength={CODE_LENGTH}\n value={otp.code}\n onChange={(e) =>\n otp.setCode(\n e.target.value.replace(/\\D/g, '').slice(0, CODE_LENGTH),\n )\n }\n onFocus={() => setCodeFocused(true)}\n onBlur={() => setCodeFocused(false)}\n autoFocus\n required\n aria-describedby={statusId}\n style={{\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n opacity: 0,\n caretColor: 'transparent',\n cursor: 'text',\n }}\n />\n <div\n className=\"sneek-otp-code-cells\"\n aria-hidden=\"true\"\n style={{ display: 'flex', gap: 10 }}\n >\n {Array.from({ length: CODE_LENGTH }).map((_, i) => {\n const digit = otp.code[i];\n const isActive = codeFocused && i === otp.code.length;\n return (\n <div\n key={i}\n data-active={isActive}\n style={{\n flex: 1,\n height: 44,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 22,\n color: 'var(--sneek-text)',\n borderBottom: `2px solid ${\n isActive ? 'var(--sneek-accent)' : 'var(--sneek-border)'\n }`,\n transition: 'border-color 200ms var(--sneek-ease)',\n }}\n >\n {digit ?? (isActive ? (\n <span\n className=\"sneek-otp-caret\"\n style={{\n width: 2,\n height: 22,\n background: 'var(--sneek-accent)',\n }}\n />\n ) : null)}\n </div>\n );\n })}\n </div>\n </div>\n <button\n type=\"submit\"\n className=\"sneek-otp-button\"\n disabled={otp.isBusy || otp.code.length < CODE_LENGTH}\n style={{\n ...button,\n opacity:\n otp.isBusy || otp.code.length < CODE_LENGTH ? 0.6 : 1,\n }}\n >\n {otp.isVerifying ? 'Verifying…' : 'Verify'}\n </button>\n <div style={{ textAlign: 'center' }}>\n {resendIn > 0 ? (\n <span\n style={{\n fontSize: 14,\n color: 'var(--sneek-text-muted)',\n }}\n >\n Resend code in {resendIn}s\n </span>\n ) : (\n <button\n type=\"button\"\n className=\"sneek-otp-link\"\n onClick={() => void otp.resend()}\n disabled={otp.isBusy}\n style={link}\n >\n Resend code\n </button>\n )}\n </div>\n </form>\n )}\n\n {showBranding ? (\n <p\n style={{\n margin: '32px 0 0',\n textAlign: 'center',\n fontSize: 12,\n lineHeight: '16px',\n color: 'var(--sneek-text-muted)',\n }}\n >\n Secured by{' '}\n <a\n href=\"https://sneek.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"sneek-otp-brand-link\"\n style={{\n display: 'inline-block',\n padding: '0 5px',\n borderRadius: 6,\n color: 'var(--sneek-accent)',\n fontWeight: 500,\n textDecoration: 'none',\n transition: 'box-shadow 200ms var(--sneek-ease)',\n }}\n >\n Sneek\n </a>\n </p>\n ) : null}\n </div>\n );\n}\n","import {\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n} from 'react';\n\nimport { COUNTRIES, flagEmoji, type Country } from './countries';\n\nfunction ChevronDown() {\n return (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M2 3.5 5 6.5 8 3.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\nexport interface CountryPickerProps {\n country: Country;\n onSelect: (country: Country) => void;\n disabled?: boolean;\n}\n\n/**\n * The flag + dial-code chip in front of the phone number field. Opens a\n * searchable list on click; the number field itself keeps auto-detecting\n * from pasted content independently of this — this is the manual path.\n */\nexport function CountryPicker({ country, onSelect, disabled }: CountryPickerProps) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const rootRef = useRef<HTMLDivElement>(null);\n const searchRef = useRef<HTMLInputElement>(null);\n const uid = useId();\n\n useEffect(() => {\n if (!open) return;\n searchRef.current?.focus();\n const onDocPointerDown = (event: MouseEvent) => {\n if (rootRef.current && !rootRef.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false);\n };\n document.addEventListener('mousedown', onDocPointerDown);\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('mousedown', onDocPointerDown);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [open]);\n\n const q = query.trim().toLowerCase();\n const filtered = q\n ? COUNTRIES.filter(\n (c) => c.name.toLowerCase().includes(q) || c.dial.includes(q.replace(/^\\+/, '')),\n )\n : COUNTRIES;\n\n const listId = `${uid}-country-list`;\n\n return (\n <div ref={rootRef} style={{ position: 'relative', flexShrink: 0 }}>\n <button\n type=\"button\"\n className=\"sneek-otp-country-chip\"\n onClick={() => setOpen((o) => !o)}\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n height: '100%',\n padding: '0 10px 0 14px',\n border: 'none',\n borderRadius: '12px 0 0 12px',\n background: 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 15,\n cursor: disabled ? 'not-allowed' : 'pointer',\n }}\n >\n <span style={{ fontSize: 18, lineHeight: 1 }}>{flagEmoji(country.iso2)}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>+{country.dial}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>\n <ChevronDown />\n </span>\n </button>\n\n {open ? (\n <div\n role=\"presentation\"\n style={{\n position: 'absolute',\n top: 'calc(100% + 6px)',\n left: 0,\n zIndex: 10,\n width: 260,\n maxWidth: '80vw',\n border: '1px solid var(--sneek-border)',\n borderRadius: 12,\n background: 'var(--sneek-surface)',\n boxShadow: 'var(--sneek-shadow), 0 8px 24px rgb(0 0 0 / 0.12)',\n overflow: 'hidden',\n }}\n >\n <input\n ref={searchRef}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && filtered[0]) {\n onSelect(filtered[0]);\n setOpen(false);\n setQuery('');\n }\n }}\n placeholder=\"Search country or code\"\n aria-controls={listId}\n role=\"combobox\"\n aria-expanded={open}\n style={{\n width: '100%',\n padding: '10px 12px',\n border: 'none',\n borderBottom: '1px solid var(--sneek-border)',\n background: 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 14,\n outline: 'none',\n }}\n />\n <div\n id={listId}\n role=\"listbox\"\n style={{ maxHeight: 240, overflowY: 'auto', padding: 6 }}\n >\n {filtered.length === 0 ? (\n <p\n style={{\n padding: '8px 10px',\n fontSize: 13,\n color: 'var(--sneek-text-muted)',\n }}\n >\n No match.\n </p>\n ) : (\n filtered.map((c) => {\n const optionStyle: CSSProperties = {\n display: 'flex',\n width: '100%',\n alignItems: 'center',\n gap: 10,\n padding: '8px 10px',\n border: 'none',\n borderRadius: 8,\n background:\n c.iso2 === country.iso2\n ? 'var(--sneek-surface-2)'\n : 'transparent',\n color: 'var(--sneek-text)',\n fontSize: 14,\n textAlign: 'left',\n cursor: 'pointer',\n };\n return (\n <button\n key={c.iso2}\n type=\"button\"\n role=\"option\"\n aria-selected={c.iso2 === country.iso2}\n onClick={() => {\n onSelect(c);\n setOpen(false);\n setQuery('');\n }}\n style={optionStyle}\n >\n <span style={{ fontSize: 17, lineHeight: 1 }}>\n {flagEmoji(c.iso2)}\n </span>\n <span style={{ flex: 1 }}>{c.name}</span>\n <span style={{ color: 'var(--sneek-text-muted)' }}>\n +{c.dial}\n </span>\n </button>\n );\n })\n )}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * Country calling codes for the phone-mode chip in the identify step.\n *\n * Flags are computed from the ISO 3166-1 alpha-2 code (two regional-indicator\n * codepoints) rather than hand-typed emoji, so there is no chance of a flag\n * silently drifting from its country. Where a dial code is shared by several\n * territories (+1, +7, +44, +61...), the first entry is the one auto-detect\n * and the default resolve to — the largest or best-known user of that code.\n */\nexport interface Country {\n iso2: string;\n name: string;\n dial: string;\n}\n\nfunction flagFromIso2(iso2: string): string {\n const A = 0x1f1e6;\n const codePoints = [...iso2.toUpperCase()].map((c) => A + (c.charCodeAt(0) - 65));\n return String.fromCodePoint(...codePoints);\n}\n\n/** [iso2, name, dial code without '+'] — ordered so shared-code lookups hit the expected country first. */\nconst RAW: [string, string, string][] = [\n ['US', 'United States', '1'],\n ['CA', 'Canada', '1'],\n ['GB', 'United Kingdom', '44'],\n ['IN', 'India', '91'],\n ['AU', 'Australia', '61'],\n ['DE', 'Germany', '49'],\n ['FR', 'France', '33'],\n ['IT', 'Italy', '39'],\n ['ES', 'Spain', '34'],\n ['PT', 'Portugal', '351'],\n ['NL', 'Netherlands', '31'],\n ['BE', 'Belgium', '32'],\n ['CH', 'Switzerland', '41'],\n ['AT', 'Austria', '43'],\n ['SE', 'Sweden', '46'],\n ['NO', 'Norway', '47'],\n ['DK', 'Denmark', '45'],\n ['FI', 'Finland', '358'],\n ['IE', 'Ireland', '353'],\n ['IS', 'Iceland', '354'],\n ['PL', 'Poland', '48'],\n ['CZ', 'Czechia', '420'],\n ['SK', 'Slovakia', '421'],\n ['HU', 'Hungary', '36'],\n ['RO', 'Romania', '40'],\n ['BG', 'Bulgaria', '359'],\n ['GR', 'Greece', '30'],\n ['TR', 'Turkiye', '90'],\n ['RU', 'Russia', '7'],\n ['UA', 'Ukraine', '380'],\n ['BY', 'Belarus', '375'],\n ['LT', 'Lithuania', '370'],\n ['LV', 'Latvia', '371'],\n ['EE', 'Estonia', '372'],\n ['HR', 'Croatia', '385'],\n ['RS', 'Serbia', '381'],\n ['SI', 'Slovenia', '386'],\n ['CY', 'Cyprus', '357'],\n ['MT', 'Malta', '356'],\n ['LU', 'Luxembourg', '352'],\n ['CN', 'China', '86'],\n ['JP', 'Japan', '81'],\n ['KR', 'South Korea', '82'],\n ['HK', 'Hong Kong', '852'],\n ['TW', 'Taiwan', '886'],\n ['MO', 'Macau', '853'],\n ['SG', 'Singapore', '65'],\n ['MY', 'Malaysia', '60'],\n ['ID', 'Indonesia', '62'],\n ['TH', 'Thailand', '66'],\n ['VN', 'Vietnam', '84'],\n ['PH', 'Philippines', '63'],\n ['PK', 'Pakistan', '92'],\n ['BD', 'Bangladesh', '880'],\n ['LK', 'Sri Lanka', '94'],\n ['NP', 'Nepal', '977'],\n ['MM', 'Myanmar', '95'],\n ['KH', 'Cambodia', '855'],\n ['LA', 'Laos', '856'],\n ['MN', 'Mongolia', '976'],\n ['KZ', 'Kazakhstan', '7'],\n ['UZ', 'Uzbekistan', '998'],\n ['AE', 'United Arab Emirates', '971'],\n ['SA', 'Saudi Arabia', '966'],\n ['QA', 'Qatar', '974'],\n ['KW', 'Kuwait', '965'],\n ['BH', 'Bahrain', '973'],\n ['OM', 'Oman', '968'],\n ['JO', 'Jordan', '962'],\n ['LB', 'Lebanon', '961'],\n ['IL', 'Israel', '972'],\n ['IQ', 'Iraq', '964'],\n ['IR', 'Iran', '98'],\n ['EG', 'Egypt', '20'],\n ['ZA', 'South Africa', '27'],\n ['NG', 'Nigeria', '234'],\n ['KE', 'Kenya', '254'],\n ['GH', 'Ghana', '233'],\n ['ET', 'Ethiopia', '251'],\n ['TZ', 'Tanzania', '255'],\n ['UG', 'Uganda', '256'],\n ['MA', 'Morocco', '212'],\n ['DZ', 'Algeria', '213'],\n ['TN', 'Tunisia', '216'],\n ['BR', 'Brazil', '55'],\n ['MX', 'Mexico', '52'],\n ['AR', 'Argentina', '54'],\n ['CL', 'Chile', '56'],\n ['CO', 'Colombia', '57'],\n ['PE', 'Peru', '51'],\n ['VE', 'Venezuela', '58'],\n ['EC', 'Ecuador', '593'],\n ['UY', 'Uruguay', '598'],\n ['PY', 'Paraguay', '595'],\n ['BO', 'Bolivia', '591'],\n ['CR', 'Costa Rica', '506'],\n ['PA', 'Panama', '507'],\n ['DO', 'Dominican Republic', '1'],\n ['GT', 'Guatemala', '502'],\n ['NZ', 'New Zealand', '64'],\n ['FJ', 'Fiji', '679'],\n];\n\nexport const COUNTRIES: readonly Country[] = RAW.map(([iso2, name, dial]) => ({\n iso2,\n name,\n dial,\n}));\n\nexport const DEFAULT_COUNTRY_ISO2 = 'IN';\n\nexport function flagEmoji(iso2: string): string {\n return flagFromIso2(iso2);\n}\n\nexport function countryByIso2(iso2: string): Country | undefined {\n return COUNTRIES.find((c) => c.iso2 === iso2);\n}\n\n/**\n * Longest-dial-code-first match against a digit string (no '+'). Tries 3, 2,\n * then 1-digit prefixes so e.g. \"44\" resolves to the UK rather than being cut\n * short at a 1-digit code that happens to also exist.\n */\nexport function countryByDialPrefix(digits: string): Country | undefined {\n for (const len of [3, 2, 1]) {\n const prefix = digits.slice(0, len);\n if (prefix.length < len) continue;\n const match = COUNTRIES.find((c) => c.dial === prefix);\n if (match) return match;\n }\n return undefined;\n}\n\n/** Best-effort guess from the browser's locale region, e.g. \"en-GB\" -> GB. */\nexport function detectCountryFromLocale(): Country | undefined {\n if (typeof navigator === 'undefined') return undefined;\n const locales = navigator.languages ?? [navigator.language];\n for (const locale of locales) {\n const match = /-([A-Z]{2})$/.exec(locale ?? '');\n if (match) {\n const found = countryByIso2(match[1]);\n if (found) return found;\n }\n }\n return undefined;\n}\n","/**\n * Theme for the drop-in login card.\n *\n * The package ships zero dependencies and no stylesheet, so the tokens are\n * injected once as CSS custom properties scoped to `.sneek-otp`. That buys two\n * things inline styles cannot: a `prefers-color-scheme` media query, and real\n * `:focus-visible` / `:hover` states.\n *\n * Light and dark are authored independently rather than one being an inversion\n * of the other. In dark, the page-to-card lightness delta carries depth and the\n * card needs no shadow; in light both are near-white, so the card takes a\n * visible border and a real shadow.\n */\nexport const SNEEK_STYLE_ID = 'sneek-otp-styles';\n\n/** Brand orange. The single accent — nothing else on the card is coloured. */\nexport const SNEEK_ACCENT_DARK = '#f86513';\n/** Darkened for light mode so it clears WCAG AA as text and as a button fill. */\nexport const SNEEK_ACCENT_LIGHT = '#b83f06';\n\nexport function buildStyles(accent?: string): string {\n const darkAccent = accent ?? SNEEK_ACCENT_DARK;\n const lightAccent = accent ?? SNEEK_ACCENT_LIGHT;\n\n const light = `\n --sneek-surface: #ffffff;\n --sneek-surface-2: #f4f1ed;\n --sneek-border: #e3ddd5;\n --sneek-text: #1c1917;\n --sneek-text-muted: #57534e;\n --sneek-accent: ${lightAccent};\n --sneek-accent-soft: color-mix(in srgb, ${lightAccent} 12%, transparent);\n --sneek-accent-shadow: color-mix(in srgb, ${lightAccent} 45%, transparent);\n --sneek-accent-contrast: #ffffff;\n --sneek-danger: #b0242a;\n --sneek-shadow: 0 3px 3px -2px rgb(0 0 0 / 0.10), 0 3px 4px rgb(0 0 0 / 0.07),\n 0 1px 8px rgb(0 0 0 / 0.06);`;\n\n const dark = `\n --sneek-surface: #17150f;\n --sneek-surface-2: #201d16;\n --sneek-border: rgba(255, 255, 255, 0.08);\n --sneek-text: #faf8f6;\n --sneek-text-muted: #a8a29b;\n --sneek-accent: ${darkAccent};\n --sneek-accent-soft: color-mix(in srgb, ${darkAccent} 16%, transparent);\n --sneek-accent-shadow: color-mix(in srgb, ${darkAccent} 55%, transparent);\n --sneek-accent-contrast: #1a0d04;\n --sneek-danger: #d43a3c;\n --sneek-shadow: none;`;\n\n return `\n.sneek-otp {${light}\n --sneek-ease: cubic-bezier(0, 0, 0.2, 1);\n}\n@media (prefers-color-scheme: dark) {\n .sneek-otp:not([data-theme=\"light\"]) {${dark}\n }\n}\n.sneek-otp[data-theme=\"dark\"] {${dark}\n}\n.sneek-otp[data-theme=\"light\"] {${light}\n}\n.sneek-otp *, .sneek-otp *::before, .sneek-otp *::after { box-sizing: border-box; }\n.sneek-otp-input:focus-visible,\n.sneek-otp-button:focus-visible,\n.sneek-otp-link:focus-visible,\n.sneek-otp-country-chip:focus-visible,\n.sneek-otp-brand-link:focus-visible {\n outline: 2px solid var(--sneek-accent);\n outline-offset: 2px;\n}\n.sneek-otp-input:focus {\n border-color: var(--sneek-accent);\n}\n.sneek-otp-phone-field:focus-within {\n border-color: var(--sneek-accent);\n}\n.sneek-otp-button:not(:disabled):hover {\n filter: brightness(1.08);\n}\n.sneek-otp-link:not(:disabled):hover {\n text-decoration: underline;\n}\n.sneek-otp-country-chip:not(:disabled):hover {\n filter: brightness(1.08);\n}\n.sneek-otp-brand-link {\n box-shadow: 0 1px 6px var(--sneek-accent-shadow);\n}\n.sneek-otp-brand-link:hover {\n box-shadow: 0 2px 10px var(--sneek-accent-shadow);\n}\n@media (prefers-reduced-motion: reduce) {\n .sneek-otp * { transition-duration: 0.01ms !important; }\n}\n@keyframes sneek-otp-caret {\n 0%, 45% { opacity: 1; }\n 50%, 100% { opacity: 0; }\n}\n.sneek-otp-caret {\n animation: sneek-otp-caret 1s step-end infinite;\n}\n`;\n}\n","import type { RequestOtpResult } from './state';\n\nexport interface FetchHandlerOptions {\n /**\n * Partner backend endpoint that sends an OTP. Receives `{ identifier }`,\n * must return `{ requestId, channels?, expiresInSeconds? }`.\n * @default '/api/auth/request-otp'\n */\n requestUrl?: string;\n /**\n * Partner backend endpoint that verifies an OTP. Receives\n * `{ requestId, code }`, returns whatever your app needs (session, token…).\n * @default '/api/auth/verify-otp'\n */\n verifyUrl?: string;\n /** Extra headers (e.g. CSRF token) to send on both requests. */\n headers?: Record<string, string>;\n /** Forwarded to fetch — set to 'include' if you use cookie sessions. */\n credentials?: RequestCredentials;\n}\n\nasync function postJson<T>(\n url: string,\n body: unknown,\n options: FetchHandlerOptions,\n): Promise<T> {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(options.headers ?? {}) },\n credentials: options.credentials,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n let message = `Request failed (${response.status})`;\n try {\n const data = (await response.json()) as { message?: string; error?: string };\n message = data.message || data.error || message;\n } catch {\n // non-JSON error body — keep the status-based message\n }\n throw new Error(message);\n }\n\n return (await response.json()) as T;\n}\n\n/**\n * Build {@link SneekOtpHandlers} that POST to your own backend endpoints.\n * Those endpoints call the Sneek API server-side with your secret key.\n */\nexport function createFetchHandlers<TResult = unknown>(\n options: FetchHandlerOptions = {},\n): {\n requestOtp: (identifier: string) => Promise<RequestOtpResult>;\n verifyOtp: (input: { requestId: string; code: string }) => Promise<TResult>;\n} {\n const requestUrl = options.requestUrl ?? '/api/auth/request-otp';\n const verifyUrl = options.verifyUrl ?? '/api/auth/verify-otp';\n\n return {\n requestOtp: (identifier: string) =>\n postJson<RequestOtpResult>(requestUrl, { identifier }, options),\n verifyOtp: (input: { requestId: string; code: string }) =>\n postJson<TResult>(verifyUrl, input, options),\n };\n}\n"],"mappings":"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","names":["useEffect","useId","useState","jsx","jsxs","useId","useState","useEffect"]}
|