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 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
- - **Paste** - Paste code from clipboard (auto-fills all fields)
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
- - Respects `prefers-reduced-motion`
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,4HAyPlB,CAAC;AAEF,QAAA,MAAM,mBAAmB,sNAyBvB,CAAC;AAEH;;;;;;;;;;;MAWM;AACN,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,kBAAkB,2CAkKpE;AAgHD,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"}
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.set(ref, true);
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(() => setValue(newValue));
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(() => focusInput(inputs.at(insertionIndex)));
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
- }, [value, inputCount, onComplete, autoSubmit]);
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 mergedInputRef = react.useCallback(mergeRefs(registerInputRef), [
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 ${index + 1} out of ${inputCount}`,
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);
@@ -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, useEffect, useMemo, createContext, useContext } from "react";
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.set(ref, true);
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(() => setValue(newValue));
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(() => focusInput(inputs.at(insertionIndex)));
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
- }, [value, inputCount, onComplete, autoSubmit]);
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 mergedInputRef = useCallback(mergeRefs(registerInputRef), [
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 ${index + 1} out of ${inputCount}`,
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.1.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",