awesome-auth-input 0.1.0 → 0.2.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 +109 -7
- package/dist/AuthCode/OneTimePassword.d.ts +3 -0
- package/dist/AuthCode/OneTimePassword.d.ts.map +1 -1
- package/dist/index.cjs +29 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +30 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
A headless, accessible, and fully-typed React component for OTP/auth code inputs with support for numeric, alphabetic, and custom validation patterns.
|
|
4
4
|
|
|
5
|
+
Storybook: https://awesome-auth-input.vercel.app/
|
|
6
|
+
|
|
5
7
|
## Features
|
|
6
8
|
|
|
7
9
|
- **Headless** - Bring your own styles, no CSS included
|
|
@@ -11,8 +13,10 @@ A headless, accessible, and fully-typed React component for OTP/auth code inputs
|
|
|
11
13
|
- **Auto-submit** - Optional auto-submit when all fields are filled
|
|
12
14
|
- **Form integration** - Hidden input for native form submission
|
|
13
15
|
- **Password mode** - Mask input characters
|
|
14
|
-
- **Paste support** - Paste codes directly
|
|
16
|
+
- **Paste & copy support** - Paste codes directly and copy complete values
|
|
17
|
+
- **Smart input behavior** - Intelligent focus management and character insertion
|
|
15
18
|
- **TypeScript** - Fully typed with exported types
|
|
19
|
+
- **Tree-shakeable** - Individual component exports for optimized bundles
|
|
16
20
|
- **Zero dependencies** - Only React as a peer dependency
|
|
17
21
|
|
|
18
22
|
## Installation
|
|
@@ -79,6 +83,18 @@ Individual input field for a single character. Must be used within `<AuthCode.Gr
|
|
|
79
83
|
|
|
80
84
|
Plus most standard `input` props (className, style, onKeyDown, etc.)
|
|
81
85
|
|
|
86
|
+
### `<AuthCode.HiddenInput>`
|
|
87
|
+
|
|
88
|
+
Hidden input that contains the complete auth code value for form submission. This component is automatically rendered by `<AuthCode.Group>`, but you can render it manually for advanced use cases.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<AuthCode.Group>
|
|
92
|
+
<AuthCode.HiddenInput />
|
|
93
|
+
<AuthCode.Input index={0} />
|
|
94
|
+
<AuthCode.Input index={1} />
|
|
95
|
+
</AuthCode.Group>
|
|
96
|
+
```
|
|
97
|
+
|
|
82
98
|
### Validation Patterns
|
|
83
99
|
|
|
84
100
|
```tsx
|
|
@@ -182,6 +198,17 @@ function OTPForm() {
|
|
|
182
198
|
</AuthCode.Group>
|
|
183
199
|
```
|
|
184
200
|
|
|
201
|
+
### Disabled State
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
<AuthCode.Group disabled={isVerifying}>
|
|
205
|
+
<AuthCode.Input index={0} />
|
|
206
|
+
<AuthCode.Input index={1} />
|
|
207
|
+
<AuthCode.Input index={2} />
|
|
208
|
+
<AuthCode.Input index={3} />
|
|
209
|
+
</AuthCode.Group>
|
|
210
|
+
```
|
|
211
|
+
|
|
185
212
|
### Custom Styling
|
|
186
213
|
|
|
187
214
|
The component is completely unstyled. Add your own CSS:
|
|
@@ -206,6 +233,12 @@ The component is completely unstyled. Add your own CSS:
|
|
|
206
233
|
border-color: #0070f3;
|
|
207
234
|
box-shadow: 0 0 0 3px rgba(0, 112, 243, 0.15);
|
|
208
235
|
}
|
|
236
|
+
|
|
237
|
+
.otp-input:disabled {
|
|
238
|
+
opacity: 0.5;
|
|
239
|
+
cursor: not-allowed;
|
|
240
|
+
background-color: #f5f5f5;
|
|
241
|
+
}
|
|
209
242
|
```
|
|
210
243
|
|
|
211
244
|
```tsx
|
|
@@ -216,6 +249,51 @@ The component is completely unstyled. Add your own CSS:
|
|
|
216
249
|
</AuthCode.Group>
|
|
217
250
|
```
|
|
218
251
|
|
|
252
|
+
## Advanced Features
|
|
253
|
+
|
|
254
|
+
### Smart Focus Management
|
|
255
|
+
|
|
256
|
+
The component intelligently manages focus to provide a smooth user experience:
|
|
257
|
+
|
|
258
|
+
- **Auto-advance**: Automatically moves to the next input when a character is entered
|
|
259
|
+
- **Smart clicking**: Clicking any input focuses the first empty field (or current field if all are filled)
|
|
260
|
+
- **Roving tabindex**: Only the current input is in the tab order for better keyboard navigation
|
|
261
|
+
|
|
262
|
+
### Password Manager Protection
|
|
263
|
+
|
|
264
|
+
The component includes data attributes to prevent password managers from interfering:
|
|
265
|
+
|
|
266
|
+
```tsx
|
|
267
|
+
// Automatically applied to all inputs
|
|
268
|
+
data-1p-ignore // 1Password
|
|
269
|
+
data-lpignore="true" // LastPass
|
|
270
|
+
data-bwignore="true" // Bitwarden
|
|
271
|
+
data-form-type="other" // Generic managers
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Intelligent Paste Handling
|
|
275
|
+
|
|
276
|
+
Paste operations are smartly detected and handled:
|
|
277
|
+
|
|
278
|
+
- Detects clipboard paste vs. manual typing
|
|
279
|
+
- Validates pasted content against the validation pattern
|
|
280
|
+
- Auto-fills all fields from the paste position
|
|
281
|
+
- Handles both short and long pasted values
|
|
282
|
+
|
|
283
|
+
### Copy Support
|
|
284
|
+
|
|
285
|
+
Copy the entire auth code with Ctrl/Cmd+C:
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
<AuthCode.Group onComplete={(code) => console.log('Code:', code)}>
|
|
289
|
+
{/* Ctrl/Cmd+C copies the complete code */}
|
|
290
|
+
<AuthCode.Input index={0} />
|
|
291
|
+
<AuthCode.Input index={1} />
|
|
292
|
+
<AuthCode.Input index={2} />
|
|
293
|
+
<AuthCode.Input index={3} />
|
|
294
|
+
</AuthCode.Group>
|
|
295
|
+
```
|
|
296
|
+
|
|
219
297
|
## TypeScript
|
|
220
298
|
|
|
221
299
|
Types are exported for your convenience:
|
|
@@ -229,21 +307,45 @@ import type {
|
|
|
229
307
|
} from 'awesome-auth-input';
|
|
230
308
|
```
|
|
231
309
|
|
|
310
|
+
## Tree-Shaking
|
|
311
|
+
|
|
312
|
+
For optimized bundle sizes, you can import individual components:
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
// Compound component (recommended)
|
|
316
|
+
import { AuthCode } from 'awesome-auth-input';
|
|
317
|
+
|
|
318
|
+
// Individual components for tree-shaking
|
|
319
|
+
import {
|
|
320
|
+
AuthCodeGroup,
|
|
321
|
+
AuthCodeInput,
|
|
322
|
+
AuthCodeHiddenInput
|
|
323
|
+
} from 'awesome-auth-input';
|
|
324
|
+
|
|
325
|
+
// Use them directly
|
|
326
|
+
<AuthCodeGroup onComplete={(code) => console.log(code)}>
|
|
327
|
+
<AuthCodeInput index={0} />
|
|
328
|
+
<AuthCodeInput index={1} />
|
|
329
|
+
</AuthCodeGroup>
|
|
330
|
+
```
|
|
331
|
+
|
|
232
332
|
## Keyboard Navigation
|
|
233
333
|
|
|
234
334
|
- **Arrow Left/Right** - Navigate between inputs
|
|
235
|
-
- **Backspace** - Delete current character and move to previous
|
|
335
|
+
- **Backspace/Delete** - Delete current character and move to previous
|
|
236
336
|
- **Ctrl/Cmd + Backspace** - Clear all inputs
|
|
237
337
|
- **Enter** - Submit the form
|
|
238
|
-
- **
|
|
338
|
+
- **Ctrl/Cmd + C** - Copy complete code to clipboard
|
|
339
|
+
- **Ctrl/Cmd + V** - Paste code from clipboard (auto-fills all fields)
|
|
239
340
|
|
|
240
341
|
## Accessibility
|
|
241
342
|
|
|
242
|
-
- Proper ARIA labels for each input
|
|
343
|
+
- Proper ARIA labels for each input (e.g., "One Time Password Character 1 out of 6")
|
|
243
344
|
- Focus management with roving tabindex
|
|
244
|
-
- Screen reader announcements
|
|
245
|
-
-
|
|
246
|
-
- Works with password managers (disabled with data attributes)
|
|
345
|
+
- Screen reader announcements for better UX
|
|
346
|
+
- Full keyboard navigation support
|
|
347
|
+
- Works with password managers (disabled with data attributes to prevent conflicts)
|
|
348
|
+
- Auto-complete hints for mobile devices (`autocomplete="one-time-code"` on hidden input)
|
|
247
349
|
|
|
248
350
|
## Browser Support
|
|
249
351
|
|
|
@@ -136,6 +136,9 @@ declare const AuthCodeHiddenInput: import("react").ForwardRefExoticComponent<Omi
|
|
|
136
136
|
* </AuthCode.Group>
|
|
137
137
|
* */
|
|
138
138
|
export declare function AuthCodeInput({ index, ...props }: AuthCodeInputProps): import("react/jsx-runtime").JSX.Element;
|
|
139
|
+
export declare namespace AuthCodeInput {
|
|
140
|
+
var displayName: string;
|
|
141
|
+
}
|
|
139
142
|
type InputMode = "text" | "numeric" | "none";
|
|
140
143
|
type ValidationPattern = ({
|
|
141
144
|
type: "custom";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OneTimePassword.d.ts","sourceRoot":"","sources":["../../src/AuthCode/OneTimePassword.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAGf,UAAU,mBAAmB;IAC3B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;;;;;;;;OAUG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,kBACR,SAAQ,mBAAmB,EACzB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,mBAAmB,CAAC;CAAG;AAEnE,QAAA,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"OneTimePassword.d.ts","sourceRoot":"","sources":["../../src/AuthCode/OneTimePassword.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAGf,UAAU,mBAAmB;IAC3B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;;;;;;;;OAUG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,kBACR,SAAQ,mBAAmB,EACzB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,mBAAmB,CAAC;CAAG;AAEnE,QAAA,MAAM,aAAa,4HAoQlB,CAAC;AAIF,QAAA,MAAM,mBAAmB,sNAyBvB,CAAC;AAIH;;;;;;;;;;;MAWM;AACN,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,kBAAkB,2CAuKpE;yBAvKe,aAAa;;;AA0R7B,KAAK,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAE7C,KAAK,iBAAiB,GAClB,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG,gBAAgB,CAAC,GACvC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAExB,KAAK,gBAAgB,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,UAAU,kBACR,SAAQ,IAAI,CACV,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAC3B,OAAO,GACP,aAAa,GACb,UAAU,GACV,cAAc,GACd,cAAc,GACd,MAAM,CACT;IACD,KAAK,EAAE,MAAM,CAAC;CACf;AAgED,OAAO,EACL,aAAa,IAAI,KAAK,EACtB,aAAa,IAAI,KAAK,EACtB,mBAAmB,IAAI,WAAW,GACnC,CAAC;AAEF,YAAY,EACV,kBAAkB,IAAI,kBAAkB,EACxC,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,GACjB,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -29,7 +29,8 @@ const AuthCodeField = react.forwardRef(
|
|
|
29
29
|
const registerInputRef = react.useCallback((ref) => {
|
|
30
30
|
if (ref) {
|
|
31
31
|
if (!inputElements.current.has(ref)) {
|
|
32
|
-
inputElements.current.
|
|
32
|
+
const position = inputElements.current.size;
|
|
33
|
+
inputElements.current.set(ref, position);
|
|
33
34
|
setInputCount(inputElements.current.size);
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -65,13 +66,17 @@ const AuthCodeField = react.forwardRef(
|
|
|
65
66
|
if (i === insertionIndex) return char;
|
|
66
67
|
return value[i] ?? "";
|
|
67
68
|
});
|
|
68
|
-
reactDom.flushSync(() =>
|
|
69
|
+
reactDom.flushSync(() => {
|
|
70
|
+
setValue(newValue);
|
|
71
|
+
});
|
|
69
72
|
if (insertionIndex < inputs.length - 1) {
|
|
70
73
|
requestAnimationFrame(
|
|
71
74
|
() => focusInput(inputs.at(insertionIndex + 1))
|
|
72
75
|
);
|
|
73
76
|
} else {
|
|
74
|
-
requestAnimationFrame(() =>
|
|
77
|
+
requestAnimationFrame(() => {
|
|
78
|
+
focusInput(inputs.at(insertionIndex));
|
|
79
|
+
});
|
|
75
80
|
}
|
|
76
81
|
return;
|
|
77
82
|
}
|
|
@@ -148,16 +153,21 @@ const AuthCodeField = react.forwardRef(
|
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
};
|
|
156
|
+
const concatenatedValue = react.useMemo(() => value.join(""), [value]);
|
|
157
|
+
react.useEffect(() => {
|
|
158
|
+
if (value.length === 0) {
|
|
159
|
+
setFocusedIndex(0);
|
|
160
|
+
}
|
|
161
|
+
}, [value]);
|
|
151
162
|
react.useEffect(() => {
|
|
152
163
|
var _a, _b;
|
|
153
|
-
const concatenatedValue = value.join("");
|
|
154
164
|
const isCodeFullyEntered = concatenatedValue.length === inputCount && value.every((v) => v !== "") && inputCount > 0;
|
|
155
165
|
if (!isCodeFullyEntered) return;
|
|
156
166
|
onComplete == null ? void 0 : onComplete(concatenatedValue);
|
|
157
167
|
if (autoSubmit) {
|
|
158
168
|
(_b = (_a = hiddenInputRef.current) == null ? void 0 : _a.form) == null ? void 0 : _b.requestSubmit();
|
|
159
169
|
}
|
|
160
|
-
}, [
|
|
170
|
+
}, [concatenatedValue, onComplete, inputCount, autoSubmit]);
|
|
161
171
|
const contextValue = react.useMemo(
|
|
162
172
|
() => ({
|
|
163
173
|
dispatch,
|
|
@@ -186,6 +196,10 @@ const AuthCodeField = react.forwardRef(
|
|
|
186
196
|
dispatch({ type: "PASTE", value: pastedText });
|
|
187
197
|
},
|
|
188
198
|
...divProps,
|
|
199
|
+
onCopy: mergeEventHandlers(divProps.onCopy, (event) => {
|
|
200
|
+
event.preventDefault();
|
|
201
|
+
event.clipboardData.setData("text/plain", value.join(""));
|
|
202
|
+
}),
|
|
189
203
|
children: [
|
|
190
204
|
/* @__PURE__ */ jsxRuntime.jsx(AuthCodeHiddenInput, {}),
|
|
191
205
|
children
|
|
@@ -194,6 +208,7 @@ const AuthCodeField = react.forwardRef(
|
|
|
194
208
|
) });
|
|
195
209
|
}
|
|
196
210
|
);
|
|
211
|
+
AuthCodeField.displayName = "AuthCode.Group";
|
|
197
212
|
const AuthCodeHiddenInput = react.forwardRef(function AuthCodeHiddenInput2(props, ref) {
|
|
198
213
|
const context = useAuthCodeContext();
|
|
199
214
|
const { name, value, hiddenInputRef } = context;
|
|
@@ -218,6 +233,7 @@ const AuthCodeHiddenInput = react.forwardRef(function AuthCodeHiddenInput2(props
|
|
|
218
233
|
}
|
|
219
234
|
);
|
|
220
235
|
});
|
|
236
|
+
AuthCodeHiddenInput.displayName = "AuthCode.HiddenInput";
|
|
221
237
|
function AuthCodeInput({ index, ...props }) {
|
|
222
238
|
const context = useAuthCodeContext();
|
|
223
239
|
const {
|
|
@@ -227,16 +243,19 @@ function AuthCodeInput({ index, ...props }) {
|
|
|
227
243
|
focusedIndex,
|
|
228
244
|
setFocusedIndex,
|
|
229
245
|
disabled,
|
|
230
|
-
inputCount
|
|
246
|
+
inputCount,
|
|
247
|
+
inputElements
|
|
231
248
|
} = context;
|
|
232
249
|
const currentCharacter = context.value[index] || "";
|
|
233
250
|
const firstEmptyIndex = Array.from({ length: inputCount }).findIndex(
|
|
234
251
|
(_, i) => !context.value[i]
|
|
235
252
|
);
|
|
236
253
|
const nextEmptyOrLastIndex = firstEmptyIndex === -1 ? inputCount - 1 : firstEmptyIndex;
|
|
237
|
-
const
|
|
254
|
+
const inputRef = react.useRef(null);
|
|
255
|
+
const mergedInputRef = react.useCallback(mergeRefs(registerInputRef, inputRef), [
|
|
238
256
|
registerInputRef
|
|
239
257
|
]);
|
|
258
|
+
const inputPosition = inputRef.current ? (inputElements.get(inputRef.current) ?? 0) + 1 : index + 1;
|
|
240
259
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
241
260
|
"input",
|
|
242
261
|
{
|
|
@@ -245,15 +264,15 @@ function AuthCodeInput({ index, ...props }) {
|
|
|
245
264
|
ref: mergedInputRef,
|
|
246
265
|
inputMode: validation.inputMode,
|
|
247
266
|
pattern: validation.pattern,
|
|
248
|
-
"aria-label": `One Time Password Character ${
|
|
267
|
+
"aria-label": `One Time Password Character ${inputPosition} out of ${inputCount}`,
|
|
249
268
|
disabled,
|
|
250
269
|
autoComplete: "off",
|
|
251
270
|
autoCorrect: "off",
|
|
252
271
|
autoCapitalize: "off",
|
|
253
272
|
"data-1p-ignore": true,
|
|
254
273
|
"data-lpignore": "true",
|
|
255
|
-
"data-form-type": "other",
|
|
256
274
|
"data-bwignore": "true",
|
|
275
|
+
"data-form-type": "other",
|
|
257
276
|
...props,
|
|
258
277
|
onPointerDown: (event) => {
|
|
259
278
|
event.preventDefault();
|
|
@@ -342,6 +361,7 @@ function AuthCodeInput({ index, ...props }) {
|
|
|
342
361
|
}
|
|
343
362
|
);
|
|
344
363
|
}
|
|
364
|
+
AuthCodeInput.displayName = "AuthCode.Input";
|
|
345
365
|
const AuthCodeContext = react.createContext(null);
|
|
346
366
|
function useAuthCodeContext() {
|
|
347
367
|
const value = react.useContext(AuthCodeContext);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/AuthCode/OneTimePassword.tsx","../src/index.ts"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useRef,\n useState,\n type ReactNode,\n type Ref,\n useMemo,\n useEffect,\n forwardRef,\n} from \"react\";\nimport { flushSync } from \"react-dom\";\n\ninterface AuthCodeCustomField {\n /**\n * The child components, typically `<AuthCode.Input>` components.\n *\n * All `<AuthCode.Input>` components must be direct or nested children of `<AuthCode.Group>`.\n */\n children: ReactNode;\n /**\n * A string specifying a name for the input control. This name is submitted\n * along with the control's value when the form data is submitted.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#name\n */\n name?: string;\n /**\n * Specifies what type of validation the user agent has to provide for each\n * character input. Allows \"numeric\", \"alpha\", \"alphanumeric\", or a custom\n * validation pattern with regex.\n *\n * @defaultValue `{ type: \"numeric\" }`\n *\n * @example\n * ```tsx\n * // Numeric only (default)\n * <AuthCode.Group validation={{ type: \"numeric\" }} />\n *\n * // Alphabetic only\n * <AuthCode.Group validation={{ type: \"alpha\" }} />\n *\n * // Custom validation\n * <AuthCode.Group\n * validation={{\n * type: \"custom\",\n * regex: /^[A-Z]$/,\n * pattern: \"[A-Z]{1}\",\n * inputMode: \"text\"\n * }}\n * />\n * ```\n */\n validation?: ValidationPattern;\n /**\n * Whether or not the component should attempt to automatically submit when\n * all fields are filled. If the field is associated with an HTML `form`\n * element, the form's `requestSubmit` method will be called.\n *\n * @defaultValue `true`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit\n */\n autoSubmit?: boolean;\n /**\n * When the `autoSubmit` prop is set to `true`, this callback will be fired\n * before attempting to submit the associated form. It will be called whether\n * or not a form is located, or if submission is not allowed.\n *\n * The callback receives the complete auth code value as a string.\n *\n * @example\n * ```tsx\n * <AuthCode.Group\n * onComplete={(value) => {\n * console.log('Code entered:', value);\n * verifyCode(value);\n * }}\n * />\n * ```\n */\n onComplete?: (value: string) => void;\n /**\n * The controlled value of the field. When provided, the component operates\n * in controlled mode. This string's value, if present, must match the total\n * number of `<AuthCode.Input>` components.\n *\n * @example\n * ```tsx\n * const [code, setCode] = useState('');\n * <AuthCode.Group value={code} onValueChange={setCode} />\n * ```\n */\n value?: string;\n /**\n * A callback fired whenever the field value changes. This callback is called\n * with the complete auth code value as a string.\n *\n * Use this prop together with `value` to create a controlled component.\n */\n onValueChange?: (value: string) => void;\n /**\n * The initial value of the uncontrolled field. When provided without `value`,\n * the component operates in uncontrolled mode.\n *\n * @example\n * ```tsx\n * <AuthCode.Group defaultValue=\"123\" />\n * ```\n */\n defaultValue?: string;\n /**\n * The type of control to render. Allows \"text\" or \"password\".\n *\n * When set to \"password\", the input characters will be masked.\n *\n * @defaultValue `\"text\"`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#type\n */\n type?: \"text\" | \"password\";\n /**\n * Whether or not the input elements are disabled.\n *\n * When set to `true`, all `<AuthCode.Input>` components will be disabled\n * and users will not be able to interact with them.\n *\n * @defaultValue `false`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled\n */\n disabled?: boolean;\n}\n\ninterface AuthCodeFieldProps\n extends AuthCodeCustomField,\n Omit<React.ComponentProps<\"div\">, keyof AuthCodeCustomField> {}\n\nconst AuthCodeField = forwardRef<HTMLDivElement, AuthCodeFieldProps>(\n function AuthCodeField(\n {\n children,\n name,\n validation = { type: \"numeric\" },\n autoSubmit = true,\n onComplete,\n value: userValue,\n onValueChange: userOnValueChange,\n defaultValue,\n type = \"text\",\n disabled = false,\n ...divProps\n }: AuthCodeFieldProps,\n forwardedRef\n ) {\n const inputElements = useRef<Map<HTMLInputElement, true>>(new Map());\n const [value, setValue] = useControllableState<string[]>({\n value: userValue !== undefined ? Array.from(userValue) : undefined,\n defaultValue: defaultValue ? Array.from(defaultValue) : [],\n onValueChange: userOnValueChange\n ? (chars) => userOnValueChange(chars.join(\"\"))\n : undefined,\n });\n\n const validationConfig =\n validation.type == \"custom\"\n ? validation\n : defaultPatternInputMap[validation.type];\n\n const [focusedIndex, setFocusedIndex] = useState(0);\n const [inputCount, setInputCount] = useState(0);\n\n const registerInputRef = useCallback((ref: HTMLInputElement | null) => {\n if (ref) {\n if (!inputElements.current.has(ref)) {\n inputElements.current.set(ref, true);\n setInputCount(inputElements.current.size);\n }\n }\n }, []);\n\n const validateChar = useCallback(\n (char: string): boolean => {\n if (!char) return true;\n\n const regex = validationConfig.regex;\n return regex.test(char);\n },\n [validationConfig]\n );\n\n const validateString = useCallback(\n (str: string): string => {\n return Array.from(str)\n .filter((char) => validateChar(char))\n .join(\"\");\n },\n [validateChar]\n );\n\n const hiddenInputRef = useRef<HTMLInputElement | null>(null);\n\n // consider removing useEffectEvent\n const dispatch = (action: FieldUpdateAction) => {\n // use an ordered dictionary instead?\n const inputs = Array.from(inputElements.current.keys());\n switch (action.type) {\n case \"TYPE_CHAR\": {\n const { char, index: targetIndex } = action;\n\n if (!validateChar(char)) return;\n\n const hasExistingValue = !!value[targetIndex];\n const firstEmptyIndex = Array.from({\n length: inputs.length,\n }).findIndex((_, i) => !value[i]);\n\n const insertionIndex =\n hasExistingValue || firstEmptyIndex === -1\n ? targetIndex\n : firstEmptyIndex;\n\n const newValue = Array.from({ length: inputs.length }, (_, i) => {\n if (i === insertionIndex) return char;\n return value[i] ?? \"\";\n });\n\n flushSync(() => setValue(newValue));\n\n if (insertionIndex < inputs.length - 1) {\n requestAnimationFrame(() =>\n focusInput(inputs.at(insertionIndex + 1))\n );\n } else {\n requestAnimationFrame(() => focusInput(inputs.at(insertionIndex)));\n }\n return;\n }\n\n case \"REMOVE_CHAR\": {\n const { index } = action;\n const totalInputLength = inputs.length;\n\n // Remove character and shift remaining values left\n const leftPortion = value.slice(0, index);\n const rightPortion = value.slice(index + 1);\n const compacted = leftPortion.concat(rightPortion);\n const emptySlots = Array(\n Math.max(0, totalInputLength - compacted.length)\n ).fill(\"\");\n\n flushSync(() => setValue(compacted.concat(emptySlots)));\n\n if (index != 0) {\n focusInput(inputs.at(index - 1));\n } else {\n // index is 0\n focusInput(inputs.at(0));\n }\n return;\n }\n\n case \"CLEAR_CHAR\": {\n const { index } = action;\n const newValue = value.slice();\n newValue[index] = \"\";\n flushSync(() => setValue(newValue));\n return;\n }\n\n case \"SUBMIT_CODE\": {\n const currentValue = value.join(\"\");\n onComplete?.(currentValue);\n hiddenInputRef.current?.form?.requestSubmit();\n break;\n }\n\n case \"PASTE\": {\n const { value } = action;\n const totalInputLength = inputs.length;\n\n const validatedValue = validateString(value);\n if (validatedValue.length === 0) return;\n\n const pastedCharacters = Array.from(value).slice(0, inputs.length);\n const emptySlots = Array(\n Math.max(0, totalInputLength - value.length)\n ).fill(\"\");\n\n flushSync(() => setValue([...pastedCharacters, ...emptySlots]));\n\n if (pastedCharacters.length === totalInputLength) {\n focusInput(inputs.at(-1));\n } else {\n focusInput(inputs.at(value.length));\n }\n return;\n }\n case \"NAVIGATE_PREVIOUS\": {\n const { index } = action;\n if (index > 0) {\n focusInput(inputs.at(index - 1));\n }\n return;\n }\n\n case \"NAVIGATE_NEXT\": {\n const { index } = action;\n if (value[index] && index < inputs.length - 1) {\n focusInput(inputs.at(index + 1));\n return;\n }\n\n const firstEmpty = Array.from({ length: inputs.length }).findIndex(\n (_, i) => !value[i]\n );\n\n // BUG: if a value was deleted in the middle of a sequence, then we would\n // not be able to navigate to the right side of the sequence\n\n focusInput(inputs.at(firstEmpty));\n return;\n }\n\n case \"CLEAR_ALL\": {\n flushSync(() => setValue([]));\n focusInput(inputs.at(0));\n return;\n }\n }\n };\n\n useEffect(() => {\n const concatenatedValue = value.join(\"\");\n const isCodeFullyEntered =\n concatenatedValue.length === inputCount &&\n value.every((v) => v !== \"\") &&\n inputCount > 0;\n\n if (!isCodeFullyEntered) return;\n\n onComplete?.(concatenatedValue);\n\n if (autoSubmit) {\n hiddenInputRef.current?.form?.requestSubmit();\n }\n }, [value, inputCount, onComplete, autoSubmit]);\n\n const contextValue = useMemo(\n () => ({\n dispatch,\n value,\n registerInputRef,\n name,\n hiddenInputRef,\n validation: validationConfig,\n type,\n focusedIndex,\n setFocusedIndex,\n disabled,\n inputCount,\n inputElements: inputElements.current,\n }),\n [value, focusedIndex, disabled, name, type, inputCount]\n );\n\n return (\n <AuthCodeContext.Provider value={contextValue}>\n <div\n // Delegating all input's paste event this parent handler\n // because we want to control the paste for all inputs.\n ref={forwardedRef}\n onPaste={(event) => {\n event.preventDefault();\n const clipboardData = event.clipboardData;\n const pastedText = clipboardData.getData(\"text/plain\");\n\n dispatch({ type: \"PASTE\", value: pastedText });\n }}\n {...divProps}\n >\n <AuthCodeHiddenInput />\n {children}\n </div>\n </AuthCodeContext.Provider>\n );\n }\n);\n\nconst AuthCodeHiddenInput = forwardRef<\n HTMLInputElement,\n Omit<React.ComponentProps<\"input\">, \"ref\">\n>(function AuthCodeHiddenInput(props, ref) {\n const context = useAuthCodeContext();\n const { name, value, hiddenInputRef } = context;\n const memoizedRefs = useCallback(mergeRefs(ref, hiddenInputRef), [\n ref,\n hiddenInputRef,\n ]);\n return (\n <input\n ref={memoizedRefs}\n name={name}\n value={value.join(\"\")}\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n autoSave=\"off\"\n inputMode=\"numeric\"\n autoComplete=\"one-time-code\"\n required\n {...props}\n type=\"hidden\"\n />\n );\n});\n\n/**\n * Input component for entering a single character of the auth code.\n *\n * **Must be used within `<AuthCode.Group>`**\n *\n * @example\n *\n * <AuthCode.Group>\n * <AuthCode.Input index={0} />\n * <AuthCode.Input index={1} />\n * </AuthCode.Group>\n * */\nexport function AuthCodeInput({ index, ...props }: AuthCodeInputProps) {\n const context = useAuthCodeContext();\n const {\n dispatch,\n registerInputRef,\n validation,\n focusedIndex,\n setFocusedIndex,\n disabled,\n inputCount,\n } = context;\n\n const currentCharacter = context.value[index] || \"\";\n const firstEmptyIndex = Array.from({ length: inputCount }).findIndex(\n (_, i) => !context.value[i]\n );\n const nextEmptyOrLastIndex =\n firstEmptyIndex === -1 ? inputCount - 1 : firstEmptyIndex;\n const mergedInputRef = useCallback(mergeRefs(registerInputRef), [\n registerInputRef,\n ]);\n return (\n <input\n type={context.type}\n tabIndex={index === focusedIndex ? 0 : -1}\n ref={mergedInputRef}\n inputMode={validation.inputMode}\n pattern={validation.pattern}\n aria-label={`One Time Password Character ${\n index + 1\n } out of ${inputCount}`}\n disabled={disabled}\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n // Disable password managers\n data-1p-ignore // 1Password\n data-lpignore=\"true\" // LastPass\n data-form-type=\"other\" // Generic password managers\n data-bwignore=\"true\" // Bitwarden\n {...props}\n onPointerDown={(event) => {\n // A click/touch on an input can cause the input to be out of selection so\n // we must prevent that default action and keep the input selected\n // in order to have a singular value\n event.preventDefault();\n const focusTargetIndex = Math.min(index, nextEmptyOrLastIndex);\n const focusTargetElement = Array.from(context.inputElements.keys())[\n focusTargetIndex\n ];\n focusInput(focusTargetElement);\n }}\n onFocus={(event) => {\n // select entire input instead of just focus\n event.target.select();\n setFocusedIndex(index);\n }}\n onInput={(event) => {\n const newInputValue = event.currentTarget.value;\n\n // Only treat as paste if it's an actual paste operation or truly long input\n // Single character duplicates (like \"11\" from typing \"1\" on \"1\") should go through onChange\n const browserInputType = (event.nativeEvent as InputEvent).inputType;\n const isPasteOperation =\n browserInputType === \"insertFromPaste\" ||\n browserInputType === \"insertFromDrop\";\n const isLongInput = newInputValue.length > 2;\n\n if (isPasteOperation || isLongInput) {\n event.preventDefault();\n dispatch({ type: \"PASTE\", value: newInputValue });\n }\n }}\n onChange={(event) => {\n const newInputValue = event.target.value;\n // check if value is valid against pattern\n if (event.target.validity.patternMismatch) return;\n dispatch({ type: \"TYPE_CHAR\", char: newInputValue, index });\n }}\n onKeyDown={mergeEventHandlers(props.onKeyDown, (event) => {\n // onKeyDown describes the intent of the user's key(s) presses\n if (event.metaKey && event.key == \"c\") return;\n\n if (\n isUndoShortcut(event) ||\n isCopyShortcut(event) ||\n isRedoShortcut(event)\n ) {\n event.preventDefault();\n return;\n }\n\n if ((event.metaKey || event.ctrlKey) && event.key === \"Backspace\") {\n dispatch({ type: \"CLEAR_ALL\" });\n return;\n }\n\n switch (event.key) {\n case \"Delete\":\n case \"Backspace\": {\n event.preventDefault();\n dispatch({ type: \"REMOVE_CHAR\", index });\n return;\n }\n\n case \"Enter\": {\n dispatch({ type: \"SUBMIT_CODE\" });\n return;\n }\n\n case \"ArrowLeft\": {\n event.preventDefault();\n dispatch({ type: \"NAVIGATE_PREVIOUS\", index });\n return;\n }\n case \"ArrowRight\": {\n event.preventDefault();\n dispatch({ type: \"NAVIGATE_NEXT\", index });\n return;\n }\n\n // Prevents up and down movements from unselecting\n case \"ArrowUp\":\n case \"ArrowDown\": {\n event.preventDefault();\n return;\n }\n\n default:\n if (event.key === currentCharacter) {\n // this is essentially focusing the next input\n dispatch({ type: \"TYPE_CHAR\", char: currentCharacter, index });\n return;\n }\n\n if (event.metaKey || event.ctrlKey) {\n return;\n }\n\n const hasValue = !!event.currentTarget.value;\n const isFullySelected =\n event.currentTarget.selectionStart === 0 &&\n event.currentTarget.selectionEnd != null &&\n event.currentTarget.selectionEnd > 0;\n\n // When input has value and is fully selected, validate the incoming key\n // to prevent selection loss from invalid keystrokes\n if (hasValue && isFullySelected) {\n // Only validate printable single characters (ignore modifiers, arrows, etc.)\n if (event.key.length === 1) {\n const isValid = validation.regex.test(event.key);\n if (!isValid) {\n event.preventDefault();\n return;\n }\n }\n }\n }\n })}\n value={currentCharacter}\n />\n );\n}\n\n// =================================================\n// CONTEXT\n// =================================================\n\nconst AuthCodeContext = createContext<AuthCodeContextValue | null>(null);\n\nfunction useAuthCodeContext() {\n const value = useContext(AuthCodeContext);\n if (!value) {\n throw new Error(\n \"\\n[awesome-auth-input] <AuthCode.Input> must be used within <AuthCode.Group>.\\n\\n\" +\n \"Make sure all <AuthCode.Input> components are children of <AuthCode.Group>:\\n\\n\" +\n \"Example:\\n\" +\n \" <AuthCode.Group>\\n\" +\n \" <AuthCode.Input index={0} />\\n\" +\n \" <AuthCode.Input index={1} />\\n\" +\n \" </AuthCode.Group>\\n\"\n );\n }\n return value;\n}\n\n// =================================================\n// HELPERS & HOOKS\n// =================================================\n\nfunction mergeEventHandlers<E extends { defaultPrevented: boolean }>(\n currentHandler?: (event: E) => void,\n nextHandler?: (event: E) => void\n) {\n return (event: E) => {\n currentHandler?.(event);\n\n if (!event.defaultPrevented) {\n nextHandler?.(event);\n }\n };\n}\n\nfunction isUndoShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (event.metaKey || event.ctrlKey) && event.key === \"z\";\n}\n\nfunction isRedoShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (\n (event.metaKey || event.ctrlKey) &&\n (event.key === \"y\" || (event.shiftKey && event.key === \"z\"))\n );\n}\n\nfunction isCopyShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (event.metaKey || event.ctrlKey) && event.key === \"c\";\n}\n\ntype MergedRef<T> = Ref<T> | undefined | null;\nfunction mergeRefs<T = any>(...refs: MergedRef<T>[]): React.RefCallback<T> {\n return function (node) {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref != null) {\n ref.current = node;\n }\n });\n };\n}\n\nconst focusInput = (element: HTMLInputElement | undefined) => {\n if (!element) return;\n if (element.disabled) return;\n // ownerDocument is the opened 'window' that owns the element\n // e.g. popups or a browser-in-browser\n if (element.ownerDocument.activeElement === element) {\n element.select();\n } else {\n element.focus();\n }\n};\n\nfunction useControllableState<T>({\n defaultValue,\n onValueChange,\n value,\n}: {\n defaultValue: T;\n onValueChange?: (value: T) => void;\n value?: T;\n}): [T, (newValue: T) => void] {\n const [internalState, setInternalState] = useState<T>(defaultValue);\n\n const isControlled = value !== undefined;\n const currentValue = isControlled ? value : internalState;\n\n const setState = useCallback(\n (newValue: T) => {\n if (!isControlled) {\n setInternalState(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange]\n );\n\n return [currentValue, setState];\n}\n\n// =================================================\n// INTERNAL TYPES & CONFIG\n// =================================================\n\ntype InputMode = \"text\" | \"numeric\" | \"none\";\n\ntype ValidationPattern =\n | ({ type: \"custom\" } & CustomValidation)\n | { type: \"alpha\" }\n | { type: \"alphanumeric\" }\n | { type: \"numeric\" };\n\ntype CustomValidation = {\n regex: RegExp;\n pattern: string;\n inputMode: InputMode;\n};\n\ninterface AuthCodeInputProps\n extends Omit<\n React.ComponentProps<\"input\">,\n | \"value\"\n | \"placeholder\"\n | \"disabled\"\n | \"autoComplete\"\n | \"defaultValue\"\n | \"type\"\n > {\n index: number;\n}\n\ninterface AuthCodeContextValue {\n dispatch: React.Dispatch<FieldUpdateAction>;\n value: string[];\n registerInputRef: (ref: HTMLInputElement | null) => void;\n name?: string;\n hiddenInputRef: Ref<HTMLInputElement | null>;\n validation:\n | (typeof defaultPatternInputMap)[DefaultInputTypes]\n | ({ type: \"custom\" } & CustomValidation);\n type: \"text\" | \"password\";\n focusedIndex: number;\n setFocusedIndex: (index: number) => void;\n disabled: boolean;\n inputCount: number;\n inputElements: Map<HTMLInputElement, true>;\n}\n\ntype DefaultInputTypes = \"alpha\" | \"alphanumeric\" | \"numeric\";\n\nconst numericRegex = /^\\d$/;\nconst alphaNumericRegex = /^[a-zA-Z\\d]$/;\nconst alphaRegex = /^[a-zA-Z]$/;\n\nconst defaultPatternInputMap = {\n alpha: {\n type: \"alpha\",\n regex: alphaRegex,\n pattern: \"[a-zA-Z]{1}\",\n inputMode: \"text\",\n },\n alphanumeric: {\n type: \"alphanumeric\",\n regex: alphaNumericRegex,\n pattern: \"[a-zA-Z0-9]{1}\",\n inputMode: \"text\",\n },\n numeric: {\n type: \"numeric\",\n regex: numericRegex,\n pattern: \"[0-9]{1}\",\n inputMode: \"numeric\",\n },\n} as const;\n\ntype FieldUpdateAction =\n | {\n type: \"TYPE_CHAR\";\n char: string;\n index: number;\n }\n | { type: \"PASTE\"; value: string }\n | { type: \"REMOVE_CHAR\"; index: number }\n | { type: \"SUBMIT_CODE\" }\n | { type: \"CLEAR_CHAR\"; index: number }\n | { type: \"NAVIGATE_PREVIOUS\"; index: number }\n | { type: \"NAVIGATE_NEXT\"; index: number }\n | { type: \"CLEAR_ALL\" };\n\n// =================================================\n// EXPORTS\n// =================================================\n\nexport {\n AuthCodeField as Group,\n AuthCodeInput as Input,\n AuthCodeHiddenInput as HiddenInput,\n};\n\nexport type {\n AuthCodeFieldProps as AuthCodeGroupProps,\n AuthCodeInputProps,\n ValidationPattern,\n CustomValidation,\n};\n","/**\n * awesome-auth-input\n * A headless, accessible React component for OTP/auth code inputs\n */\n\nimport {\n Group,\n Input,\n HiddenInput,\n} from \"./AuthCode/OneTimePassword\";\n\nexport type {\n AuthCodeGroupProps,\n AuthCodeInputProps,\n ValidationPattern,\n CustomValidation,\n} from \"./AuthCode/OneTimePassword\";\n\n/**\n * AuthCode - A compound component for OTP/auth code inputs\n *\n * @example\n * ```tsx\n * <AuthCode.Group onComplete={(code) => console.log(code)}>\n * <AuthCode.Input index={0} />\n * <AuthCode.Input index={1} />\n * <AuthCode.Input index={2} />\n * <AuthCode.Input index={3} />\n * </AuthCode.Group>\n * ```\n */\nconst AuthCode = {\n /**\n * The root component that manages state and validation for auth code inputs.\n * All `<AuthCode.Input>` components must be children of this component.\n */\n Group,\n /**\n * Individual input field for a single character of the auth code.\n * Must be used within `<AuthCode.Group>`.\n */\n Input,\n /**\n * Hidden input that contains the full auth code value for form submission.\n * Automatically rendered by Group, but can be customized if needed.\n */\n HiddenInput,\n};\n\nexport { AuthCode };\n\n// Also export individual components for tree-shaking\nexport { Group as AuthCodeGroup, Input as AuthCodeInput, HiddenInput as AuthCodeHiddenInput };\n\n"],"names":["forwardRef","AuthCodeField","useRef","useState","useCallback","flushSync","value","useEffect","useMemo","jsx","jsxs","AuthCodeHiddenInput","createContext","useContext","Group","Input","HiddenInput"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/AuthCode/OneTimePassword.tsx","../src/index.ts"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useRef,\n useState,\n type ReactNode,\n type Ref,\n useMemo,\n useEffect,\n forwardRef,\n} from \"react\";\nimport { flushSync } from \"react-dom\";\n\ninterface AuthCodeCustomField {\n /**\n * The child components, typically `<AuthCode.Input>` components.\n *\n * All `<AuthCode.Input>` components must be direct or nested children of `<AuthCode.Group>`.\n */\n children: ReactNode;\n /**\n * A string specifying a name for the input control. This name is submitted\n * along with the control's value when the form data is submitted.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#name\n */\n name?: string;\n /**\n * Specifies what type of validation the user agent has to provide for each\n * character input. Allows \"numeric\", \"alpha\", \"alphanumeric\", or a custom\n * validation pattern with regex.\n *\n * @defaultValue `{ type: \"numeric\" }`\n *\n * @example\n * ```tsx\n * // Numeric only (default)\n * <AuthCode.Group validation={{ type: \"numeric\" }} />\n *\n * // Alphabetic only\n * <AuthCode.Group validation={{ type: \"alpha\" }} />\n *\n * // Custom validation\n * <AuthCode.Group\n * validation={{\n * type: \"custom\",\n * regex: /^[A-Z]$/,\n * pattern: \"[A-Z]{1}\",\n * inputMode: \"text\"\n * }}\n * />\n * ```\n */\n validation?: ValidationPattern;\n /**\n * Whether or not the component should attempt to automatically submit when\n * all fields are filled. If the field is associated with an HTML `form`\n * element, the form's `requestSubmit` method will be called.\n *\n * @defaultValue `true`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit\n */\n autoSubmit?: boolean;\n /**\n * When the `autoSubmit` prop is set to `true`, this callback will be fired\n * before attempting to submit the associated form. It will be called whether\n * or not a form is located, or if submission is not allowed.\n *\n * The callback receives the complete auth code value as a string.\n *\n * @example\n * ```tsx\n * <AuthCode.Group\n * onComplete={(value) => {\n * console.log('Code entered:', value);\n * verifyCode(value);\n * }}\n * />\n * ```\n */\n onComplete?: (value: string) => void;\n /**\n * The controlled value of the field. When provided, the component operates\n * in controlled mode. This string's value, if present, must match the total\n * number of `<AuthCode.Input>` components.\n *\n * @example\n * ```tsx\n * const [code, setCode] = useState('');\n * <AuthCode.Group value={code} onValueChange={setCode} />\n * ```\n */\n value?: string;\n /**\n * A callback fired whenever the field value changes. This callback is called\n * with the complete auth code value as a string.\n *\n * Use this prop together with `value` to create a controlled component.\n */\n onValueChange?: (value: string) => void;\n /**\n * The initial value of the uncontrolled field. When provided without `value`,\n * the component operates in uncontrolled mode.\n *\n * @example\n * ```tsx\n * <AuthCode.Group defaultValue=\"123\" />\n * ```\n */\n defaultValue?: string;\n /**\n * The type of control to render. Allows \"text\" or \"password\".\n *\n * When set to \"password\", the input characters will be masked.\n *\n * @defaultValue `\"text\"`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#type\n */\n type?: \"text\" | \"password\";\n /**\n * Whether or not the input elements are disabled.\n *\n * When set to `true`, all `<AuthCode.Input>` components will be disabled\n * and users will not be able to interact with them.\n *\n * @defaultValue `false`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled\n */\n disabled?: boolean;\n}\n\ninterface AuthCodeFieldProps\n extends AuthCodeCustomField,\n Omit<React.ComponentProps<\"div\">, keyof AuthCodeCustomField> {}\n\nconst AuthCodeField = forwardRef<HTMLDivElement, AuthCodeFieldProps>(\n function AuthCodeField(\n {\n children,\n name,\n validation = { type: \"numeric\" },\n autoSubmit = true,\n onComplete,\n value: userValue,\n onValueChange: userOnValueChange,\n defaultValue,\n type = \"text\",\n disabled = false,\n ...divProps\n }: AuthCodeFieldProps,\n forwardedRef\n ) {\n const inputElements = useRef<Map<HTMLInputElement, number>>(new Map());\n const [value, setValue] = useControllableState<string[]>({\n value: userValue !== undefined ? Array.from(userValue) : undefined,\n defaultValue: defaultValue ? Array.from(defaultValue) : [],\n onValueChange: userOnValueChange\n ? (chars) => userOnValueChange(chars.join(\"\"))\n : undefined,\n });\n\n const validationConfig =\n validation.type == \"custom\"\n ? validation\n : defaultPatternInputMap[validation.type];\n\n const [focusedIndex, setFocusedIndex] = useState(0);\n const [inputCount, setInputCount] = useState(0);\n\n const registerInputRef = useCallback((ref: HTMLInputElement | null) => {\n if (ref) {\n if (!inputElements.current.has(ref)) {\n const position = inputElements.current.size;\n inputElements.current.set(ref, position);\n setInputCount(inputElements.current.size);\n }\n }\n }, []);\n\n const validateChar = useCallback(\n (char: string): boolean => {\n if (!char) return true;\n\n const regex = validationConfig.regex;\n return regex.test(char);\n },\n [validationConfig]\n );\n\n const validateString = useCallback(\n (str: string): string => {\n return Array.from(str)\n .filter((char) => validateChar(char))\n .join(\"\");\n },\n [validateChar]\n );\n\n const hiddenInputRef = useRef<HTMLInputElement | null>(null);\n\n const dispatch = (action: FieldUpdateAction) => {\n // use an ordered dictionary instead?\n const inputs = Array.from(inputElements.current.keys());\n switch (action.type) {\n case \"TYPE_CHAR\": {\n const { char, index: targetIndex } = action;\n\n if (!validateChar(char)) return;\n\n const hasExistingValue = !!value[targetIndex];\n const firstEmptyIndex = Array.from({\n length: inputs.length,\n }).findIndex((_, i) => !value[i]);\n\n const insertionIndex =\n hasExistingValue || firstEmptyIndex === -1\n ? targetIndex\n : firstEmptyIndex;\n\n const newValue = Array.from({ length: inputs.length }, (_, i) => {\n if (i === insertionIndex) return char;\n return value[i] ?? \"\";\n });\n\n flushSync(() => {\n setValue(newValue);\n });\n\n if (insertionIndex < inputs.length - 1) {\n requestAnimationFrame(() =>\n focusInput(inputs.at(insertionIndex + 1))\n );\n } else {\n requestAnimationFrame(() => {\n focusInput(inputs.at(insertionIndex));\n });\n }\n return;\n }\n\n case \"REMOVE_CHAR\": {\n const { index } = action;\n const totalInputLength = inputs.length;\n\n // Remove character and shift remaining values left\n const leftPortion = value.slice(0, index);\n const rightPortion = value.slice(index + 1);\n const compacted = leftPortion.concat(rightPortion);\n const emptySlots = Array(\n Math.max(0, totalInputLength - compacted.length)\n ).fill(\"\");\n\n flushSync(() => setValue(compacted.concat(emptySlots)));\n\n if (index != 0) {\n focusInput(inputs.at(index - 1));\n } else {\n focusInput(inputs.at(0));\n }\n return;\n }\n\n case \"CLEAR_CHAR\": {\n const { index } = action;\n const newValue = value.slice();\n newValue[index] = \"\";\n flushSync(() => setValue(newValue));\n return;\n }\n\n case \"SUBMIT_CODE\": {\n const currentValue = value.join(\"\");\n onComplete?.(currentValue);\n hiddenInputRef.current?.form?.requestSubmit();\n break;\n }\n\n case \"PASTE\": {\n const { value } = action;\n const totalInputLength = inputs.length;\n\n const validatedValue = validateString(value);\n if (validatedValue.length === 0) return;\n\n const pastedCharacters = Array.from(value).slice(0, inputs.length);\n const emptySlots = Array(\n Math.max(0, totalInputLength - value.length)\n ).fill(\"\");\n\n flushSync(() => setValue([...pastedCharacters, ...emptySlots]));\n\n if (pastedCharacters.length === totalInputLength) {\n focusInput(inputs.at(-1));\n } else {\n focusInput(inputs.at(value.length));\n }\n return;\n }\n case \"NAVIGATE_PREVIOUS\": {\n const { index } = action;\n if (index > 0) {\n focusInput(inputs.at(index - 1));\n }\n return;\n }\n\n case \"NAVIGATE_NEXT\": {\n const { index } = action;\n if (value[index] && index < inputs.length - 1) {\n focusInput(inputs.at(index + 1));\n return;\n }\n\n const firstEmpty = Array.from({ length: inputs.length }).findIndex(\n (_, i) => !value[i]\n );\n\n focusInput(inputs.at(firstEmpty));\n return;\n }\n\n case \"CLEAR_ALL\": {\n flushSync(() => setValue([]));\n focusInput(inputs.at(0));\n return;\n }\n }\n };\n\n const concatenatedValue = useMemo(() => value.join(\"\"), [value]);\n\n useEffect(() => {\n if (value.length === 0) {\n setFocusedIndex(0);\n }\n }, [value]);\n\n useEffect(() => {\n const isCodeFullyEntered =\n concatenatedValue.length === inputCount &&\n value.every((v) => v !== \"\") &&\n inputCount > 0;\n\n if (!isCodeFullyEntered) return;\n\n onComplete?.(concatenatedValue);\n\n if (autoSubmit) {\n hiddenInputRef.current?.form?.requestSubmit();\n }\n }, [concatenatedValue, onComplete, inputCount, autoSubmit]);\n\n const contextValue = useMemo(\n () => ({\n dispatch,\n value,\n registerInputRef,\n name,\n hiddenInputRef,\n validation: validationConfig,\n type,\n focusedIndex,\n setFocusedIndex,\n disabled,\n inputCount,\n inputElements: inputElements.current,\n }),\n [value, focusedIndex, disabled, name, type, inputCount]\n );\n\n return (\n <AuthCodeContext.Provider value={contextValue}>\n <div\n // Delegating all input's paste event this parent handler\n // because we want to control the paste for all inputs.\n ref={forwardedRef}\n onPaste={(event) => {\n event.preventDefault();\n const clipboardData = event.clipboardData;\n const pastedText = clipboardData.getData(\"text/plain\");\n\n dispatch({ type: \"PASTE\", value: pastedText });\n }}\n {...divProps}\n onCopy={mergeEventHandlers(divProps.onCopy, (event) => {\n event.preventDefault();\n event.clipboardData.setData(\"text/plain\", value.join(\"\"));\n })}\n >\n <AuthCodeHiddenInput />\n {children}\n </div>\n </AuthCodeContext.Provider>\n );\n }\n);\n\nAuthCodeField.displayName = \"AuthCode.Group\";\n\nconst AuthCodeHiddenInput = forwardRef<\n HTMLInputElement,\n Omit<React.ComponentProps<\"input\">, \"ref\">\n>(function AuthCodeHiddenInput(props, ref) {\n const context = useAuthCodeContext();\n const { name, value, hiddenInputRef } = context;\n const memoizedRefs = useCallback(mergeRefs(ref, hiddenInputRef), [\n ref,\n hiddenInputRef,\n ]);\n return (\n <input\n ref={memoizedRefs}\n name={name}\n value={value.join(\"\")}\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n autoSave=\"off\"\n inputMode=\"numeric\"\n autoComplete=\"one-time-code\"\n required\n {...props}\n type=\"hidden\"\n />\n );\n});\n\nAuthCodeHiddenInput.displayName = \"AuthCode.HiddenInput\";\n\n/**\n * Input component for entering a single character of the auth code.\n *\n * **Must be used within `<AuthCode.Group>`**\n *\n * @example\n *\n * <AuthCode.Group>\n * <AuthCode.Input index={0} />\n * <AuthCode.Input index={1} />\n * </AuthCode.Group>\n * */\nexport function AuthCodeInput({ index, ...props }: AuthCodeInputProps) {\n const context = useAuthCodeContext();\n const {\n dispatch,\n registerInputRef,\n validation,\n focusedIndex,\n setFocusedIndex,\n disabled,\n inputCount,\n inputElements,\n } = context;\n\n const currentCharacter = context.value[index] || \"\";\n const firstEmptyIndex = Array.from({ length: inputCount }).findIndex(\n (_, i) => !context.value[i]\n );\n const nextEmptyOrLastIndex =\n firstEmptyIndex === -1 ? inputCount - 1 : firstEmptyIndex;\n const inputRef = useRef<HTMLInputElement | null>(null);\n const mergedInputRef = useCallback(mergeRefs(registerInputRef, inputRef), [\n registerInputRef,\n ]);\n\n const inputPosition = inputRef.current\n ? (inputElements.get(inputRef.current) ?? 0) + 1\n : index + 1;\n\n return (\n <input\n type={context.type}\n tabIndex={index === focusedIndex ? 0 : -1}\n ref={mergedInputRef}\n inputMode={validation.inputMode}\n pattern={validation.pattern}\n aria-label={`One Time Password Character ${inputPosition} out of ${inputCount}`}\n disabled={disabled}\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n // Disable password managers\n data-1p-ignore // 1Password\n data-lpignore=\"true\" // LastPass\n data-bwignore=\"true\" // Bitwarden\n data-form-type=\"other\" // Generic password managers\n {...props}\n onPointerDown={(event) => {\n // A click/touch on an input can cause the input to be out of selection so\n // we must prevent that default action and keep the input selected\n // in order to have a singular value\n event.preventDefault();\n const focusTargetIndex = Math.min(index, nextEmptyOrLastIndex);\n const focusTargetElement = Array.from(context.inputElements.keys())[\n focusTargetIndex\n ];\n focusInput(focusTargetElement);\n }}\n onFocus={(event) => {\n // select entire input instead of just focus\n event.target.select();\n setFocusedIndex(index);\n }}\n onInput={(event) => {\n const newInputValue = event.currentTarget.value;\n\n // Only treat as paste if it's an actual paste operation or truly long input\n // Single character duplicates (like \"11\" from typing \"1\" on \"1\") should go through onChange\n const browserInputType = (event.nativeEvent as InputEvent).inputType;\n const isPasteOperation =\n browserInputType === \"insertFromPaste\" ||\n browserInputType === \"insertFromDrop\";\n const isLongInput = newInputValue.length > 2;\n\n if (isPasteOperation || isLongInput) {\n event.preventDefault();\n dispatch({ type: \"PASTE\", value: newInputValue });\n }\n }}\n onChange={(event) => {\n const newInputValue = event.target.value;\n // check if value is valid against pattern\n if (event.target.validity.patternMismatch) return;\n dispatch({ type: \"TYPE_CHAR\", char: newInputValue, index });\n }}\n onKeyDown={mergeEventHandlers(props.onKeyDown, (event) => {\n // onKeyDown describes the intent of the user's key(s) presses\n if (event.metaKey && event.key == \"c\") return;\n\n if (\n isUndoShortcut(event) ||\n isCopyShortcut(event) ||\n isRedoShortcut(event)\n ) {\n event.preventDefault();\n return;\n }\n\n if ((event.metaKey || event.ctrlKey) && event.key === \"Backspace\") {\n dispatch({ type: \"CLEAR_ALL\" });\n return;\n }\n\n switch (event.key) {\n case \"Delete\":\n case \"Backspace\": {\n event.preventDefault();\n dispatch({ type: \"REMOVE_CHAR\", index });\n return;\n }\n\n case \"Enter\": {\n dispatch({ type: \"SUBMIT_CODE\" });\n return;\n }\n\n case \"ArrowLeft\": {\n event.preventDefault();\n dispatch({ type: \"NAVIGATE_PREVIOUS\", index });\n return;\n }\n case \"ArrowRight\": {\n event.preventDefault();\n dispatch({ type: \"NAVIGATE_NEXT\", index });\n return;\n }\n\n // Prevents up and down movements from unselecting\n case \"ArrowUp\":\n case \"ArrowDown\": {\n event.preventDefault();\n return;\n }\n\n default:\n if (event.key === currentCharacter) {\n // this is essentially focusing the next input\n dispatch({ type: \"TYPE_CHAR\", char: currentCharacter, index });\n return;\n }\n\n if (event.metaKey || event.ctrlKey) {\n return;\n }\n\n const hasValue = !!event.currentTarget.value;\n const isFullySelected =\n event.currentTarget.selectionStart === 0 &&\n event.currentTarget.selectionEnd != null &&\n event.currentTarget.selectionEnd > 0;\n\n // When input has value and is fully selected, validate the incoming key\n // to prevent selection loss from invalid keystrokes\n if (hasValue && isFullySelected) {\n // Only validate printable single characters (ignore modifiers, arrows, etc.)\n if (event.key.length === 1) {\n const isValid = validation.regex.test(event.key);\n if (!isValid) {\n event.preventDefault();\n return;\n }\n }\n }\n }\n })}\n value={currentCharacter}\n />\n );\n}\n\nAuthCodeInput.displayName = \"AuthCode.Input\";\n\n// =================================================\n// CONTEXT\n// =================================================\n\nconst AuthCodeContext = createContext<AuthCodeContextValue | null>(null);\n\nfunction useAuthCodeContext() {\n const value = useContext(AuthCodeContext);\n if (!value) {\n throw new Error(\n \"\\n[awesome-auth-input] <AuthCode.Input> must be used within <AuthCode.Group>.\\n\\n\" +\n \"Make sure all <AuthCode.Input> components are children of <AuthCode.Group>:\\n\\n\" +\n \"Example:\\n\" +\n \" <AuthCode.Group>\\n\" +\n \" <AuthCode.Input index={0} />\\n\" +\n \" <AuthCode.Input index={1} />\\n\" +\n \" </AuthCode.Group>\\n\"\n );\n }\n return value;\n}\n\n// =================================================\n// HELPERS & HOOKS\n// =================================================\n\nfunction mergeEventHandlers<E extends { defaultPrevented: boolean }>(\n currentHandler?: (event: E) => void,\n nextHandler?: (event: E) => void\n) {\n return (event: E) => {\n currentHandler?.(event);\n\n if (!event.defaultPrevented) {\n nextHandler?.(event);\n }\n };\n}\n\nfunction isUndoShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (event.metaKey || event.ctrlKey) && event.key === \"z\";\n}\n\nfunction isRedoShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (\n (event.metaKey || event.ctrlKey) &&\n (event.key === \"y\" || (event.shiftKey && event.key === \"z\"))\n );\n}\n\nfunction isCopyShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (event.metaKey || event.ctrlKey) && event.key === \"c\";\n}\n\ntype MergedRef<T> = Ref<T> | undefined | null;\nfunction mergeRefs<T = any>(...refs: MergedRef<T>[]): React.RefCallback<T> {\n return function (node) {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref != null) {\n ref.current = node;\n }\n });\n };\n}\n\nconst focusInput = (element: HTMLInputElement | undefined) => {\n if (!element) return;\n if (element.disabled) return;\n\n // Using ownerDocument.activeElement to check focus correctly across\n // different document contexts (iframes, popups, shadow DOM)\n if (element.ownerDocument.activeElement === element) {\n element.select();\n } else {\n element.focus();\n }\n};\n\nfunction useControllableState<T>({\n defaultValue,\n onValueChange,\n value,\n}: {\n defaultValue: T;\n onValueChange?: (value: T) => void;\n value?: T;\n}): [T, (newValue: T) => void] {\n const [internalState, setInternalState] = useState<T>(defaultValue);\n\n const isControlled = value !== undefined;\n const currentValue = isControlled ? value : internalState;\n\n const setState = useCallback(\n (newValue: T) => {\n if (!isControlled) {\n setInternalState(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange]\n );\n\n return [currentValue, setState];\n}\n\n// =================================================\n// INTERNAL TYPES & CONFIG\n// =================================================\n\ntype InputMode = \"text\" | \"numeric\" | \"none\";\n\ntype ValidationPattern =\n | ({ type: \"custom\" } & CustomValidation)\n | { type: \"alpha\" }\n | { type: \"alphanumeric\" }\n | { type: \"numeric\" };\n\ntype CustomValidation = {\n regex: RegExp;\n pattern: string;\n inputMode: InputMode;\n};\n\ninterface AuthCodeInputProps\n extends Omit<\n React.ComponentProps<\"input\">,\n | \"value\"\n | \"placeholder\"\n | \"disabled\"\n | \"autoComplete\"\n | \"defaultValue\"\n | \"type\"\n > {\n index: number;\n}\n\ninterface AuthCodeContextValue {\n dispatch: React.Dispatch<FieldUpdateAction>;\n value: string[];\n registerInputRef: (ref: HTMLInputElement | null) => void;\n name?: string;\n hiddenInputRef: Ref<HTMLInputElement | null>;\n validation:\n | (typeof defaultPatternInputMap)[DefaultInputTypes]\n | ({ type: \"custom\" } & CustomValidation);\n type: \"text\" | \"password\";\n focusedIndex: number;\n setFocusedIndex: (index: number) => void;\n disabled: boolean;\n inputCount: number;\n inputElements: Map<HTMLInputElement, number>;\n}\n\ntype DefaultInputTypes = \"alpha\" | \"alphanumeric\" | \"numeric\";\n\nconst numericRegex = /^\\d$/;\nconst alphaNumericRegex = /^[a-zA-Z\\d]$/;\nconst alphaRegex = /^[a-zA-Z]$/;\n\nconst defaultPatternInputMap = {\n alpha: {\n type: \"alpha\",\n regex: alphaRegex,\n pattern: \"[a-zA-Z]{1}\",\n inputMode: \"text\",\n },\n alphanumeric: {\n type: \"alphanumeric\",\n regex: alphaNumericRegex,\n pattern: \"[a-zA-Z0-9]{1}\",\n inputMode: \"text\",\n },\n numeric: {\n type: \"numeric\",\n regex: numericRegex,\n pattern: \"[0-9]{1}\",\n inputMode: \"numeric\",\n },\n} as const;\n\ntype FieldUpdateAction =\n | {\n type: \"TYPE_CHAR\";\n char: string;\n index: number;\n }\n | { type: \"PASTE\"; value: string }\n | { type: \"REMOVE_CHAR\"; index: number }\n | { type: \"SUBMIT_CODE\" }\n | { type: \"CLEAR_CHAR\"; index: number }\n | { type: \"NAVIGATE_PREVIOUS\"; index: number }\n | { type: \"NAVIGATE_NEXT\"; index: number }\n | { type: \"CLEAR_ALL\" };\n\n// =================================================\n// EXPORTS\n// =================================================\n\nexport {\n AuthCodeField as Group,\n AuthCodeInput as Input,\n AuthCodeHiddenInput as HiddenInput,\n};\n\nexport type {\n AuthCodeFieldProps as AuthCodeGroupProps,\n AuthCodeInputProps,\n ValidationPattern,\n CustomValidation,\n};\n","/**\n * awesome-auth-input\n * A headless, accessible React component for OTP/auth code inputs\n */\n\nimport {\n Group,\n Input,\n HiddenInput,\n} from \"./AuthCode/OneTimePassword\";\n\nexport type {\n AuthCodeGroupProps,\n AuthCodeInputProps,\n ValidationPattern,\n CustomValidation,\n} from \"./AuthCode/OneTimePassword\";\n\n/**\n * AuthCode - A compound component for OTP/auth code inputs\n *\n * @example\n * ```tsx\n * <AuthCode.Group onComplete={(code) => console.log(code)}>\n * <AuthCode.Input index={0} />\n * <AuthCode.Input index={1} />\n * <AuthCode.Input index={2} />\n * <AuthCode.Input index={3} />\n * </AuthCode.Group>\n * ```\n */\nconst AuthCode = {\n /**\n * The root component that manages state and validation for auth code inputs.\n * All `<AuthCode.Input>` components must be children of this component.\n */\n Group,\n /**\n * Individual input field for a single character of the auth code.\n * Must be used within `<AuthCode.Group>`.\n */\n Input,\n /**\n * Hidden input that contains the full auth code value for form submission.\n * Automatically rendered by Group, but can be customized if needed.\n */\n HiddenInput,\n};\n\nexport { AuthCode };\n\n// Also export individual components for tree-shaking\nexport { Group as AuthCodeGroup, Input as AuthCodeInput, HiddenInput as AuthCodeHiddenInput };\n\n"],"names":["forwardRef","AuthCodeField","useRef","useState","useCallback","flushSync","value","useMemo","useEffect","jsx","jsxs","AuthCodeHiddenInput","createContext","useContext","Group","Input","HiddenInput"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef, useRef, useState, useCallback,
|
|
2
|
+
import { forwardRef, useRef, useState, useCallback, useMemo, useEffect, createContext, useContext } from "react";
|
|
3
3
|
import { flushSync } from "react-dom";
|
|
4
4
|
const AuthCodeField = forwardRef(
|
|
5
5
|
function AuthCodeField2({
|
|
@@ -27,7 +27,8 @@ const AuthCodeField = forwardRef(
|
|
|
27
27
|
const registerInputRef = useCallback((ref) => {
|
|
28
28
|
if (ref) {
|
|
29
29
|
if (!inputElements.current.has(ref)) {
|
|
30
|
-
inputElements.current.
|
|
30
|
+
const position = inputElements.current.size;
|
|
31
|
+
inputElements.current.set(ref, position);
|
|
31
32
|
setInputCount(inputElements.current.size);
|
|
32
33
|
}
|
|
33
34
|
}
|
|
@@ -63,13 +64,17 @@ const AuthCodeField = forwardRef(
|
|
|
63
64
|
if (i === insertionIndex) return char;
|
|
64
65
|
return value[i] ?? "";
|
|
65
66
|
});
|
|
66
|
-
flushSync(() =>
|
|
67
|
+
flushSync(() => {
|
|
68
|
+
setValue(newValue);
|
|
69
|
+
});
|
|
67
70
|
if (insertionIndex < inputs.length - 1) {
|
|
68
71
|
requestAnimationFrame(
|
|
69
72
|
() => focusInput(inputs.at(insertionIndex + 1))
|
|
70
73
|
);
|
|
71
74
|
} else {
|
|
72
|
-
requestAnimationFrame(() =>
|
|
75
|
+
requestAnimationFrame(() => {
|
|
76
|
+
focusInput(inputs.at(insertionIndex));
|
|
77
|
+
});
|
|
73
78
|
}
|
|
74
79
|
return;
|
|
75
80
|
}
|
|
@@ -146,16 +151,21 @@ const AuthCodeField = forwardRef(
|
|
|
146
151
|
}
|
|
147
152
|
}
|
|
148
153
|
};
|
|
154
|
+
const concatenatedValue = useMemo(() => value.join(""), [value]);
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
if (value.length === 0) {
|
|
157
|
+
setFocusedIndex(0);
|
|
158
|
+
}
|
|
159
|
+
}, [value]);
|
|
149
160
|
useEffect(() => {
|
|
150
161
|
var _a, _b;
|
|
151
|
-
const concatenatedValue = value.join("");
|
|
152
162
|
const isCodeFullyEntered = concatenatedValue.length === inputCount && value.every((v) => v !== "") && inputCount > 0;
|
|
153
163
|
if (!isCodeFullyEntered) return;
|
|
154
164
|
onComplete == null ? void 0 : onComplete(concatenatedValue);
|
|
155
165
|
if (autoSubmit) {
|
|
156
166
|
(_b = (_a = hiddenInputRef.current) == null ? void 0 : _a.form) == null ? void 0 : _b.requestSubmit();
|
|
157
167
|
}
|
|
158
|
-
}, [
|
|
168
|
+
}, [concatenatedValue, onComplete, inputCount, autoSubmit]);
|
|
159
169
|
const contextValue = useMemo(
|
|
160
170
|
() => ({
|
|
161
171
|
dispatch,
|
|
@@ -184,6 +194,10 @@ const AuthCodeField = forwardRef(
|
|
|
184
194
|
dispatch({ type: "PASTE", value: pastedText });
|
|
185
195
|
},
|
|
186
196
|
...divProps,
|
|
197
|
+
onCopy: mergeEventHandlers(divProps.onCopy, (event) => {
|
|
198
|
+
event.preventDefault();
|
|
199
|
+
event.clipboardData.setData("text/plain", value.join(""));
|
|
200
|
+
}),
|
|
187
201
|
children: [
|
|
188
202
|
/* @__PURE__ */ jsx(AuthCodeHiddenInput, {}),
|
|
189
203
|
children
|
|
@@ -192,6 +206,7 @@ const AuthCodeField = forwardRef(
|
|
|
192
206
|
) });
|
|
193
207
|
}
|
|
194
208
|
);
|
|
209
|
+
AuthCodeField.displayName = "AuthCode.Group";
|
|
195
210
|
const AuthCodeHiddenInput = forwardRef(function AuthCodeHiddenInput2(props, ref) {
|
|
196
211
|
const context = useAuthCodeContext();
|
|
197
212
|
const { name, value, hiddenInputRef } = context;
|
|
@@ -216,6 +231,7 @@ const AuthCodeHiddenInput = forwardRef(function AuthCodeHiddenInput2(props, ref)
|
|
|
216
231
|
}
|
|
217
232
|
);
|
|
218
233
|
});
|
|
234
|
+
AuthCodeHiddenInput.displayName = "AuthCode.HiddenInput";
|
|
219
235
|
function AuthCodeInput({ index, ...props }) {
|
|
220
236
|
const context = useAuthCodeContext();
|
|
221
237
|
const {
|
|
@@ -225,16 +241,19 @@ function AuthCodeInput({ index, ...props }) {
|
|
|
225
241
|
focusedIndex,
|
|
226
242
|
setFocusedIndex,
|
|
227
243
|
disabled,
|
|
228
|
-
inputCount
|
|
244
|
+
inputCount,
|
|
245
|
+
inputElements
|
|
229
246
|
} = context;
|
|
230
247
|
const currentCharacter = context.value[index] || "";
|
|
231
248
|
const firstEmptyIndex = Array.from({ length: inputCount }).findIndex(
|
|
232
249
|
(_, i) => !context.value[i]
|
|
233
250
|
);
|
|
234
251
|
const nextEmptyOrLastIndex = firstEmptyIndex === -1 ? inputCount - 1 : firstEmptyIndex;
|
|
235
|
-
const
|
|
252
|
+
const inputRef = useRef(null);
|
|
253
|
+
const mergedInputRef = useCallback(mergeRefs(registerInputRef, inputRef), [
|
|
236
254
|
registerInputRef
|
|
237
255
|
]);
|
|
256
|
+
const inputPosition = inputRef.current ? (inputElements.get(inputRef.current) ?? 0) + 1 : index + 1;
|
|
238
257
|
return /* @__PURE__ */ jsx(
|
|
239
258
|
"input",
|
|
240
259
|
{
|
|
@@ -243,15 +262,15 @@ function AuthCodeInput({ index, ...props }) {
|
|
|
243
262
|
ref: mergedInputRef,
|
|
244
263
|
inputMode: validation.inputMode,
|
|
245
264
|
pattern: validation.pattern,
|
|
246
|
-
"aria-label": `One Time Password Character ${
|
|
265
|
+
"aria-label": `One Time Password Character ${inputPosition} out of ${inputCount}`,
|
|
247
266
|
disabled,
|
|
248
267
|
autoComplete: "off",
|
|
249
268
|
autoCorrect: "off",
|
|
250
269
|
autoCapitalize: "off",
|
|
251
270
|
"data-1p-ignore": true,
|
|
252
271
|
"data-lpignore": "true",
|
|
253
|
-
"data-form-type": "other",
|
|
254
272
|
"data-bwignore": "true",
|
|
273
|
+
"data-form-type": "other",
|
|
255
274
|
...props,
|
|
256
275
|
onPointerDown: (event) => {
|
|
257
276
|
event.preventDefault();
|
|
@@ -340,6 +359,7 @@ function AuthCodeInput({ index, ...props }) {
|
|
|
340
359
|
}
|
|
341
360
|
);
|
|
342
361
|
}
|
|
362
|
+
AuthCodeInput.displayName = "AuthCode.Input";
|
|
343
363
|
const AuthCodeContext = createContext(null);
|
|
344
364
|
function useAuthCodeContext() {
|
|
345
365
|
const value = useContext(AuthCodeContext);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/AuthCode/OneTimePassword.tsx","../src/index.ts"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useRef,\n useState,\n type ReactNode,\n type Ref,\n useMemo,\n useEffect,\n forwardRef,\n} from \"react\";\nimport { flushSync } from \"react-dom\";\n\ninterface AuthCodeCustomField {\n /**\n * The child components, typically `<AuthCode.Input>` components.\n *\n * All `<AuthCode.Input>` components must be direct or nested children of `<AuthCode.Group>`.\n */\n children: ReactNode;\n /**\n * A string specifying a name for the input control. This name is submitted\n * along with the control's value when the form data is submitted.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#name\n */\n name?: string;\n /**\n * Specifies what type of validation the user agent has to provide for each\n * character input. Allows \"numeric\", \"alpha\", \"alphanumeric\", or a custom\n * validation pattern with regex.\n *\n * @defaultValue `{ type: \"numeric\" }`\n *\n * @example\n * ```tsx\n * // Numeric only (default)\n * <AuthCode.Group validation={{ type: \"numeric\" }} />\n *\n * // Alphabetic only\n * <AuthCode.Group validation={{ type: \"alpha\" }} />\n *\n * // Custom validation\n * <AuthCode.Group\n * validation={{\n * type: \"custom\",\n * regex: /^[A-Z]$/,\n * pattern: \"[A-Z]{1}\",\n * inputMode: \"text\"\n * }}\n * />\n * ```\n */\n validation?: ValidationPattern;\n /**\n * Whether or not the component should attempt to automatically submit when\n * all fields are filled. If the field is associated with an HTML `form`\n * element, the form's `requestSubmit` method will be called.\n *\n * @defaultValue `true`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit\n */\n autoSubmit?: boolean;\n /**\n * When the `autoSubmit` prop is set to `true`, this callback will be fired\n * before attempting to submit the associated form. It will be called whether\n * or not a form is located, or if submission is not allowed.\n *\n * The callback receives the complete auth code value as a string.\n *\n * @example\n * ```tsx\n * <AuthCode.Group\n * onComplete={(value) => {\n * console.log('Code entered:', value);\n * verifyCode(value);\n * }}\n * />\n * ```\n */\n onComplete?: (value: string) => void;\n /**\n * The controlled value of the field. When provided, the component operates\n * in controlled mode. This string's value, if present, must match the total\n * number of `<AuthCode.Input>` components.\n *\n * @example\n * ```tsx\n * const [code, setCode] = useState('');\n * <AuthCode.Group value={code} onValueChange={setCode} />\n * ```\n */\n value?: string;\n /**\n * A callback fired whenever the field value changes. This callback is called\n * with the complete auth code value as a string.\n *\n * Use this prop together with `value` to create a controlled component.\n */\n onValueChange?: (value: string) => void;\n /**\n * The initial value of the uncontrolled field. When provided without `value`,\n * the component operates in uncontrolled mode.\n *\n * @example\n * ```tsx\n * <AuthCode.Group defaultValue=\"123\" />\n * ```\n */\n defaultValue?: string;\n /**\n * The type of control to render. Allows \"text\" or \"password\".\n *\n * When set to \"password\", the input characters will be masked.\n *\n * @defaultValue `\"text\"`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#type\n */\n type?: \"text\" | \"password\";\n /**\n * Whether or not the input elements are disabled.\n *\n * When set to `true`, all `<AuthCode.Input>` components will be disabled\n * and users will not be able to interact with them.\n *\n * @defaultValue `false`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled\n */\n disabled?: boolean;\n}\n\ninterface AuthCodeFieldProps\n extends AuthCodeCustomField,\n Omit<React.ComponentProps<\"div\">, keyof AuthCodeCustomField> {}\n\nconst AuthCodeField = forwardRef<HTMLDivElement, AuthCodeFieldProps>(\n function AuthCodeField(\n {\n children,\n name,\n validation = { type: \"numeric\" },\n autoSubmit = true,\n onComplete,\n value: userValue,\n onValueChange: userOnValueChange,\n defaultValue,\n type = \"text\",\n disabled = false,\n ...divProps\n }: AuthCodeFieldProps,\n forwardedRef\n ) {\n const inputElements = useRef<Map<HTMLInputElement, true>>(new Map());\n const [value, setValue] = useControllableState<string[]>({\n value: userValue !== undefined ? Array.from(userValue) : undefined,\n defaultValue: defaultValue ? Array.from(defaultValue) : [],\n onValueChange: userOnValueChange\n ? (chars) => userOnValueChange(chars.join(\"\"))\n : undefined,\n });\n\n const validationConfig =\n validation.type == \"custom\"\n ? validation\n : defaultPatternInputMap[validation.type];\n\n const [focusedIndex, setFocusedIndex] = useState(0);\n const [inputCount, setInputCount] = useState(0);\n\n const registerInputRef = useCallback((ref: HTMLInputElement | null) => {\n if (ref) {\n if (!inputElements.current.has(ref)) {\n inputElements.current.set(ref, true);\n setInputCount(inputElements.current.size);\n }\n }\n }, []);\n\n const validateChar = useCallback(\n (char: string): boolean => {\n if (!char) return true;\n\n const regex = validationConfig.regex;\n return regex.test(char);\n },\n [validationConfig]\n );\n\n const validateString = useCallback(\n (str: string): string => {\n return Array.from(str)\n .filter((char) => validateChar(char))\n .join(\"\");\n },\n [validateChar]\n );\n\n const hiddenInputRef = useRef<HTMLInputElement | null>(null);\n\n // consider removing useEffectEvent\n const dispatch = (action: FieldUpdateAction) => {\n // use an ordered dictionary instead?\n const inputs = Array.from(inputElements.current.keys());\n switch (action.type) {\n case \"TYPE_CHAR\": {\n const { char, index: targetIndex } = action;\n\n if (!validateChar(char)) return;\n\n const hasExistingValue = !!value[targetIndex];\n const firstEmptyIndex = Array.from({\n length: inputs.length,\n }).findIndex((_, i) => !value[i]);\n\n const insertionIndex =\n hasExistingValue || firstEmptyIndex === -1\n ? targetIndex\n : firstEmptyIndex;\n\n const newValue = Array.from({ length: inputs.length }, (_, i) => {\n if (i === insertionIndex) return char;\n return value[i] ?? \"\";\n });\n\n flushSync(() => setValue(newValue));\n\n if (insertionIndex < inputs.length - 1) {\n requestAnimationFrame(() =>\n focusInput(inputs.at(insertionIndex + 1))\n );\n } else {\n requestAnimationFrame(() => focusInput(inputs.at(insertionIndex)));\n }\n return;\n }\n\n case \"REMOVE_CHAR\": {\n const { index } = action;\n const totalInputLength = inputs.length;\n\n // Remove character and shift remaining values left\n const leftPortion = value.slice(0, index);\n const rightPortion = value.slice(index + 1);\n const compacted = leftPortion.concat(rightPortion);\n const emptySlots = Array(\n Math.max(0, totalInputLength - compacted.length)\n ).fill(\"\");\n\n flushSync(() => setValue(compacted.concat(emptySlots)));\n\n if (index != 0) {\n focusInput(inputs.at(index - 1));\n } else {\n // index is 0\n focusInput(inputs.at(0));\n }\n return;\n }\n\n case \"CLEAR_CHAR\": {\n const { index } = action;\n const newValue = value.slice();\n newValue[index] = \"\";\n flushSync(() => setValue(newValue));\n return;\n }\n\n case \"SUBMIT_CODE\": {\n const currentValue = value.join(\"\");\n onComplete?.(currentValue);\n hiddenInputRef.current?.form?.requestSubmit();\n break;\n }\n\n case \"PASTE\": {\n const { value } = action;\n const totalInputLength = inputs.length;\n\n const validatedValue = validateString(value);\n if (validatedValue.length === 0) return;\n\n const pastedCharacters = Array.from(value).slice(0, inputs.length);\n const emptySlots = Array(\n Math.max(0, totalInputLength - value.length)\n ).fill(\"\");\n\n flushSync(() => setValue([...pastedCharacters, ...emptySlots]));\n\n if (pastedCharacters.length === totalInputLength) {\n focusInput(inputs.at(-1));\n } else {\n focusInput(inputs.at(value.length));\n }\n return;\n }\n case \"NAVIGATE_PREVIOUS\": {\n const { index } = action;\n if (index > 0) {\n focusInput(inputs.at(index - 1));\n }\n return;\n }\n\n case \"NAVIGATE_NEXT\": {\n const { index } = action;\n if (value[index] && index < inputs.length - 1) {\n focusInput(inputs.at(index + 1));\n return;\n }\n\n const firstEmpty = Array.from({ length: inputs.length }).findIndex(\n (_, i) => !value[i]\n );\n\n // BUG: if a value was deleted in the middle of a sequence, then we would\n // not be able to navigate to the right side of the sequence\n\n focusInput(inputs.at(firstEmpty));\n return;\n }\n\n case \"CLEAR_ALL\": {\n flushSync(() => setValue([]));\n focusInput(inputs.at(0));\n return;\n }\n }\n };\n\n useEffect(() => {\n const concatenatedValue = value.join(\"\");\n const isCodeFullyEntered =\n concatenatedValue.length === inputCount &&\n value.every((v) => v !== \"\") &&\n inputCount > 0;\n\n if (!isCodeFullyEntered) return;\n\n onComplete?.(concatenatedValue);\n\n if (autoSubmit) {\n hiddenInputRef.current?.form?.requestSubmit();\n }\n }, [value, inputCount, onComplete, autoSubmit]);\n\n const contextValue = useMemo(\n () => ({\n dispatch,\n value,\n registerInputRef,\n name,\n hiddenInputRef,\n validation: validationConfig,\n type,\n focusedIndex,\n setFocusedIndex,\n disabled,\n inputCount,\n inputElements: inputElements.current,\n }),\n [value, focusedIndex, disabled, name, type, inputCount]\n );\n\n return (\n <AuthCodeContext.Provider value={contextValue}>\n <div\n // Delegating all input's paste event this parent handler\n // because we want to control the paste for all inputs.\n ref={forwardedRef}\n onPaste={(event) => {\n event.preventDefault();\n const clipboardData = event.clipboardData;\n const pastedText = clipboardData.getData(\"text/plain\");\n\n dispatch({ type: \"PASTE\", value: pastedText });\n }}\n {...divProps}\n >\n <AuthCodeHiddenInput />\n {children}\n </div>\n </AuthCodeContext.Provider>\n );\n }\n);\n\nconst AuthCodeHiddenInput = forwardRef<\n HTMLInputElement,\n Omit<React.ComponentProps<\"input\">, \"ref\">\n>(function AuthCodeHiddenInput(props, ref) {\n const context = useAuthCodeContext();\n const { name, value, hiddenInputRef } = context;\n const memoizedRefs = useCallback(mergeRefs(ref, hiddenInputRef), [\n ref,\n hiddenInputRef,\n ]);\n return (\n <input\n ref={memoizedRefs}\n name={name}\n value={value.join(\"\")}\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n autoSave=\"off\"\n inputMode=\"numeric\"\n autoComplete=\"one-time-code\"\n required\n {...props}\n type=\"hidden\"\n />\n );\n});\n\n/**\n * Input component for entering a single character of the auth code.\n *\n * **Must be used within `<AuthCode.Group>`**\n *\n * @example\n *\n * <AuthCode.Group>\n * <AuthCode.Input index={0} />\n * <AuthCode.Input index={1} />\n * </AuthCode.Group>\n * */\nexport function AuthCodeInput({ index, ...props }: AuthCodeInputProps) {\n const context = useAuthCodeContext();\n const {\n dispatch,\n registerInputRef,\n validation,\n focusedIndex,\n setFocusedIndex,\n disabled,\n inputCount,\n } = context;\n\n const currentCharacter = context.value[index] || \"\";\n const firstEmptyIndex = Array.from({ length: inputCount }).findIndex(\n (_, i) => !context.value[i]\n );\n const nextEmptyOrLastIndex =\n firstEmptyIndex === -1 ? inputCount - 1 : firstEmptyIndex;\n const mergedInputRef = useCallback(mergeRefs(registerInputRef), [\n registerInputRef,\n ]);\n return (\n <input\n type={context.type}\n tabIndex={index === focusedIndex ? 0 : -1}\n ref={mergedInputRef}\n inputMode={validation.inputMode}\n pattern={validation.pattern}\n aria-label={`One Time Password Character ${\n index + 1\n } out of ${inputCount}`}\n disabled={disabled}\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n // Disable password managers\n data-1p-ignore // 1Password\n data-lpignore=\"true\" // LastPass\n data-form-type=\"other\" // Generic password managers\n data-bwignore=\"true\" // Bitwarden\n {...props}\n onPointerDown={(event) => {\n // A click/touch on an input can cause the input to be out of selection so\n // we must prevent that default action and keep the input selected\n // in order to have a singular value\n event.preventDefault();\n const focusTargetIndex = Math.min(index, nextEmptyOrLastIndex);\n const focusTargetElement = Array.from(context.inputElements.keys())[\n focusTargetIndex\n ];\n focusInput(focusTargetElement);\n }}\n onFocus={(event) => {\n // select entire input instead of just focus\n event.target.select();\n setFocusedIndex(index);\n }}\n onInput={(event) => {\n const newInputValue = event.currentTarget.value;\n\n // Only treat as paste if it's an actual paste operation or truly long input\n // Single character duplicates (like \"11\" from typing \"1\" on \"1\") should go through onChange\n const browserInputType = (event.nativeEvent as InputEvent).inputType;\n const isPasteOperation =\n browserInputType === \"insertFromPaste\" ||\n browserInputType === \"insertFromDrop\";\n const isLongInput = newInputValue.length > 2;\n\n if (isPasteOperation || isLongInput) {\n event.preventDefault();\n dispatch({ type: \"PASTE\", value: newInputValue });\n }\n }}\n onChange={(event) => {\n const newInputValue = event.target.value;\n // check if value is valid against pattern\n if (event.target.validity.patternMismatch) return;\n dispatch({ type: \"TYPE_CHAR\", char: newInputValue, index });\n }}\n onKeyDown={mergeEventHandlers(props.onKeyDown, (event) => {\n // onKeyDown describes the intent of the user's key(s) presses\n if (event.metaKey && event.key == \"c\") return;\n\n if (\n isUndoShortcut(event) ||\n isCopyShortcut(event) ||\n isRedoShortcut(event)\n ) {\n event.preventDefault();\n return;\n }\n\n if ((event.metaKey || event.ctrlKey) && event.key === \"Backspace\") {\n dispatch({ type: \"CLEAR_ALL\" });\n return;\n }\n\n switch (event.key) {\n case \"Delete\":\n case \"Backspace\": {\n event.preventDefault();\n dispatch({ type: \"REMOVE_CHAR\", index });\n return;\n }\n\n case \"Enter\": {\n dispatch({ type: \"SUBMIT_CODE\" });\n return;\n }\n\n case \"ArrowLeft\": {\n event.preventDefault();\n dispatch({ type: \"NAVIGATE_PREVIOUS\", index });\n return;\n }\n case \"ArrowRight\": {\n event.preventDefault();\n dispatch({ type: \"NAVIGATE_NEXT\", index });\n return;\n }\n\n // Prevents up and down movements from unselecting\n case \"ArrowUp\":\n case \"ArrowDown\": {\n event.preventDefault();\n return;\n }\n\n default:\n if (event.key === currentCharacter) {\n // this is essentially focusing the next input\n dispatch({ type: \"TYPE_CHAR\", char: currentCharacter, index });\n return;\n }\n\n if (event.metaKey || event.ctrlKey) {\n return;\n }\n\n const hasValue = !!event.currentTarget.value;\n const isFullySelected =\n event.currentTarget.selectionStart === 0 &&\n event.currentTarget.selectionEnd != null &&\n event.currentTarget.selectionEnd > 0;\n\n // When input has value and is fully selected, validate the incoming key\n // to prevent selection loss from invalid keystrokes\n if (hasValue && isFullySelected) {\n // Only validate printable single characters (ignore modifiers, arrows, etc.)\n if (event.key.length === 1) {\n const isValid = validation.regex.test(event.key);\n if (!isValid) {\n event.preventDefault();\n return;\n }\n }\n }\n }\n })}\n value={currentCharacter}\n />\n );\n}\n\n// =================================================\n// CONTEXT\n// =================================================\n\nconst AuthCodeContext = createContext<AuthCodeContextValue | null>(null);\n\nfunction useAuthCodeContext() {\n const value = useContext(AuthCodeContext);\n if (!value) {\n throw new Error(\n \"\\n[awesome-auth-input] <AuthCode.Input> must be used within <AuthCode.Group>.\\n\\n\" +\n \"Make sure all <AuthCode.Input> components are children of <AuthCode.Group>:\\n\\n\" +\n \"Example:\\n\" +\n \" <AuthCode.Group>\\n\" +\n \" <AuthCode.Input index={0} />\\n\" +\n \" <AuthCode.Input index={1} />\\n\" +\n \" </AuthCode.Group>\\n\"\n );\n }\n return value;\n}\n\n// =================================================\n// HELPERS & HOOKS\n// =================================================\n\nfunction mergeEventHandlers<E extends { defaultPrevented: boolean }>(\n currentHandler?: (event: E) => void,\n nextHandler?: (event: E) => void\n) {\n return (event: E) => {\n currentHandler?.(event);\n\n if (!event.defaultPrevented) {\n nextHandler?.(event);\n }\n };\n}\n\nfunction isUndoShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (event.metaKey || event.ctrlKey) && event.key === \"z\";\n}\n\nfunction isRedoShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (\n (event.metaKey || event.ctrlKey) &&\n (event.key === \"y\" || (event.shiftKey && event.key === \"z\"))\n );\n}\n\nfunction isCopyShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (event.metaKey || event.ctrlKey) && event.key === \"c\";\n}\n\ntype MergedRef<T> = Ref<T> | undefined | null;\nfunction mergeRefs<T = any>(...refs: MergedRef<T>[]): React.RefCallback<T> {\n return function (node) {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref != null) {\n ref.current = node;\n }\n });\n };\n}\n\nconst focusInput = (element: HTMLInputElement | undefined) => {\n if (!element) return;\n if (element.disabled) return;\n // ownerDocument is the opened 'window' that owns the element\n // e.g. popups or a browser-in-browser\n if (element.ownerDocument.activeElement === element) {\n element.select();\n } else {\n element.focus();\n }\n};\n\nfunction useControllableState<T>({\n defaultValue,\n onValueChange,\n value,\n}: {\n defaultValue: T;\n onValueChange?: (value: T) => void;\n value?: T;\n}): [T, (newValue: T) => void] {\n const [internalState, setInternalState] = useState<T>(defaultValue);\n\n const isControlled = value !== undefined;\n const currentValue = isControlled ? value : internalState;\n\n const setState = useCallback(\n (newValue: T) => {\n if (!isControlled) {\n setInternalState(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange]\n );\n\n return [currentValue, setState];\n}\n\n// =================================================\n// INTERNAL TYPES & CONFIG\n// =================================================\n\ntype InputMode = \"text\" | \"numeric\" | \"none\";\n\ntype ValidationPattern =\n | ({ type: \"custom\" } & CustomValidation)\n | { type: \"alpha\" }\n | { type: \"alphanumeric\" }\n | { type: \"numeric\" };\n\ntype CustomValidation = {\n regex: RegExp;\n pattern: string;\n inputMode: InputMode;\n};\n\ninterface AuthCodeInputProps\n extends Omit<\n React.ComponentProps<\"input\">,\n | \"value\"\n | \"placeholder\"\n | \"disabled\"\n | \"autoComplete\"\n | \"defaultValue\"\n | \"type\"\n > {\n index: number;\n}\n\ninterface AuthCodeContextValue {\n dispatch: React.Dispatch<FieldUpdateAction>;\n value: string[];\n registerInputRef: (ref: HTMLInputElement | null) => void;\n name?: string;\n hiddenInputRef: Ref<HTMLInputElement | null>;\n validation:\n | (typeof defaultPatternInputMap)[DefaultInputTypes]\n | ({ type: \"custom\" } & CustomValidation);\n type: \"text\" | \"password\";\n focusedIndex: number;\n setFocusedIndex: (index: number) => void;\n disabled: boolean;\n inputCount: number;\n inputElements: Map<HTMLInputElement, true>;\n}\n\ntype DefaultInputTypes = \"alpha\" | \"alphanumeric\" | \"numeric\";\n\nconst numericRegex = /^\\d$/;\nconst alphaNumericRegex = /^[a-zA-Z\\d]$/;\nconst alphaRegex = /^[a-zA-Z]$/;\n\nconst defaultPatternInputMap = {\n alpha: {\n type: \"alpha\",\n regex: alphaRegex,\n pattern: \"[a-zA-Z]{1}\",\n inputMode: \"text\",\n },\n alphanumeric: {\n type: \"alphanumeric\",\n regex: alphaNumericRegex,\n pattern: \"[a-zA-Z0-9]{1}\",\n inputMode: \"text\",\n },\n numeric: {\n type: \"numeric\",\n regex: numericRegex,\n pattern: \"[0-9]{1}\",\n inputMode: \"numeric\",\n },\n} as const;\n\ntype FieldUpdateAction =\n | {\n type: \"TYPE_CHAR\";\n char: string;\n index: number;\n }\n | { type: \"PASTE\"; value: string }\n | { type: \"REMOVE_CHAR\"; index: number }\n | { type: \"SUBMIT_CODE\" }\n | { type: \"CLEAR_CHAR\"; index: number }\n | { type: \"NAVIGATE_PREVIOUS\"; index: number }\n | { type: \"NAVIGATE_NEXT\"; index: number }\n | { type: \"CLEAR_ALL\" };\n\n// =================================================\n// EXPORTS\n// =================================================\n\nexport {\n AuthCodeField as Group,\n AuthCodeInput as Input,\n AuthCodeHiddenInput as HiddenInput,\n};\n\nexport type {\n AuthCodeFieldProps as AuthCodeGroupProps,\n AuthCodeInputProps,\n ValidationPattern,\n CustomValidation,\n};\n","/**\n * awesome-auth-input\n * A headless, accessible React component for OTP/auth code inputs\n */\n\nimport {\n Group,\n Input,\n HiddenInput,\n} from \"./AuthCode/OneTimePassword\";\n\nexport type {\n AuthCodeGroupProps,\n AuthCodeInputProps,\n ValidationPattern,\n CustomValidation,\n} from \"./AuthCode/OneTimePassword\";\n\n/**\n * AuthCode - A compound component for OTP/auth code inputs\n *\n * @example\n * ```tsx\n * <AuthCode.Group onComplete={(code) => console.log(code)}>\n * <AuthCode.Input index={0} />\n * <AuthCode.Input index={1} />\n * <AuthCode.Input index={2} />\n * <AuthCode.Input index={3} />\n * </AuthCode.Group>\n * ```\n */\nconst AuthCode = {\n /**\n * The root component that manages state and validation for auth code inputs.\n * All `<AuthCode.Input>` components must be children of this component.\n */\n Group,\n /**\n * Individual input field for a single character of the auth code.\n * Must be used within `<AuthCode.Group>`.\n */\n Input,\n /**\n * Hidden input that contains the full auth code value for form submission.\n * Automatically rendered by Group, but can be customized if needed.\n */\n HiddenInput,\n};\n\nexport { AuthCode };\n\n// Also export individual components for tree-shaking\nexport { Group as AuthCodeGroup, Input as AuthCodeInput, HiddenInput as AuthCodeHiddenInput };\n\n"],"names":["AuthCodeField","value","AuthCodeHiddenInput","Group","Input","HiddenInput"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/AuthCode/OneTimePassword.tsx","../src/index.ts"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useRef,\n useState,\n type ReactNode,\n type Ref,\n useMemo,\n useEffect,\n forwardRef,\n} from \"react\";\nimport { flushSync } from \"react-dom\";\n\ninterface AuthCodeCustomField {\n /**\n * The child components, typically `<AuthCode.Input>` components.\n *\n * All `<AuthCode.Input>` components must be direct or nested children of `<AuthCode.Group>`.\n */\n children: ReactNode;\n /**\n * A string specifying a name for the input control. This name is submitted\n * along with the control's value when the form data is submitted.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#name\n */\n name?: string;\n /**\n * Specifies what type of validation the user agent has to provide for each\n * character input. Allows \"numeric\", \"alpha\", \"alphanumeric\", or a custom\n * validation pattern with regex.\n *\n * @defaultValue `{ type: \"numeric\" }`\n *\n * @example\n * ```tsx\n * // Numeric only (default)\n * <AuthCode.Group validation={{ type: \"numeric\" }} />\n *\n * // Alphabetic only\n * <AuthCode.Group validation={{ type: \"alpha\" }} />\n *\n * // Custom validation\n * <AuthCode.Group\n * validation={{\n * type: \"custom\",\n * regex: /^[A-Z]$/,\n * pattern: \"[A-Z]{1}\",\n * inputMode: \"text\"\n * }}\n * />\n * ```\n */\n validation?: ValidationPattern;\n /**\n * Whether or not the component should attempt to automatically submit when\n * all fields are filled. If the field is associated with an HTML `form`\n * element, the form's `requestSubmit` method will be called.\n *\n * @defaultValue `true`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit\n */\n autoSubmit?: boolean;\n /**\n * When the `autoSubmit` prop is set to `true`, this callback will be fired\n * before attempting to submit the associated form. It will be called whether\n * or not a form is located, or if submission is not allowed.\n *\n * The callback receives the complete auth code value as a string.\n *\n * @example\n * ```tsx\n * <AuthCode.Group\n * onComplete={(value) => {\n * console.log('Code entered:', value);\n * verifyCode(value);\n * }}\n * />\n * ```\n */\n onComplete?: (value: string) => void;\n /**\n * The controlled value of the field. When provided, the component operates\n * in controlled mode. This string's value, if present, must match the total\n * number of `<AuthCode.Input>` components.\n *\n * @example\n * ```tsx\n * const [code, setCode] = useState('');\n * <AuthCode.Group value={code} onValueChange={setCode} />\n * ```\n */\n value?: string;\n /**\n * A callback fired whenever the field value changes. This callback is called\n * with the complete auth code value as a string.\n *\n * Use this prop together with `value` to create a controlled component.\n */\n onValueChange?: (value: string) => void;\n /**\n * The initial value of the uncontrolled field. When provided without `value`,\n * the component operates in uncontrolled mode.\n *\n * @example\n * ```tsx\n * <AuthCode.Group defaultValue=\"123\" />\n * ```\n */\n defaultValue?: string;\n /**\n * The type of control to render. Allows \"text\" or \"password\".\n *\n * When set to \"password\", the input characters will be masked.\n *\n * @defaultValue `\"text\"`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#type\n */\n type?: \"text\" | \"password\";\n /**\n * Whether or not the input elements are disabled.\n *\n * When set to `true`, all `<AuthCode.Input>` components will be disabled\n * and users will not be able to interact with them.\n *\n * @defaultValue `false`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled\n */\n disabled?: boolean;\n}\n\ninterface AuthCodeFieldProps\n extends AuthCodeCustomField,\n Omit<React.ComponentProps<\"div\">, keyof AuthCodeCustomField> {}\n\nconst AuthCodeField = forwardRef<HTMLDivElement, AuthCodeFieldProps>(\n function AuthCodeField(\n {\n children,\n name,\n validation = { type: \"numeric\" },\n autoSubmit = true,\n onComplete,\n value: userValue,\n onValueChange: userOnValueChange,\n defaultValue,\n type = \"text\",\n disabled = false,\n ...divProps\n }: AuthCodeFieldProps,\n forwardedRef\n ) {\n const inputElements = useRef<Map<HTMLInputElement, number>>(new Map());\n const [value, setValue] = useControllableState<string[]>({\n value: userValue !== undefined ? Array.from(userValue) : undefined,\n defaultValue: defaultValue ? Array.from(defaultValue) : [],\n onValueChange: userOnValueChange\n ? (chars) => userOnValueChange(chars.join(\"\"))\n : undefined,\n });\n\n const validationConfig =\n validation.type == \"custom\"\n ? validation\n : defaultPatternInputMap[validation.type];\n\n const [focusedIndex, setFocusedIndex] = useState(0);\n const [inputCount, setInputCount] = useState(0);\n\n const registerInputRef = useCallback((ref: HTMLInputElement | null) => {\n if (ref) {\n if (!inputElements.current.has(ref)) {\n const position = inputElements.current.size;\n inputElements.current.set(ref, position);\n setInputCount(inputElements.current.size);\n }\n }\n }, []);\n\n const validateChar = useCallback(\n (char: string): boolean => {\n if (!char) return true;\n\n const regex = validationConfig.regex;\n return regex.test(char);\n },\n [validationConfig]\n );\n\n const validateString = useCallback(\n (str: string): string => {\n return Array.from(str)\n .filter((char) => validateChar(char))\n .join(\"\");\n },\n [validateChar]\n );\n\n const hiddenInputRef = useRef<HTMLInputElement | null>(null);\n\n const dispatch = (action: FieldUpdateAction) => {\n // use an ordered dictionary instead?\n const inputs = Array.from(inputElements.current.keys());\n switch (action.type) {\n case \"TYPE_CHAR\": {\n const { char, index: targetIndex } = action;\n\n if (!validateChar(char)) return;\n\n const hasExistingValue = !!value[targetIndex];\n const firstEmptyIndex = Array.from({\n length: inputs.length,\n }).findIndex((_, i) => !value[i]);\n\n const insertionIndex =\n hasExistingValue || firstEmptyIndex === -1\n ? targetIndex\n : firstEmptyIndex;\n\n const newValue = Array.from({ length: inputs.length }, (_, i) => {\n if (i === insertionIndex) return char;\n return value[i] ?? \"\";\n });\n\n flushSync(() => {\n setValue(newValue);\n });\n\n if (insertionIndex < inputs.length - 1) {\n requestAnimationFrame(() =>\n focusInput(inputs.at(insertionIndex + 1))\n );\n } else {\n requestAnimationFrame(() => {\n focusInput(inputs.at(insertionIndex));\n });\n }\n return;\n }\n\n case \"REMOVE_CHAR\": {\n const { index } = action;\n const totalInputLength = inputs.length;\n\n // Remove character and shift remaining values left\n const leftPortion = value.slice(0, index);\n const rightPortion = value.slice(index + 1);\n const compacted = leftPortion.concat(rightPortion);\n const emptySlots = Array(\n Math.max(0, totalInputLength - compacted.length)\n ).fill(\"\");\n\n flushSync(() => setValue(compacted.concat(emptySlots)));\n\n if (index != 0) {\n focusInput(inputs.at(index - 1));\n } else {\n focusInput(inputs.at(0));\n }\n return;\n }\n\n case \"CLEAR_CHAR\": {\n const { index } = action;\n const newValue = value.slice();\n newValue[index] = \"\";\n flushSync(() => setValue(newValue));\n return;\n }\n\n case \"SUBMIT_CODE\": {\n const currentValue = value.join(\"\");\n onComplete?.(currentValue);\n hiddenInputRef.current?.form?.requestSubmit();\n break;\n }\n\n case \"PASTE\": {\n const { value } = action;\n const totalInputLength = inputs.length;\n\n const validatedValue = validateString(value);\n if (validatedValue.length === 0) return;\n\n const pastedCharacters = Array.from(value).slice(0, inputs.length);\n const emptySlots = Array(\n Math.max(0, totalInputLength - value.length)\n ).fill(\"\");\n\n flushSync(() => setValue([...pastedCharacters, ...emptySlots]));\n\n if (pastedCharacters.length === totalInputLength) {\n focusInput(inputs.at(-1));\n } else {\n focusInput(inputs.at(value.length));\n }\n return;\n }\n case \"NAVIGATE_PREVIOUS\": {\n const { index } = action;\n if (index > 0) {\n focusInput(inputs.at(index - 1));\n }\n return;\n }\n\n case \"NAVIGATE_NEXT\": {\n const { index } = action;\n if (value[index] && index < inputs.length - 1) {\n focusInput(inputs.at(index + 1));\n return;\n }\n\n const firstEmpty = Array.from({ length: inputs.length }).findIndex(\n (_, i) => !value[i]\n );\n\n focusInput(inputs.at(firstEmpty));\n return;\n }\n\n case \"CLEAR_ALL\": {\n flushSync(() => setValue([]));\n focusInput(inputs.at(0));\n return;\n }\n }\n };\n\n const concatenatedValue = useMemo(() => value.join(\"\"), [value]);\n\n useEffect(() => {\n if (value.length === 0) {\n setFocusedIndex(0);\n }\n }, [value]);\n\n useEffect(() => {\n const isCodeFullyEntered =\n concatenatedValue.length === inputCount &&\n value.every((v) => v !== \"\") &&\n inputCount > 0;\n\n if (!isCodeFullyEntered) return;\n\n onComplete?.(concatenatedValue);\n\n if (autoSubmit) {\n hiddenInputRef.current?.form?.requestSubmit();\n }\n }, [concatenatedValue, onComplete, inputCount, autoSubmit]);\n\n const contextValue = useMemo(\n () => ({\n dispatch,\n value,\n registerInputRef,\n name,\n hiddenInputRef,\n validation: validationConfig,\n type,\n focusedIndex,\n setFocusedIndex,\n disabled,\n inputCount,\n inputElements: inputElements.current,\n }),\n [value, focusedIndex, disabled, name, type, inputCount]\n );\n\n return (\n <AuthCodeContext.Provider value={contextValue}>\n <div\n // Delegating all input's paste event this parent handler\n // because we want to control the paste for all inputs.\n ref={forwardedRef}\n onPaste={(event) => {\n event.preventDefault();\n const clipboardData = event.clipboardData;\n const pastedText = clipboardData.getData(\"text/plain\");\n\n dispatch({ type: \"PASTE\", value: pastedText });\n }}\n {...divProps}\n onCopy={mergeEventHandlers(divProps.onCopy, (event) => {\n event.preventDefault();\n event.clipboardData.setData(\"text/plain\", value.join(\"\"));\n })}\n >\n <AuthCodeHiddenInput />\n {children}\n </div>\n </AuthCodeContext.Provider>\n );\n }\n);\n\nAuthCodeField.displayName = \"AuthCode.Group\";\n\nconst AuthCodeHiddenInput = forwardRef<\n HTMLInputElement,\n Omit<React.ComponentProps<\"input\">, \"ref\">\n>(function AuthCodeHiddenInput(props, ref) {\n const context = useAuthCodeContext();\n const { name, value, hiddenInputRef } = context;\n const memoizedRefs = useCallback(mergeRefs(ref, hiddenInputRef), [\n ref,\n hiddenInputRef,\n ]);\n return (\n <input\n ref={memoizedRefs}\n name={name}\n value={value.join(\"\")}\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n autoSave=\"off\"\n inputMode=\"numeric\"\n autoComplete=\"one-time-code\"\n required\n {...props}\n type=\"hidden\"\n />\n );\n});\n\nAuthCodeHiddenInput.displayName = \"AuthCode.HiddenInput\";\n\n/**\n * Input component for entering a single character of the auth code.\n *\n * **Must be used within `<AuthCode.Group>`**\n *\n * @example\n *\n * <AuthCode.Group>\n * <AuthCode.Input index={0} />\n * <AuthCode.Input index={1} />\n * </AuthCode.Group>\n * */\nexport function AuthCodeInput({ index, ...props }: AuthCodeInputProps) {\n const context = useAuthCodeContext();\n const {\n dispatch,\n registerInputRef,\n validation,\n focusedIndex,\n setFocusedIndex,\n disabled,\n inputCount,\n inputElements,\n } = context;\n\n const currentCharacter = context.value[index] || \"\";\n const firstEmptyIndex = Array.from({ length: inputCount }).findIndex(\n (_, i) => !context.value[i]\n );\n const nextEmptyOrLastIndex =\n firstEmptyIndex === -1 ? inputCount - 1 : firstEmptyIndex;\n const inputRef = useRef<HTMLInputElement | null>(null);\n const mergedInputRef = useCallback(mergeRefs(registerInputRef, inputRef), [\n registerInputRef,\n ]);\n\n const inputPosition = inputRef.current\n ? (inputElements.get(inputRef.current) ?? 0) + 1\n : index + 1;\n\n return (\n <input\n type={context.type}\n tabIndex={index === focusedIndex ? 0 : -1}\n ref={mergedInputRef}\n inputMode={validation.inputMode}\n pattern={validation.pattern}\n aria-label={`One Time Password Character ${inputPosition} out of ${inputCount}`}\n disabled={disabled}\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n // Disable password managers\n data-1p-ignore // 1Password\n data-lpignore=\"true\" // LastPass\n data-bwignore=\"true\" // Bitwarden\n data-form-type=\"other\" // Generic password managers\n {...props}\n onPointerDown={(event) => {\n // A click/touch on an input can cause the input to be out of selection so\n // we must prevent that default action and keep the input selected\n // in order to have a singular value\n event.preventDefault();\n const focusTargetIndex = Math.min(index, nextEmptyOrLastIndex);\n const focusTargetElement = Array.from(context.inputElements.keys())[\n focusTargetIndex\n ];\n focusInput(focusTargetElement);\n }}\n onFocus={(event) => {\n // select entire input instead of just focus\n event.target.select();\n setFocusedIndex(index);\n }}\n onInput={(event) => {\n const newInputValue = event.currentTarget.value;\n\n // Only treat as paste if it's an actual paste operation or truly long input\n // Single character duplicates (like \"11\" from typing \"1\" on \"1\") should go through onChange\n const browserInputType = (event.nativeEvent as InputEvent).inputType;\n const isPasteOperation =\n browserInputType === \"insertFromPaste\" ||\n browserInputType === \"insertFromDrop\";\n const isLongInput = newInputValue.length > 2;\n\n if (isPasteOperation || isLongInput) {\n event.preventDefault();\n dispatch({ type: \"PASTE\", value: newInputValue });\n }\n }}\n onChange={(event) => {\n const newInputValue = event.target.value;\n // check if value is valid against pattern\n if (event.target.validity.patternMismatch) return;\n dispatch({ type: \"TYPE_CHAR\", char: newInputValue, index });\n }}\n onKeyDown={mergeEventHandlers(props.onKeyDown, (event) => {\n // onKeyDown describes the intent of the user's key(s) presses\n if (event.metaKey && event.key == \"c\") return;\n\n if (\n isUndoShortcut(event) ||\n isCopyShortcut(event) ||\n isRedoShortcut(event)\n ) {\n event.preventDefault();\n return;\n }\n\n if ((event.metaKey || event.ctrlKey) && event.key === \"Backspace\") {\n dispatch({ type: \"CLEAR_ALL\" });\n return;\n }\n\n switch (event.key) {\n case \"Delete\":\n case \"Backspace\": {\n event.preventDefault();\n dispatch({ type: \"REMOVE_CHAR\", index });\n return;\n }\n\n case \"Enter\": {\n dispatch({ type: \"SUBMIT_CODE\" });\n return;\n }\n\n case \"ArrowLeft\": {\n event.preventDefault();\n dispatch({ type: \"NAVIGATE_PREVIOUS\", index });\n return;\n }\n case \"ArrowRight\": {\n event.preventDefault();\n dispatch({ type: \"NAVIGATE_NEXT\", index });\n return;\n }\n\n // Prevents up and down movements from unselecting\n case \"ArrowUp\":\n case \"ArrowDown\": {\n event.preventDefault();\n return;\n }\n\n default:\n if (event.key === currentCharacter) {\n // this is essentially focusing the next input\n dispatch({ type: \"TYPE_CHAR\", char: currentCharacter, index });\n return;\n }\n\n if (event.metaKey || event.ctrlKey) {\n return;\n }\n\n const hasValue = !!event.currentTarget.value;\n const isFullySelected =\n event.currentTarget.selectionStart === 0 &&\n event.currentTarget.selectionEnd != null &&\n event.currentTarget.selectionEnd > 0;\n\n // When input has value and is fully selected, validate the incoming key\n // to prevent selection loss from invalid keystrokes\n if (hasValue && isFullySelected) {\n // Only validate printable single characters (ignore modifiers, arrows, etc.)\n if (event.key.length === 1) {\n const isValid = validation.regex.test(event.key);\n if (!isValid) {\n event.preventDefault();\n return;\n }\n }\n }\n }\n })}\n value={currentCharacter}\n />\n );\n}\n\nAuthCodeInput.displayName = \"AuthCode.Input\";\n\n// =================================================\n// CONTEXT\n// =================================================\n\nconst AuthCodeContext = createContext<AuthCodeContextValue | null>(null);\n\nfunction useAuthCodeContext() {\n const value = useContext(AuthCodeContext);\n if (!value) {\n throw new Error(\n \"\\n[awesome-auth-input] <AuthCode.Input> must be used within <AuthCode.Group>.\\n\\n\" +\n \"Make sure all <AuthCode.Input> components are children of <AuthCode.Group>:\\n\\n\" +\n \"Example:\\n\" +\n \" <AuthCode.Group>\\n\" +\n \" <AuthCode.Input index={0} />\\n\" +\n \" <AuthCode.Input index={1} />\\n\" +\n \" </AuthCode.Group>\\n\"\n );\n }\n return value;\n}\n\n// =================================================\n// HELPERS & HOOKS\n// =================================================\n\nfunction mergeEventHandlers<E extends { defaultPrevented: boolean }>(\n currentHandler?: (event: E) => void,\n nextHandler?: (event: E) => void\n) {\n return (event: E) => {\n currentHandler?.(event);\n\n if (!event.defaultPrevented) {\n nextHandler?.(event);\n }\n };\n}\n\nfunction isUndoShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (event.metaKey || event.ctrlKey) && event.key === \"z\";\n}\n\nfunction isRedoShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (\n (event.metaKey || event.ctrlKey) &&\n (event.key === \"y\" || (event.shiftKey && event.key === \"z\"))\n );\n}\n\nfunction isCopyShortcut(event: React.KeyboardEvent<HTMLInputElement>): boolean {\n return (event.metaKey || event.ctrlKey) && event.key === \"c\";\n}\n\ntype MergedRef<T> = Ref<T> | undefined | null;\nfunction mergeRefs<T = any>(...refs: MergedRef<T>[]): React.RefCallback<T> {\n return function (node) {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref != null) {\n ref.current = node;\n }\n });\n };\n}\n\nconst focusInput = (element: HTMLInputElement | undefined) => {\n if (!element) return;\n if (element.disabled) return;\n\n // Using ownerDocument.activeElement to check focus correctly across\n // different document contexts (iframes, popups, shadow DOM)\n if (element.ownerDocument.activeElement === element) {\n element.select();\n } else {\n element.focus();\n }\n};\n\nfunction useControllableState<T>({\n defaultValue,\n onValueChange,\n value,\n}: {\n defaultValue: T;\n onValueChange?: (value: T) => void;\n value?: T;\n}): [T, (newValue: T) => void] {\n const [internalState, setInternalState] = useState<T>(defaultValue);\n\n const isControlled = value !== undefined;\n const currentValue = isControlled ? value : internalState;\n\n const setState = useCallback(\n (newValue: T) => {\n if (!isControlled) {\n setInternalState(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange]\n );\n\n return [currentValue, setState];\n}\n\n// =================================================\n// INTERNAL TYPES & CONFIG\n// =================================================\n\ntype InputMode = \"text\" | \"numeric\" | \"none\";\n\ntype ValidationPattern =\n | ({ type: \"custom\" } & CustomValidation)\n | { type: \"alpha\" }\n | { type: \"alphanumeric\" }\n | { type: \"numeric\" };\n\ntype CustomValidation = {\n regex: RegExp;\n pattern: string;\n inputMode: InputMode;\n};\n\ninterface AuthCodeInputProps\n extends Omit<\n React.ComponentProps<\"input\">,\n | \"value\"\n | \"placeholder\"\n | \"disabled\"\n | \"autoComplete\"\n | \"defaultValue\"\n | \"type\"\n > {\n index: number;\n}\n\ninterface AuthCodeContextValue {\n dispatch: React.Dispatch<FieldUpdateAction>;\n value: string[];\n registerInputRef: (ref: HTMLInputElement | null) => void;\n name?: string;\n hiddenInputRef: Ref<HTMLInputElement | null>;\n validation:\n | (typeof defaultPatternInputMap)[DefaultInputTypes]\n | ({ type: \"custom\" } & CustomValidation);\n type: \"text\" | \"password\";\n focusedIndex: number;\n setFocusedIndex: (index: number) => void;\n disabled: boolean;\n inputCount: number;\n inputElements: Map<HTMLInputElement, number>;\n}\n\ntype DefaultInputTypes = \"alpha\" | \"alphanumeric\" | \"numeric\";\n\nconst numericRegex = /^\\d$/;\nconst alphaNumericRegex = /^[a-zA-Z\\d]$/;\nconst alphaRegex = /^[a-zA-Z]$/;\n\nconst defaultPatternInputMap = {\n alpha: {\n type: \"alpha\",\n regex: alphaRegex,\n pattern: \"[a-zA-Z]{1}\",\n inputMode: \"text\",\n },\n alphanumeric: {\n type: \"alphanumeric\",\n regex: alphaNumericRegex,\n pattern: \"[a-zA-Z0-9]{1}\",\n inputMode: \"text\",\n },\n numeric: {\n type: \"numeric\",\n regex: numericRegex,\n pattern: \"[0-9]{1}\",\n inputMode: \"numeric\",\n },\n} as const;\n\ntype FieldUpdateAction =\n | {\n type: \"TYPE_CHAR\";\n char: string;\n index: number;\n }\n | { type: \"PASTE\"; value: string }\n | { type: \"REMOVE_CHAR\"; index: number }\n | { type: \"SUBMIT_CODE\" }\n | { type: \"CLEAR_CHAR\"; index: number }\n | { type: \"NAVIGATE_PREVIOUS\"; index: number }\n | { type: \"NAVIGATE_NEXT\"; index: number }\n | { type: \"CLEAR_ALL\" };\n\n// =================================================\n// EXPORTS\n// =================================================\n\nexport {\n AuthCodeField as Group,\n AuthCodeInput as Input,\n AuthCodeHiddenInput as HiddenInput,\n};\n\nexport type {\n AuthCodeFieldProps as AuthCodeGroupProps,\n AuthCodeInputProps,\n ValidationPattern,\n CustomValidation,\n};\n","/**\n * awesome-auth-input\n * A headless, accessible React component for OTP/auth code inputs\n */\n\nimport {\n Group,\n Input,\n HiddenInput,\n} from \"./AuthCode/OneTimePassword\";\n\nexport type {\n AuthCodeGroupProps,\n AuthCodeInputProps,\n ValidationPattern,\n CustomValidation,\n} from \"./AuthCode/OneTimePassword\";\n\n/**\n * AuthCode - A compound component for OTP/auth code inputs\n *\n * @example\n * ```tsx\n * <AuthCode.Group onComplete={(code) => console.log(code)}>\n * <AuthCode.Input index={0} />\n * <AuthCode.Input index={1} />\n * <AuthCode.Input index={2} />\n * <AuthCode.Input index={3} />\n * </AuthCode.Group>\n * ```\n */\nconst AuthCode = {\n /**\n * The root component that manages state and validation for auth code inputs.\n * All `<AuthCode.Input>` components must be children of this component.\n */\n Group,\n /**\n * Individual input field for a single character of the auth code.\n * Must be used within `<AuthCode.Group>`.\n */\n Input,\n /**\n * Hidden input that contains the full auth code value for form submission.\n * Automatically rendered by Group, but can be customized if needed.\n */\n HiddenInput,\n};\n\nexport { AuthCode };\n\n// Also export individual components for tree-shaking\nexport { Group as AuthCodeGroup, Input as AuthCodeInput, HiddenInput as AuthCodeHiddenInput };\n\n"],"names":["AuthCodeField","value","AuthCodeHiddenInput","Group","Input","HiddenInput"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "awesome-auth-input",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A headless, accessible, and fully-typed React component for OTP/auth code inputs with support for numeric, alphabetic, and custom validation patterns.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|