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.
- package/README.md +86 -111
- package/dist/chunk-64MVNASE.mjs +42 -0
- package/dist/chunk-IQG3OBQL.mjs +127 -0
- package/dist/index.d.mts +3 -10
- package/dist/index.d.ts +3 -10
- package/dist/index.js +112 -351
- package/dist/index.mjs +8 -18
- package/dist/react/index.d.mts +72 -51
- package/dist/react/index.d.ts +72 -51
- package/dist/react/index.js +85 -180
- package/dist/react/index.mjs +3 -3
- package/dist/server/index.d.mts +38 -98
- package/dist/server/index.d.ts +38 -98
- package/dist/server/index.js +25 -167
- package/dist/server/index.mjs +3 -11
- package/package.json +15 -6
- package/dist/chunk-FTNSOYOW.mjs +0 -223
- package/dist/chunk-XGASTZZ6.mjs +0 -180
package/dist/react/index.d.mts
CHANGED
|
@@ -1,60 +1,81 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { OTPInput } from 'input-otp';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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,
|
|
81
|
+
export { InputOTP, InputOTPGroup, type InputOTPProps, InputOTPSeparator, InputOTPSlot, OTP, type OTPProps };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,60 +1,81 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { OTPInput } from 'input-otp';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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,
|
|
81
|
+
export { InputOTP, InputOTPGroup, type InputOTPProps, InputOTPSeparator, InputOTPSlot, OTP, type OTPProps };
|
package/dist/react/index.js
CHANGED
|
@@ -34,13 +34,13 @@ __export(react_exports, {
|
|
|
34
34
|
InputOTPGroup: () => InputOTPGroup,
|
|
35
35
|
InputOTPSeparator: () => InputOTPSeparator,
|
|
36
36
|
InputOTPSlot: () => InputOTPSlot,
|
|
37
|
-
|
|
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
|
|
63
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
className: "
|
|
71
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
107
|
-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
165
|
+
OTP
|
|
261
166
|
});
|
package/dist/react/index.mjs
CHANGED
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
InputOTPGroup,
|
|
4
4
|
InputOTPSeparator,
|
|
5
5
|
InputOTPSlot,
|
|
6
|
-
|
|
7
|
-
} from "../chunk-
|
|
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
|
-
|
|
14
|
+
OTP
|
|
15
15
|
};
|