irismail 0.1.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,60 +1,81 @@
1
- import * as input_otp from 'input-otp';
1
+ import { OTPInput } from 'input-otp';
2
2
  import * as React from 'react';
3
3
 
4
- declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "maxLength" | "value" | "onChange" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
5
- value?: string;
6
- onChange?: (newValue: string) => unknown;
7
- maxLength: number;
8
- textAlign?: "left" | "center" | "right";
9
- onComplete?: (...args: any[]) => unknown;
10
- pushPasswordManagerStrategy?: "increase-width" | "none";
11
- pasteTransformer?: (pasted: string) => string;
12
- containerClassName?: string;
13
- noScriptCSSFallback?: string | null;
14
- } & {
15
- render: (props: input_otp.RenderProps) => React.ReactNode;
16
- children?: never;
17
- } & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "maxLength" | "value" | "onChange" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
18
- value?: string;
19
- onChange?: (newValue: string) => unknown;
20
- maxLength: number;
21
- textAlign?: "left" | "center" | "right";
22
- onComplete?: (...args: any[]) => unknown;
23
- pushPasswordManagerStrategy?: "increase-width" | "none";
24
- pasteTransformer?: (pasted: string) => string;
25
- containerClassName?: string;
26
- noScriptCSSFallback?: string | null;
27
- } & {
28
- render?: never;
29
- children: React.ReactNode;
30
- } & React.RefAttributes<HTMLInputElement>, "ref">) & React.RefAttributes<HTMLInputElement>>;
4
+ type InputOTPProps = React.ComponentPropsWithoutRef<typeof OTPInput> & {
5
+ /** Show error styling */
6
+ error?: boolean;
7
+ };
8
+ /**
9
+ * Low-level OTP input wrapper for the composition pattern.
10
+ * Use this when you need custom slot arrangements.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <InputOTP maxLength={6} value={code} onChange={setCode}>
15
+ * <InputOTPGroup>
16
+ * <InputOTPSlot index={0} />
17
+ * <InputOTPSlot index={1} />
18
+ * <InputOTPSlot index={2} />
19
+ * </InputOTPGroup>
20
+ * <InputOTPSeparator />
21
+ * <InputOTPGroup>
22
+ * <InputOTPSlot index={3} />
23
+ * <InputOTPSlot index={4} />
24
+ * <InputOTPSlot index={5} />
25
+ * </InputOTPGroup>
26
+ * </InputOTP>
27
+ * ```
28
+ */
29
+ declare const InputOTP: React.ForwardRefExoticComponent<InputOTPProps & React.RefAttributes<HTMLInputElement>>;
31
30
  declare const InputOTPGroup: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
32
31
  declare const InputOTPSlot: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
33
32
  index: number;
34
33
  } & React.RefAttributes<HTMLDivElement>>;
35
34
  declare const InputOTPSeparator: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
36
-
37
- interface UseOTPOptions {
38
- email: string;
39
- onRateLimit?: (resetTime: number) => void;
40
- }
41
- declare function useOTP({ email, onRateLimit }: UseOTPOptions): {
42
- otpTimeLeft: number;
43
- resendTimeLeft: number;
44
- attemptsLeft: number;
45
- isRateLimited: boolean;
46
- rateLimitResetTime: number | null;
47
- formatTime: (seconds: number) => string;
48
- recordSentOTP: () => void;
49
- checkRateLimit: () => {
50
- limited: boolean;
51
- attemptsLeft: number;
52
- resetTime?: undefined;
53
- } | {
54
- limited: boolean;
55
- attemptsLeft: number;
56
- resetTime: number | undefined;
57
- };
35
+ type OTPProps = {
36
+ /** Number of OTP digits (default: 6) */
37
+ length?: number;
38
+ /** Controlled input value */
39
+ value?: string;
40
+ /** Called when value changes */
41
+ onChange?: (value: string) => void;
42
+ /** Called when all digits are entered */
43
+ onComplete?: (value: string) => void;
44
+ /** Disable the input */
45
+ disabled?: boolean;
46
+ /** Show error styling */
47
+ error?: boolean;
48
+ /** Auto focus the first input on mount */
49
+ autoFocus?: boolean;
50
+ /** Name attribute for form integration */
51
+ name?: string;
52
+ /** Additional className for the container */
53
+ className?: string;
54
+ /** Pattern to match input against (default: digits only) */
55
+ pattern?: string;
58
56
  };
57
+ /**
58
+ * Simple, easy-to-use OTP input component.
59
+ *
60
+ * @example
61
+ * ```tsx
62
+ * // Basic usage
63
+ * <OTP value={code} onChange={setCode} />
64
+ *
65
+ * // With completion callback
66
+ * <OTP
67
+ * value={code}
68
+ * onChange={setCode}
69
+ * onComplete={(value) => verify(value)}
70
+ * />
71
+ *
72
+ * // With error state
73
+ * <OTP value={code} onChange={setCode} error={isInvalid} />
74
+ *
75
+ * // Custom length
76
+ * <OTP length={4} value={code} onChange={setCode} />
77
+ * ```
78
+ */
79
+ declare const OTP: React.ForwardRefExoticComponent<OTPProps & React.RefAttributes<HTMLInputElement>>;
59
80
 
60
- export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, useOTP };
81
+ export { InputOTP, InputOTPGroup, type InputOTPProps, InputOTPSeparator, InputOTPSlot, OTP, type OTPProps };
@@ -1,60 +1,81 @@
1
- import * as input_otp from 'input-otp';
1
+ import { OTPInput } from 'input-otp';
2
2
  import * as React from 'react';
3
3
 
4
- declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "maxLength" | "value" | "onChange" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
5
- value?: string;
6
- onChange?: (newValue: string) => unknown;
7
- maxLength: number;
8
- textAlign?: "left" | "center" | "right";
9
- onComplete?: (...args: any[]) => unknown;
10
- pushPasswordManagerStrategy?: "increase-width" | "none";
11
- pasteTransformer?: (pasted: string) => string;
12
- containerClassName?: string;
13
- noScriptCSSFallback?: string | null;
14
- } & {
15
- render: (props: input_otp.RenderProps) => React.ReactNode;
16
- children?: never;
17
- } & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "maxLength" | "value" | "onChange" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
18
- value?: string;
19
- onChange?: (newValue: string) => unknown;
20
- maxLength: number;
21
- textAlign?: "left" | "center" | "right";
22
- onComplete?: (...args: any[]) => unknown;
23
- pushPasswordManagerStrategy?: "increase-width" | "none";
24
- pasteTransformer?: (pasted: string) => string;
25
- containerClassName?: string;
26
- noScriptCSSFallback?: string | null;
27
- } & {
28
- render?: never;
29
- children: React.ReactNode;
30
- } & React.RefAttributes<HTMLInputElement>, "ref">) & React.RefAttributes<HTMLInputElement>>;
4
+ type InputOTPProps = React.ComponentPropsWithoutRef<typeof OTPInput> & {
5
+ /** Show error styling */
6
+ error?: boolean;
7
+ };
8
+ /**
9
+ * Low-level OTP input wrapper for the composition pattern.
10
+ * Use this when you need custom slot arrangements.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <InputOTP maxLength={6} value={code} onChange={setCode}>
15
+ * <InputOTPGroup>
16
+ * <InputOTPSlot index={0} />
17
+ * <InputOTPSlot index={1} />
18
+ * <InputOTPSlot index={2} />
19
+ * </InputOTPGroup>
20
+ * <InputOTPSeparator />
21
+ * <InputOTPGroup>
22
+ * <InputOTPSlot index={3} />
23
+ * <InputOTPSlot index={4} />
24
+ * <InputOTPSlot index={5} />
25
+ * </InputOTPGroup>
26
+ * </InputOTP>
27
+ * ```
28
+ */
29
+ declare const InputOTP: React.ForwardRefExoticComponent<InputOTPProps & React.RefAttributes<HTMLInputElement>>;
31
30
  declare const InputOTPGroup: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
32
31
  declare const InputOTPSlot: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
33
32
  index: number;
34
33
  } & React.RefAttributes<HTMLDivElement>>;
35
34
  declare const InputOTPSeparator: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
36
-
37
- interface UseOTPOptions {
38
- email: string;
39
- onRateLimit?: (resetTime: number) => void;
40
- }
41
- declare function useOTP({ email, onRateLimit }: UseOTPOptions): {
42
- otpTimeLeft: number;
43
- resendTimeLeft: number;
44
- attemptsLeft: number;
45
- isRateLimited: boolean;
46
- rateLimitResetTime: number | null;
47
- formatTime: (seconds: number) => string;
48
- recordSentOTP: () => void;
49
- checkRateLimit: () => {
50
- limited: boolean;
51
- attemptsLeft: number;
52
- resetTime?: undefined;
53
- } | {
54
- limited: boolean;
55
- attemptsLeft: number;
56
- resetTime: number | undefined;
57
- };
35
+ type OTPProps = {
36
+ /** Number of OTP digits (default: 6) */
37
+ length?: number;
38
+ /** Controlled input value */
39
+ value?: string;
40
+ /** Called when value changes */
41
+ onChange?: (value: string) => void;
42
+ /** Called when all digits are entered */
43
+ onComplete?: (value: string) => void;
44
+ /** Disable the input */
45
+ disabled?: boolean;
46
+ /** Show error styling */
47
+ error?: boolean;
48
+ /** Auto focus the first input on mount */
49
+ autoFocus?: boolean;
50
+ /** Name attribute for form integration */
51
+ name?: string;
52
+ /** Additional className for the container */
53
+ className?: string;
54
+ /** Pattern to match input against (default: digits only) */
55
+ pattern?: string;
58
56
  };
57
+ /**
58
+ * Simple, easy-to-use OTP input component.
59
+ *
60
+ * @example
61
+ * ```tsx
62
+ * // Basic usage
63
+ * <OTP value={code} onChange={setCode} />
64
+ *
65
+ * // With completion callback
66
+ * <OTP
67
+ * value={code}
68
+ * onChange={setCode}
69
+ * onComplete={(value) => verify(value)}
70
+ * />
71
+ *
72
+ * // With error state
73
+ * <OTP value={code} onChange={setCode} error={isInvalid} />
74
+ *
75
+ * // Custom length
76
+ * <OTP length={4} value={code} onChange={setCode} />
77
+ * ```
78
+ */
79
+ declare const OTP: React.ForwardRefExoticComponent<OTPProps & React.RefAttributes<HTMLInputElement>>;
59
80
 
60
- export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, useOTP };
81
+ export { InputOTP, InputOTPGroup, type InputOTPProps, InputOTPSeparator, InputOTPSlot, OTP, type OTPProps };
@@ -34,13 +34,13 @@ __export(react_exports, {
34
34
  InputOTPGroup: () => InputOTPGroup,
35
35
  InputOTPSeparator: () => InputOTPSeparator,
36
36
  InputOTPSlot: () => InputOTPSlot,
37
- useOTP: () => useOTP
37
+ OTP: () => OTP
38
38
  });
39
39
  module.exports = __toCommonJS(react_exports);
40
40
 
41
41
  // src/react/components/input-otp.tsx
42
- var React = __toESM(require("react"));
43
42
  var import_input_otp = require("input-otp");
43
+ var React = __toESM(require("react"));
44
44
 
45
45
  // src/utils/constants.ts
46
46
  var import_clsx = require("clsx");
@@ -48,214 +48,119 @@ var import_tailwind_merge = require("tailwind-merge");
48
48
  function cn(...inputs) {
49
49
  return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
50
50
  }
51
- var OTP_DEFAULTS = {
52
- LENGTH: 6,
53
- EXPIRY_MINUTES: 5,
54
- RESEND_COOLDOWN_SECONDS: 120,
55
- // 2 minutes
56
- MAX_ATTEMPTS: 5,
57
- RATE_LIMIT_RESET_HOURS: 1
58
- };
59
51
 
60
52
  // src/react/components/input-otp.tsx
61
53
  var import_jsx_runtime = require("react/jsx-runtime");
62
- var Dot = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
63
- "svg",
54
+ var InputOTPStyleContext = React.createContext({});
55
+ var InputOTP = React.forwardRef(({ className, containerClassName, error, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InputOTPStyleContext.Provider, { value: { error }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
56
+ import_input_otp.OTPInput,
64
57
  {
65
- width: "15",
66
- height: "15",
67
- viewBox: "0 0 15 15",
68
- fill: "none",
69
- xmlns: "http://www.w3.org/2000/svg",
70
- className: "h-4 w-4",
71
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
72
- "path",
73
- {
74
- d: "M7.5 7.5C7.5 8.32843 6.82843 9 6 9C5.17157 9 4.5 8.32843 4.5 7.5C4.5 6.67157 5.17157 6 6 6C6.82843 6 7.5 6.67157 7.5 7.5Z",
75
- fill: "currentColor",
76
- fillRule: "evenodd",
77
- clipRule: "evenodd"
78
- }
79
- )
58
+ ref,
59
+ containerClassName: cn(
60
+ "flex items-center gap-2 has-[:disabled]:opacity-50",
61
+ containerClassName
62
+ ),
63
+ className: cn("disabled:cursor-not-allowed", className),
64
+ ...props
80
65
  }
81
- );
82
- var InputOTP = React.forwardRef(
83
- ({ className, containerClassName, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
84
- import_input_otp.OTPInput,
85
- {
86
- ref,
87
- containerClassName: cn("flex items-center gap-2 has-[:disabled]:opacity-50", containerClassName),
88
- className: cn("disabled:cursor-not-allowed", className),
89
- ...props
90
- }
91
- )
92
- );
66
+ ) }));
93
67
  InputOTP.displayName = "InputOTP";
94
- var InputOTPGroup = React.forwardRef(
95
- ({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref, className: cn("flex items-center", className), ...props })
96
- );
68
+ var InputOTPGroup = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
69
+ "div",
70
+ {
71
+ ref,
72
+ className: cn("flex items-center gap-2", className),
73
+ ...props
74
+ }
75
+ ));
97
76
  InputOTPGroup.displayName = "InputOTPGroup";
98
77
  var InputOTPSlot = React.forwardRef(({ index, className, ...props }, ref) => {
99
78
  const inputOTPContext = React.useContext(import_input_otp.OTPInputContext);
100
- const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
79
+ const { error } = React.useContext(InputOTPStyleContext);
80
+ const slot = inputOTPContext.slots[index];
81
+ const { char, hasFakeCaret, isActive } = slot;
101
82
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
102
83
  "div",
103
84
  {
104
85
  ref,
105
86
  className: cn(
106
- "relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
107
- isActive && "z-10 ring-2 ring-ring ring-offset-background",
87
+ // Base styles
88
+ "relative flex h-12 w-10 items-center justify-center",
89
+ "border-2 rounded-lg",
90
+ "font-mono text-lg font-medium",
91
+ "transition-all duration-150",
92
+ // Default state
93
+ "border-zinc-700 bg-zinc-900 text-white",
94
+ // Filled state
95
+ char && "border-zinc-500",
96
+ // Active/focus state
97
+ isActive && "ring-2 ring-offset-2 ring-offset-zinc-950 ring-indigo-500 border-indigo-500",
98
+ // Error state
99
+ error && "border-red-500/70 bg-red-500/10",
100
+ error && isActive && "ring-red-500",
108
101
  className
109
102
  ),
103
+ "data-active": isActive,
104
+ "data-filled": Boolean(char),
110
105
  ...props,
111
106
  children: [
112
107
  char,
113
- hasFakeCaret && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-4 w-px animate-caret-blink bg-foreground duration-1000" }) })
108
+ hasFakeCaret && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-5 w-0.5 animate-caret-blink rounded-full bg-indigo-400" }) })
114
109
  ]
115
110
  }
116
111
  );
117
112
  });
118
113
  InputOTPSlot.displayName = "InputOTPSlot";
119
- var InputOTPSeparator = React.forwardRef(
120
- ({ ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref, role: "separator", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dot, {}) })
121
- );
114
+ var InputOTPSeparator = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
115
+ "div",
116
+ {
117
+ ref,
118
+ role: "separator",
119
+ className: cn("flex items-center justify-center text-zinc-500", className),
120
+ ...props,
121
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "w-3 h-0.5 bg-zinc-600 rounded-full" })
122
+ }
123
+ ));
122
124
  InputOTPSeparator.displayName = "InputOTPSeparator";
123
-
124
- // src/react/hooks/use-otp.ts
125
- var import_react = require("react");
126
- function useOTP({ email, onRateLimit }) {
127
- const [otpTimeLeft, setOtpTimeLeft] = (0, import_react.useState)(OTP_DEFAULTS.EXPIRY_MINUTES * 60);
128
- const [resendTimeLeft, setResendTimeLeft] = (0, import_react.useState)(0);
129
- const [attemptsLeft, setAttemptsLeft] = (0, import_react.useState)(OTP_DEFAULTS.MAX_ATTEMPTS);
130
- const [isRateLimited, setIsRateLimited] = (0, import_react.useState)(false);
131
- const [rateLimitResetTime, setRateLimitResetTime] = (0, import_react.useState)(null);
132
- const getStorageKey = (prefix) => `${prefix}_${email}`;
133
- const getStoredData = (key) => {
134
- if (typeof window === "undefined") return null;
135
- const data = sessionStorage.getItem(key);
136
- return data ? JSON.parse(data) : null;
137
- };
138
- const setStoredData = (key, data) => {
139
- if (typeof window !== "undefined") {
140
- sessionStorage.setItem(key, JSON.stringify(data));
141
- }
142
- };
143
- const removeStoredData = (key) => {
144
- if (typeof window !== "undefined") {
145
- sessionStorage.removeItem(key);
146
- }
147
- };
148
- const checkRateLimit = () => {
149
- const key = getStorageKey("rate_limit");
150
- const data = getStoredData(key);
151
- if (!data) {
152
- setAttemptsLeft(OTP_DEFAULTS.MAX_ATTEMPTS);
153
- setIsRateLimited(false);
154
- return { limited: false, attemptsLeft: OTP_DEFAULTS.MAX_ATTEMPTS };
155
- }
156
- const currentTime = Date.now();
157
- const resetTime = OTP_DEFAULTS.RATE_LIMIT_RESET_HOURS * 60 * 60 * 1e3;
158
- if (currentTime - data.firstAttemptTime > resetTime) {
159
- removeStoredData(key);
160
- setAttemptsLeft(OTP_DEFAULTS.MAX_ATTEMPTS);
161
- setIsRateLimited(false);
162
- return { limited: false, attemptsLeft: OTP_DEFAULTS.MAX_ATTEMPTS };
163
- }
164
- const attempts = OTP_DEFAULTS.MAX_ATTEMPTS - data.attempts;
165
- const limited = data.attempts >= OTP_DEFAULTS.MAX_ATTEMPTS;
166
- const limitResetTime = data.firstAttemptTime + resetTime;
167
- setAttemptsLeft(Math.max(0, attempts));
168
- setIsRateLimited(limited);
169
- setRateLimitResetTime(limited ? limitResetTime : null);
170
- if (limited && onRateLimit) {
171
- onRateLimit(limitResetTime);
172
- }
173
- return { limited, attemptsLeft: Math.max(0, attempts), resetTime: limited ? limitResetTime : void 0 };
174
- };
175
- const updateRateLimit = () => {
176
- const key = getStorageKey("rate_limit");
177
- const data = getStoredData(key);
178
- const currentTime = Date.now();
179
- let newData;
180
- if (!data) {
181
- newData = {
182
- attempts: 1,
183
- firstAttemptTime: currentTime,
184
- lastAttemptTime: currentTime
185
- };
186
- } else {
187
- const resetTime = OTP_DEFAULTS.RATE_LIMIT_RESET_HOURS * 60 * 60 * 1e3;
188
- if (currentTime - data.firstAttemptTime > resetTime) {
189
- newData = {
190
- attempts: 1,
191
- firstAttemptTime: currentTime,
192
- lastAttemptTime: currentTime
193
- };
194
- } else {
195
- newData = {
196
- ...data,
197
- attempts: data.attempts + 1,
198
- lastAttemptTime: currentTime
199
- };
125
+ var OTP = React.forwardRef(
126
+ ({
127
+ length = 6,
128
+ value,
129
+ onChange,
130
+ onComplete,
131
+ disabled,
132
+ error,
133
+ autoFocus,
134
+ name,
135
+ className,
136
+ pattern = "^[0-9]*$"
137
+ }, ref) => {
138
+ const slotIndices = Array.from({ length }, (_, i) => i);
139
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
140
+ InputOTP,
141
+ {
142
+ ref,
143
+ maxLength: length,
144
+ value,
145
+ onChange,
146
+ onComplete,
147
+ disabled,
148
+ error,
149
+ autoFocus,
150
+ name,
151
+ pattern,
152
+ containerClassName: className,
153
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InputOTPGroup, { children: slotIndices.map((index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InputOTPSlot, { index }, index)) })
200
154
  }
201
- }
202
- setStoredData(key, newData);
203
- checkRateLimit();
204
- return newData;
205
- };
206
- const checkResendCooldown = () => {
207
- const key = getStorageKey("last_sent");
208
- const lastSentTime = getStoredData(key);
209
- if (!lastSentTime) {
210
- setResendTimeLeft(0);
211
- return { canResend: true, timeLeft: 0 };
212
- }
213
- const currentTime = Date.now();
214
- const timeSinceLastSent = currentTime - lastSentTime;
215
- const cooldown = OTP_DEFAULTS.RESEND_COOLDOWN_SECONDS * 1e3;
216
- const canResend = timeSinceLastSent >= cooldown;
217
- const timeLeft = canResend ? 0 : Math.ceil((cooldown - timeSinceLastSent) / 1e3);
218
- setResendTimeLeft(timeLeft);
219
- return { canResend, timeLeft };
220
- };
221
- const recordSentOTP = () => {
222
- const key = getStorageKey("last_sent");
223
- setStoredData(key, Date.now());
224
- updateRateLimit();
225
- setOtpTimeLeft(OTP_DEFAULTS.EXPIRY_MINUTES * 60);
226
- setResendTimeLeft(OTP_DEFAULTS.RESEND_COOLDOWN_SECONDS);
227
- };
228
- (0, import_react.useEffect)(() => {
229
- checkRateLimit();
230
- checkResendCooldown();
231
- const timer = setInterval(() => {
232
- setOtpTimeLeft((prev) => Math.max(0, prev - 1));
233
- const { timeLeft } = checkResendCooldown();
234
- setResendTimeLeft(timeLeft);
235
- }, 1e3);
236
- return () => clearInterval(timer);
237
- }, [email]);
238
- const formatTime = (seconds) => {
239
- const mins = Math.floor(seconds / 60);
240
- const secs = seconds % 60;
241
- return `${mins}:${secs.toString().padStart(2, "0")}`;
242
- };
243
- return {
244
- otpTimeLeft,
245
- resendTimeLeft,
246
- attemptsLeft,
247
- isRateLimited,
248
- rateLimitResetTime,
249
- formatTime,
250
- recordSentOTP,
251
- checkRateLimit
252
- };
253
- }
155
+ );
156
+ }
157
+ );
158
+ OTP.displayName = "OTP";
254
159
  // Annotate the CommonJS export names for ESM import in node:
255
160
  0 && (module.exports = {
256
161
  InputOTP,
257
162
  InputOTPGroup,
258
163
  InputOTPSeparator,
259
164
  InputOTPSlot,
260
- useOTP
165
+ OTP
261
166
  });
@@ -3,13 +3,13 @@ import {
3
3
  InputOTPGroup,
4
4
  InputOTPSeparator,
5
5
  InputOTPSlot,
6
- useOTP
7
- } from "../chunk-FTNSOYOW.mjs";
6
+ OTP
7
+ } from "../chunk-IQG3OBQL.mjs";
8
8
  import "../chunk-QZ7TP4HQ.mjs";
9
9
  export {
10
10
  InputOTP,
11
11
  InputOTPGroup,
12
12
  InputOTPSeparator,
13
13
  InputOTPSlot,
14
- useOTP
14
+ OTP
15
15
  };