@yamada-ui/pin-input 1.1.3-next-20241117114930 → 1.2.0-next-20241118203459
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-MYBEULDW.mjs → chunk-TU5BZGLV.mjs} +40 -13
- package/dist/chunk-TU5BZGLV.mjs.map +1 -0
- package/dist/index.js +39 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/pin-input.js +39 -12
- package/dist/pin-input.js.map +1 -1
- package/dist/pin-input.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-MYBEULDW.mjs.map +0 -1
@@ -94,6 +94,18 @@ var PinInput = forwardRef(
|
|
94
94
|
},
|
95
95
|
[descendants, moveFocus, manageFocus]
|
96
96
|
);
|
97
|
+
const focusInputField = useCallback(
|
98
|
+
(direction, index) => {
|
99
|
+
const input = direction === "next" ? descendants.nextValue(index, void 0, false) : descendants.prevValue(index, void 0, false);
|
100
|
+
if (!input) return;
|
101
|
+
const valueLength = input.node.value.length;
|
102
|
+
requestAnimationFrame(() => {
|
103
|
+
input.node.focus();
|
104
|
+
input.node.setSelectionRange(0, valueLength);
|
105
|
+
});
|
106
|
+
},
|
107
|
+
[descendants]
|
108
|
+
);
|
97
109
|
const setValue = useCallback(
|
98
110
|
(value2, index, isFocus = true) => {
|
99
111
|
var _a;
|
@@ -158,19 +170,34 @@ var PinInput = forwardRef(
|
|
158
170
|
]
|
159
171
|
);
|
160
172
|
const onKeyDown = useCallback(
|
161
|
-
(index) => (
|
162
|
-
if (
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
173
|
+
(index) => (ev) => {
|
174
|
+
if (!manageFocus) return;
|
175
|
+
const actions = {
|
176
|
+
ArrowLeft: () => {
|
177
|
+
ev.preventDefault();
|
178
|
+
focusInputField("prev", index);
|
179
|
+
},
|
180
|
+
ArrowRight: () => {
|
181
|
+
ev.preventDefault();
|
182
|
+
focusInputField("next", index);
|
183
|
+
},
|
184
|
+
Backspace: () => {
|
185
|
+
if (ev.target.value === "") {
|
186
|
+
const prevInput = descendants.prevValue(index, void 0, false);
|
187
|
+
if (!prevInput) return;
|
188
|
+
setValue("", index - 1, false);
|
189
|
+
prevInput.node.focus();
|
190
|
+
setMoveFocus(true);
|
191
|
+
} else {
|
192
|
+
setMoveFocus(false);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
};
|
196
|
+
const action = actions[ev.key];
|
197
|
+
if (!action) return;
|
198
|
+
action();
|
172
199
|
},
|
173
|
-
[descendants, manageFocus, setValue]
|
200
|
+
[descendants, focusInputField, manageFocus, setValue]
|
174
201
|
);
|
175
202
|
const onFocus = useCallback(
|
176
203
|
(index) => () => setFocusedIndex(index),
|
@@ -263,4 +290,4 @@ export {
|
|
263
290
|
PinInput,
|
264
291
|
PinInputField
|
265
292
|
};
|
266
|
-
//# sourceMappingURL=chunk-
|
293
|
+
//# sourceMappingURL=chunk-TU5BZGLV.mjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../src/pin-input.tsx"],"sourcesContent":["import type {\n ColorModeToken,\n CSS,\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\nimport {\n forwardRef,\n omitThemeProps,\n ui,\n useComponentMultiStyle,\n} from \"@yamada-ui/core\"\nimport {\n formControlProperties,\n useFormControlProps,\n} from \"@yamada-ui/form-control\"\nimport { useControllableState } from \"@yamada-ui/use-controllable-state\"\nimport { createDescendant } from \"@yamada-ui/use-descendant\"\nimport {\n createContext,\n cx,\n filterUndefined,\n getValidChildren,\n handlerAll,\n mergeRefs,\n splitObject,\n} from \"@yamada-ui/utils\"\nimport { useCallback, useEffect, useId, useState } from \"react\"\n\nconst toArray = (value?: string) => value?.split(\"\")\n\nconst validate = (value: string, type: PinInputProps[\"type\"]) => {\n const NUMERIC_REGEX = /^[0-9]+$/\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i\n\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX\n\n return regex.test(value)\n}\n\ninterface PinInputContext {\n styles: { [key: string]: CSSUIObject | undefined }\n getInputProps: (\n props: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps,\n ) => PinInputFieldProps\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n name: \"PinInputContext\",\n errorMessage: `PinInputContext returned is 'undefined'. Seems you forgot to wrap the components in \"<PinInput />\"`,\n})\n\nconst { DescendantsContextProvider, useDescendant, useDescendants } =\n createDescendant<HTMLInputElement>()\n\ninterface PinInputOptions {\n /**\n * The top-level id string that will be applied to the input fields.\n * The index of the input will be appended to this top-level id.\n */\n id?: string\n /**\n * The type of values the pin-input should allow.\n *\n * @default 'number'\n */\n type?: \"alphanumeric\" | \"number\"\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\n /**\n * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * If `true`, focus will move automatically to the next input once filled.\n *\n * @default true\n */\n manageFocus?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\n /**\n * If `true`, the pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * The placeholder for the pin input.\n *\n * @default '○'\n */\n placeholder?: string\n /**\n * The value of the pin input.\n */\n value?: string\n /**\n * Function called on input change.\n */\n onChange?: (value: string) => void\n /**\n * Function called when all inputs have valid values.\n */\n onComplete?: (value: string) => void\n}\n\nexport interface PinInputProps\n extends Omit<HTMLUIProps, \"defaultValue\" | \"mask\" | \"onChange\">,\n ThemeProps<\"PinInput\">,\n FormControlOptions,\n PinInputOptions {}\n\n/**\n * `PinInput` is a component used to capture pin codes or OTP (One-Time Password) inputs.\n *\n * @see Docs https://yamada-ui.com/components/forms/pin-input\n */\nexport const PinInput = forwardRef<PinInputProps, \"div\">(\n ({ errorBorderColor, focusBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useComponentMultiStyle(\"PinInput\", {\n errorBorderColor,\n focusBorderColor,\n ...props,\n })\n let {\n id,\n type = \"number\",\n className,\n autoFocus,\n children,\n defaultValue,\n items = 4,\n manageFocus = true,\n mask,\n otp = false,\n placeholder = \"○\",\n value,\n onChange: onChangeProp,\n onComplete,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const [\n {\n \"aria-readonly\": _ariaReadonly,\n disabled,\n readOnly,\n ...formControlProps\n },\n containerProps,\n ] = splitObject(rest, formControlProperties)\n const uuid = useId()\n\n id ??= uuid\n\n const descendants = useDescendants()\n\n const [moveFocus, setMoveFocus] = useState<boolean>(true)\n const [focusedIndex, setFocusedIndex] = useState<number>(-1)\n\n useEffect(() => {\n if (!autoFocus) return\n\n const firstValue = descendants.firstValue()\n\n if (!firstValue) return\n\n requestAnimationFrame(() => firstValue.node.focus())\n }, [autoFocus, descendants])\n\n const [values, setValues] = useControllableState<string[]>({\n defaultValue: toArray(defaultValue) || [],\n value: toArray(value),\n onChange: (values) => onChangeProp?.(values.join(\"\")),\n })\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus || !manageFocus) return\n\n const next = descendants.nextValue(index, undefined, false)\n\n if (!next) return\n\n requestAnimationFrame(() => next.node.focus())\n },\n [descendants, moveFocus, manageFocus],\n )\n\n const focusInputField = useCallback(\n (direction: \"next\" | \"prev\", index: number) => {\n const input =\n direction === \"next\"\n ? descendants.nextValue(index, undefined, false)\n : descendants.prevValue(index, undefined, false)\n\n if (!input) return\n\n const valueLength = input.node.value.length\n\n requestAnimationFrame(() => {\n input.node.focus()\n input.node.setSelectionRange(0, valueLength)\n })\n },\n [descendants],\n )\n\n const setValue = useCallback(\n (value: string, index: number, isFocus = true) => {\n let nextValues = [...values]\n\n nextValues[index] = value\n\n setValues(nextValues)\n\n nextValues = nextValues.filter(Boolean)\n\n const isComplete =\n value !== \"\" && nextValues.length === descendants.count()\n\n if (isComplete) {\n onComplete?.(nextValues.join(\"\"))\n descendants.value(index)?.node.blur()\n } else if (isFocus) {\n focusNext(index)\n }\n },\n [values, setValues, descendants, onComplete, focusNext],\n )\n\n const getNextValue = useCallback(\n (value: string | undefined, eventValue: string) => {\n let nextValue = eventValue\n\n if (!value?.length) return nextValue\n\n if (value.startsWith(eventValue.charAt(0))) {\n nextValue = eventValue.charAt(1)\n } else if (value.startsWith(eventValue.charAt(1))) {\n nextValue = eventValue.charAt(0)\n }\n\n return nextValue\n },\n [],\n )\n\n const onChange = useCallback(\n (index: number) =>\n ({ target }: ChangeEvent<HTMLInputElement>) => {\n const eventValue = target.value\n const currentValue = values[index]\n const nextValue = getNextValue(currentValue, eventValue)\n\n if (nextValue === \"\") {\n setValue(\"\", index)\n\n return\n }\n\n if (eventValue.length > 2) {\n if (!validate(eventValue, type)) return\n\n const nextValue = eventValue\n .split(\"\")\n .filter((_, index) => index < descendants.count())\n\n setValues(nextValue)\n\n if (nextValue.length === descendants.count()) {\n onComplete?.(nextValue.join(\"\"))\n descendants.value(index)?.node.blur()\n }\n } else {\n if (validate(nextValue, type)) setValue(nextValue, index)\n\n setMoveFocus(true)\n }\n },\n [\n descendants,\n getNextValue,\n onComplete,\n setValue,\n setValues,\n type,\n values,\n ],\n )\n\n const onKeyDown = useCallback(\n (index: number) => (ev: KeyboardEvent<HTMLInputElement>) => {\n if (!manageFocus) return\n\n const actions: { [key: string]: Function | undefined } = {\n ArrowLeft: () => {\n ev.preventDefault()\n focusInputField(\"prev\", index)\n },\n ArrowRight: () => {\n ev.preventDefault()\n focusInputField(\"next\", index)\n },\n Backspace: () => {\n if ((ev.target as HTMLInputElement).value === \"\") {\n const prevInput = descendants.prevValue(index, undefined, false)\n\n if (!prevInput) return\n\n setValue(\"\", index - 1, false)\n prevInput.node.focus()\n setMoveFocus(true)\n } else {\n setMoveFocus(false)\n }\n },\n }\n\n const action = actions[ev.key]\n\n if (!action) return\n\n action()\n },\n [descendants, focusInputField, manageFocus, setValue],\n )\n\n const onFocus = useCallback(\n (index: number) => () => setFocusedIndex(index),\n [],\n )\n\n const onBlur = useCallback(() => setFocusedIndex(-1), [])\n\n const getInputProps = useCallback(\n ({\n index,\n ...props\n }: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps): PinInputFieldProps => ({\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n disabled,\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n readOnly,\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\n value: values[index] || \"\",\n onBlur: handlerAll(props.onBlur, onBlur),\n onChange: handlerAll(props.onChange, onChange(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n }),\n [\n type,\n mask,\n formControlProps,\n id,\n values,\n onChange,\n onKeyDown,\n onFocus,\n onBlur,\n otp,\n focusedIndex,\n disabled,\n readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n alignItems: \"center\",\n display: \"flex\",\n ...styles.container,\n }\n\n let cloneChildren = getValidChildren(children)\n\n if (!cloneChildren.length)\n for (let i = 0; i < items; i++) {\n cloneChildren.push(<PinInputField key={i} />)\n }\n\n return (\n <DescendantsContextProvider value={descendants}>\n <PinInputProvider value={{ styles, getInputProps }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n role=\"group\"\n __css={css}\n {...formControlProps}\n {...containerProps}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nPinInput.displayName = \"PinInput\"\nPinInput.__ui__ = \"PinInput\"\n\nexport interface PinInputFieldProps\n extends HTMLUIProps<\"input\">,\n FormControlOptions {}\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { styles, getInputProps } = usePinInputContext()\n const { index, register } = useDescendant()\n\n rest = useFormControlProps(rest)\n\n const css: CSSUIObject = { ...styles.field }\n\n return (\n <ui.input\n className={cx(\"ui-pin-input__field\", className)}\n {...getInputProps({ ...rest, ref: mergeRefs(register, ref), index })}\n __css={css}\n />\n )\n },\n)\n\nPinInputField.displayName = \"PinInputField\"\nPinInputField.__ui__ = \"PinInputField\"\n"],"mappings":"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","names":["values","value","nextValue","index","props"]}
|
package/dist/index.js
CHANGED
@@ -104,6 +104,18 @@ var PinInput = (0, import_core.forwardRef)(
|
|
104
104
|
},
|
105
105
|
[descendants, moveFocus, manageFocus]
|
106
106
|
);
|
107
|
+
const focusInputField = (0, import_react.useCallback)(
|
108
|
+
(direction, index) => {
|
109
|
+
const input = direction === "next" ? descendants.nextValue(index, void 0, false) : descendants.prevValue(index, void 0, false);
|
110
|
+
if (!input) return;
|
111
|
+
const valueLength = input.node.value.length;
|
112
|
+
requestAnimationFrame(() => {
|
113
|
+
input.node.focus();
|
114
|
+
input.node.setSelectionRange(0, valueLength);
|
115
|
+
});
|
116
|
+
},
|
117
|
+
[descendants]
|
118
|
+
);
|
107
119
|
const setValue = (0, import_react.useCallback)(
|
108
120
|
(value2, index, isFocus = true) => {
|
109
121
|
var _a;
|
@@ -168,19 +180,34 @@ var PinInput = (0, import_core.forwardRef)(
|
|
168
180
|
]
|
169
181
|
);
|
170
182
|
const onKeyDown = (0, import_react.useCallback)(
|
171
|
-
(index) => (
|
172
|
-
if (
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
183
|
+
(index) => (ev) => {
|
184
|
+
if (!manageFocus) return;
|
185
|
+
const actions = {
|
186
|
+
ArrowLeft: () => {
|
187
|
+
ev.preventDefault();
|
188
|
+
focusInputField("prev", index);
|
189
|
+
},
|
190
|
+
ArrowRight: () => {
|
191
|
+
ev.preventDefault();
|
192
|
+
focusInputField("next", index);
|
193
|
+
},
|
194
|
+
Backspace: () => {
|
195
|
+
if (ev.target.value === "") {
|
196
|
+
const prevInput = descendants.prevValue(index, void 0, false);
|
197
|
+
if (!prevInput) return;
|
198
|
+
setValue("", index - 1, false);
|
199
|
+
prevInput.node.focus();
|
200
|
+
setMoveFocus(true);
|
201
|
+
} else {
|
202
|
+
setMoveFocus(false);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
};
|
206
|
+
const action = actions[ev.key];
|
207
|
+
if (!action) return;
|
208
|
+
action();
|
182
209
|
},
|
183
|
-
[descendants, manageFocus, setValue]
|
210
|
+
[descendants, focusInputField, manageFocus, setValue]
|
184
211
|
);
|
185
212
|
const onFocus = (0, import_react.useCallback)(
|
186
213
|
(index) => () => setFocusedIndex(index),
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/pin-input.tsx"],"sourcesContent":["export { PinInput, PinInputField } from \"./pin-input\"\nexport type { PinInputFieldProps, PinInputProps } from \"./pin-input\"\n","import type {\n ColorModeToken,\n CSS,\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\nimport {\n forwardRef,\n omitThemeProps,\n ui,\n useComponentMultiStyle,\n} from \"@yamada-ui/core\"\nimport {\n formControlProperties,\n useFormControlProps,\n} from \"@yamada-ui/form-control\"\nimport { useControllableState } from \"@yamada-ui/use-controllable-state\"\nimport { createDescendant } from \"@yamada-ui/use-descendant\"\nimport {\n createContext,\n cx,\n filterUndefined,\n getValidChildren,\n handlerAll,\n mergeRefs,\n splitObject,\n} from \"@yamada-ui/utils\"\nimport { useCallback, useEffect, useId, useState } from \"react\"\n\nconst toArray = (value?: string) => value?.split(\"\")\n\nconst validate = (value: string, type: PinInputProps[\"type\"]) => {\n const NUMERIC_REGEX = /^[0-9]+$/\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i\n\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX\n\n return regex.test(value)\n}\n\ninterface PinInputContext {\n styles: { [key: string]: CSSUIObject | undefined }\n getInputProps: (\n props: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps,\n ) => PinInputFieldProps\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n name: \"PinInputContext\",\n errorMessage: `PinInputContext returned is 'undefined'. Seems you forgot to wrap the components in \"<PinInput />\"`,\n})\n\nconst { DescendantsContextProvider, useDescendant, useDescendants } =\n createDescendant<HTMLInputElement>()\n\ninterface PinInputOptions {\n /**\n * The top-level id string that will be applied to the input fields.\n * The index of the input will be appended to this top-level id.\n */\n id?: string\n /**\n * The type of values the pin-input should allow.\n *\n * @default 'number'\n */\n type?: \"alphanumeric\" | \"number\"\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\n /**\n * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * If `true`, focus will move automatically to the next input once filled.\n *\n * @default true\n */\n manageFocus?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\n /**\n * If `true`, the pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * The placeholder for the pin input.\n *\n * @default '○'\n */\n placeholder?: string\n /**\n * The value of the pin input.\n */\n value?: string\n /**\n * Function called on input change.\n */\n onChange?: (value: string) => void\n /**\n * Function called when all inputs have valid values.\n */\n onComplete?: (value: string) => void\n}\n\nexport interface PinInputProps\n extends Omit<HTMLUIProps, \"defaultValue\" | \"mask\" | \"onChange\">,\n ThemeProps<\"PinInput\">,\n FormControlOptions,\n PinInputOptions {}\n\n/**\n * `PinInput` is a component used to capture pin codes or OTP (One-Time Password) inputs.\n *\n * @see Docs https://yamada-ui.com/components/forms/pin-input\n */\nexport const PinInput = forwardRef<PinInputProps, \"div\">(\n ({ errorBorderColor, focusBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useComponentMultiStyle(\"PinInput\", {\n errorBorderColor,\n focusBorderColor,\n ...props,\n })\n let {\n id,\n type = \"number\",\n className,\n autoFocus,\n children,\n defaultValue,\n items = 4,\n manageFocus = true,\n mask,\n otp = false,\n placeholder = \"○\",\n value,\n onChange: onChangeProp,\n onComplete,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const [\n {\n \"aria-readonly\": _ariaReadonly,\n disabled,\n readOnly,\n ...formControlProps\n },\n containerProps,\n ] = splitObject(rest, formControlProperties)\n const uuid = useId()\n\n id ??= uuid\n\n const descendants = useDescendants()\n\n const [moveFocus, setMoveFocus] = useState<boolean>(true)\n const [focusedIndex, setFocusedIndex] = useState<number>(-1)\n\n useEffect(() => {\n if (!autoFocus) return\n\n const firstValue = descendants.firstValue()\n\n if (!firstValue) return\n\n requestAnimationFrame(() => firstValue.node.focus())\n }, [autoFocus, descendants])\n\n const [values, setValues] = useControllableState<string[]>({\n defaultValue: toArray(defaultValue) || [],\n value: toArray(value),\n onChange: (values) => onChangeProp?.(values.join(\"\")),\n })\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus || !manageFocus) return\n\n const next = descendants.nextValue(index, undefined, false)\n\n if (!next) return\n\n requestAnimationFrame(() => next.node.focus())\n },\n [descendants, moveFocus, manageFocus],\n )\n\n const setValue = useCallback(\n (value: string, index: number, isFocus = true) => {\n let nextValues = [...values]\n\n nextValues[index] = value\n\n setValues(nextValues)\n\n nextValues = nextValues.filter(Boolean)\n\n const isComplete =\n value !== \"\" && nextValues.length === descendants.count()\n\n if (isComplete) {\n onComplete?.(nextValues.join(\"\"))\n descendants.value(index)?.node.blur()\n } else if (isFocus) {\n focusNext(index)\n }\n },\n [values, setValues, descendants, onComplete, focusNext],\n )\n\n const getNextValue = useCallback(\n (value: string | undefined, eventValue: string) => {\n let nextValue = eventValue\n\n if (!value?.length) return nextValue\n\n if (value.startsWith(eventValue.charAt(0))) {\n nextValue = eventValue.charAt(1)\n } else if (value.startsWith(eventValue.charAt(1))) {\n nextValue = eventValue.charAt(0)\n }\n\n return nextValue\n },\n [],\n )\n\n const onChange = useCallback(\n (index: number) =>\n ({ target }: ChangeEvent<HTMLInputElement>) => {\n const eventValue = target.value\n const currentValue = values[index]\n const nextValue = getNextValue(currentValue, eventValue)\n\n if (nextValue === \"\") {\n setValue(\"\", index)\n\n return\n }\n\n if (eventValue.length > 2) {\n if (!validate(eventValue, type)) return\n\n const nextValue = eventValue\n .split(\"\")\n .filter((_, index) => index < descendants.count())\n\n setValues(nextValue)\n\n if (nextValue.length === descendants.count()) {\n onComplete?.(nextValue.join(\"\"))\n descendants.value(index)?.node.blur()\n }\n } else {\n if (validate(nextValue, type)) setValue(nextValue, index)\n\n setMoveFocus(true)\n }\n },\n [\n descendants,\n getNextValue,\n onComplete,\n setValue,\n setValues,\n type,\n values,\n ],\n )\n\n const onKeyDown = useCallback(\n (index: number) =>\n ({ key, target }: KeyboardEvent<HTMLInputElement>) => {\n if (key !== \"Backspace\" || !manageFocus) return\n\n if ((target as HTMLInputElement).value === \"\") {\n const prevInput = descendants.prevValue(index, undefined, false)\n\n if (!prevInput) return\n\n setValue(\"\", index - 1, false)\n prevInput.node.focus()\n setMoveFocus(true)\n } else {\n setMoveFocus(false)\n }\n },\n [descendants, manageFocus, setValue],\n )\n\n const onFocus = useCallback(\n (index: number) => () => setFocusedIndex(index),\n [],\n )\n\n const onBlur = useCallback(() => setFocusedIndex(-1), [])\n\n const getInputProps = useCallback(\n ({\n index,\n ...props\n }: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps): PinInputFieldProps => ({\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n disabled,\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n readOnly,\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\n value: values[index] || \"\",\n onBlur: handlerAll(props.onBlur, onBlur),\n onChange: handlerAll(props.onChange, onChange(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n }),\n [\n type,\n mask,\n formControlProps,\n id,\n values,\n onChange,\n onKeyDown,\n onFocus,\n onBlur,\n otp,\n focusedIndex,\n disabled,\n readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n alignItems: \"center\",\n display: \"flex\",\n ...styles.container,\n }\n\n let cloneChildren = getValidChildren(children)\n\n if (!cloneChildren.length)\n for (let i = 0; i < items; i++) {\n cloneChildren.push(<PinInputField key={i} />)\n }\n\n return (\n <DescendantsContextProvider value={descendants}>\n <PinInputProvider value={{ styles, getInputProps }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n role=\"group\"\n __css={css}\n {...formControlProps}\n {...containerProps}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nPinInput.displayName = \"PinInput\"\nPinInput.__ui__ = \"PinInput\"\n\nexport interface PinInputFieldProps\n extends HTMLUIProps<\"input\">,\n FormControlOptions {}\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { styles, getInputProps } = usePinInputContext()\n const { index, register } = useDescendant()\n\n rest = useFormControlProps(rest)\n\n const css: CSSUIObject = { ...styles.field }\n\n return (\n <ui.input\n className={cx(\"ui-pin-input__field\", className)}\n {...getInputProps({ ...rest, ref: mergeRefs(register, ref), index })}\n __css={css}\n />\n )\n },\n)\n\nPinInputField.displayName = \"PinInputField\"\nPinInputField.__ui__ = \"PinInputField\"\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSA,kBAKO;AACP,0BAGO;AACP,oCAAqC;AACrC,4BAAiC;AACjC,mBAQO;AACP,mBAAwD;AA2V7B;AAzV3B,IAAM,UAAU,CAAC,UAAmB,+BAAO,MAAM;AAEjD,IAAM,WAAW,CAAC,OAAe,SAAgC;AAC/D,QAAM,gBAAgB;AACtB,QAAM,sBAAsB;AAE5B,QAAM,QAAQ,SAAS,iBAAiB,sBAAsB;AAE9D,SAAO,MAAM,KAAK,KAAK;AACzB;AAYA,IAAM,CAAC,kBAAkB,kBAAkB,QAAI,4BAA+B;AAAA,EAC5E,MAAM;AAAA,EACN,cAAc;AAChB,CAAC;AAED,IAAM,EAAE,4BAA4B,eAAe,eAAe,QAChE,wCAAmC;AAmF9B,IAAM,eAAW;AAAA,EACtB,CAAC,EAAE,kBAAkB,kBAAkB,GAAG,MAAM,GAAG,QAAQ;AACzD,UAAM,CAAC,QAAQ,WAAW,QAAI,oCAAuB,YAAY;AAAA,MAC/D;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,CAAC;AACD,QAAI;AAAA,MACF;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,cAAc;AAAA,MACd;AAAA,MACA,MAAM;AAAA,MACN,cAAc;AAAA,MACd;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA,GAAG;AAAA,IACL,QAAI,6CAAoB,4BAAe,WAAW,CAAC;AACnD,UAAM;AAAA,MACJ;AAAA,QACE,iBAAiB;AAAA,QACjB;AAAA,QACA;AAAA,QACA,GAAG;AAAA,MACL;AAAA,MACA;AAAA,IACF,QAAI,0BAAY,MAAM,yCAAqB;AAC3C,UAAM,WAAO,oBAAM;AAEnB,2BAAO;AAEP,UAAM,cAAc,eAAe;AAEnC,UAAM,CAAC,WAAW,YAAY,QAAI,uBAAkB,IAAI;AACxD,UAAM,CAAC,cAAc,eAAe,QAAI,uBAAiB,EAAE;AAE3D,gCAAU,MAAM;AACd,UAAI,CAAC,UAAW;AAEhB,YAAM,aAAa,YAAY,WAAW;AAE1C,UAAI,CAAC,WAAY;AAEjB,4BAAsB,MAAM,WAAW,KAAK,MAAM,CAAC;AAAA,IACrD,GAAG,CAAC,WAAW,WAAW,CAAC;AAE3B,UAAM,CAAC,QAAQ,SAAS,QAAI,oDAA+B;AAAA,MACzD,cAAc,QAAQ,YAAY,KAAK,CAAC;AAAA,MACxC,OAAO,QAAQ,KAAK;AAAA,MACpB,UAAU,CAACA,YAAW,6CAAeA,QAAO,KAAK,EAAE;AAAA,IACrD,CAAC;AAED,UAAM,gBAAY;AAAA,MAChB,CAAC,UAAkB;AACjB,YAAI,CAAC,aAAa,CAAC,YAAa;AAEhC,cAAM,OAAO,YAAY,UAAU,OAAO,QAAW,KAAK;AAE1D,YAAI,CAAC,KAAM;AAEX,8BAAsB,MAAM,KAAK,KAAK,MAAM,CAAC;AAAA,MAC/C;AAAA,MACA,CAAC,aAAa,WAAW,WAAW;AAAA,IACtC;AAEA,UAAM,eAAW;AAAA,MACf,CAACC,QAAe,OAAe,UAAU,SAAS;AAtNxD;AAuNQ,YAAI,aAAa,CAAC,GAAG,MAAM;AAE3B,mBAAW,KAAK,IAAIA;AAEpB,kBAAU,UAAU;AAEpB,qBAAa,WAAW,OAAO,OAAO;AAEtC,cAAM,aACJA,WAAU,MAAM,WAAW,WAAW,YAAY,MAAM;AAE1D,YAAI,YAAY;AACd,mDAAa,WAAW,KAAK,EAAE;AAC/B,4BAAY,MAAM,KAAK,MAAvB,mBAA0B,KAAK;AAAA,QACjC,WAAW,SAAS;AAClB,oBAAU,KAAK;AAAA,QACjB;AAAA,MACF;AAAA,MACA,CAAC,QAAQ,WAAW,aAAa,YAAY,SAAS;AAAA,IACxD;AAEA,UAAM,mBAAe;AAAA,MACnB,CAACA,QAA2B,eAAuB;AACjD,YAAI,YAAY;AAEhB,YAAI,EAACA,UAAA,gBAAAA,OAAO,QAAQ,QAAO;AAE3B,YAAIA,OAAM,WAAW,WAAW,OAAO,CAAC,CAAC,GAAG;AAC1C,sBAAY,WAAW,OAAO,CAAC;AAAA,QACjC,WAAWA,OAAM,WAAW,WAAW,OAAO,CAAC,CAAC,GAAG;AACjD,sBAAY,WAAW,OAAO,CAAC;AAAA,QACjC;AAEA,eAAO;AAAA,MACT;AAAA,MACA,CAAC;AAAA,IACH;AAEA,UAAM,eAAW;AAAA,MACf,CAAC,UACC,CAAC,EAAE,OAAO,MAAqC;AA/PvD;AAgQU,cAAM,aAAa,OAAO;AAC1B,cAAM,eAAe,OAAO,KAAK;AACjC,cAAM,YAAY,aAAa,cAAc,UAAU;AAEvD,YAAI,cAAc,IAAI;AACpB,mBAAS,IAAI,KAAK;AAElB;AAAA,QACF;AAEA,YAAI,WAAW,SAAS,GAAG;AACzB,cAAI,CAAC,SAAS,YAAY,IAAI,EAAG;AAEjC,gBAAMC,aAAY,WACf,MAAM,EAAE,EACR,OAAO,CAAC,GAAGC,WAAUA,SAAQ,YAAY,MAAM,CAAC;AAEnD,oBAAUD,UAAS;AAEnB,cAAIA,WAAU,WAAW,YAAY,MAAM,GAAG;AAC5C,qDAAaA,WAAU,KAAK,EAAE;AAC9B,8BAAY,MAAM,KAAK,MAAvB,mBAA0B,KAAK;AAAA,UACjC;AAAA,QACF,OAAO;AACL,cAAI,SAAS,WAAW,IAAI,EAAG,UAAS,WAAW,KAAK;AAExD,uBAAa,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,MACF;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,gBAAY;AAAA,MAChB,CAAC,UACC,CAAC,EAAE,KAAK,OAAO,MAAuC;AACpD,YAAI,QAAQ,eAAe,CAAC,YAAa;AAEzC,YAAK,OAA4B,UAAU,IAAI;AAC7C,gBAAM,YAAY,YAAY,UAAU,OAAO,QAAW,KAAK;AAE/D,cAAI,CAAC,UAAW;AAEhB,mBAAS,IAAI,QAAQ,GAAG,KAAK;AAC7B,oBAAU,KAAK,MAAM;AACrB,uBAAa,IAAI;AAAA,QACnB,OAAO;AACL,uBAAa,KAAK;AAAA,QACpB;AAAA,MACF;AAAA,MACF,CAAC,aAAa,aAAa,QAAQ;AAAA,IACrC;AAEA,UAAM,cAAU;AAAA,MACd,CAAC,UAAkB,MAAM,gBAAgB,KAAK;AAAA,MAC9C,CAAC;AAAA,IACH;AAEA,UAAM,aAAS,0BAAY,MAAM,gBAAgB,EAAE,GAAG,CAAC,CAAC;AAExD,UAAM,oBAAgB;AAAA,MACpB,CAAC;AAAA,QACC;AAAA,QACA,GAAGE;AAAA,MACL,OAGgD;AAAA,QAC9C,MAAM,OAAO,aAAa,SAAS,WAAW,QAAQ;AAAA,QACtD;AAAA,QACA,WAAW,SAAS,WAAW,YAAY;AAAA,QAC3C;AAAA,QACA,GAAG;AAAA,QACH,OAAG,8BAAgBA,MAAK;AAAA,QACxB,IAAI,GAAG,EAAE,IAAI,KAAK;AAAA,QAClB,cAAc,MAAM,kBAAkB;AAAA,QACtC,aACE,iBAAiB,SAAS,CAAC,YAAY,CAACA,OAAM,WAC1C,KACA;AAAA,QACN,OAAO,OAAO,KAAK,KAAK;AAAA,QACxB,YAAQ,yBAAWA,OAAM,QAAQ,MAAM;AAAA,QACvC,cAAU,yBAAWA,OAAM,UAAU,SAAS,KAAK,CAAC;AAAA,QACpD,aAAS,yBAAWA,OAAM,SAAS,QAAQ,KAAK,CAAC;AAAA,QACjD,eAAW,yBAAWA,OAAM,WAAW,UAAU,KAAK,CAAC;AAAA,MACzD;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAmB;AAAA,MACvB,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,GAAG,OAAO;AAAA,IACZ;AAEA,QAAI,oBAAgB,+BAAiB,QAAQ;AAE7C,QAAI,CAAC,cAAc;AACjB,eAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,sBAAc,KAAK,4CAAC,mBAAmB,CAAG,CAAE;AAAA,MAC9C;AAEF,WACE,4CAAC,8BAA2B,OAAO,aACjC,sDAAC,oBAAiB,OAAO,EAAE,QAAQ,cAAc,GAC/C;AAAA,MAAC,eAAG;AAAA,MAAH;AAAA,QACC;AAAA,QACA,eAAW,iBAAG,gBAAgB,SAAS;AAAA,QACvC,MAAK;AAAA,QACL,OAAO;AAAA,QACN,GAAG;AAAA,QACH,GAAG;AAAA,QAEH;AAAA;AAAA,IACH,GACF,GACF;AAAA,EAEJ;AACF;AAEA,SAAS,cAAc;AACvB,SAAS,SAAS;AAMX,IAAM,oBAAgB;AAAA,EAC3B,CAAC,EAAE,WAAW,GAAG,KAAK,GAAG,QAAQ;AAC/B,UAAM,EAAE,QAAQ,cAAc,IAAI,mBAAmB;AACrD,UAAM,EAAE,OAAO,SAAS,IAAI,cAAc;AAE1C,eAAO,yCAAoB,IAAI;AAE/B,UAAM,MAAmB,EAAE,GAAG,OAAO,MAAM;AAE3C,WACE;AAAA,MAAC,eAAG;AAAA,MAAH;AAAA,QACC,eAAW,iBAAG,uBAAuB,SAAS;AAAA,QAC7C,GAAG,cAAc,EAAE,GAAG,MAAM,SAAK,wBAAU,UAAU,GAAG,GAAG,MAAM,CAAC;AAAA,QACnE,OAAO;AAAA;AAAA,IACT;AAAA,EAEJ;AACF;AAEA,cAAc,cAAc;AAC5B,cAAc,SAAS;","names":["values","value","nextValue","index","props"]}
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/pin-input.tsx"],"sourcesContent":["export { PinInput, PinInputField } from \"./pin-input\"\nexport type { PinInputFieldProps, PinInputProps } from \"./pin-input\"\n","import type {\n ColorModeToken,\n CSS,\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\nimport {\n forwardRef,\n omitThemeProps,\n ui,\n useComponentMultiStyle,\n} from \"@yamada-ui/core\"\nimport {\n formControlProperties,\n useFormControlProps,\n} from \"@yamada-ui/form-control\"\nimport { useControllableState } from \"@yamada-ui/use-controllable-state\"\nimport { createDescendant } from \"@yamada-ui/use-descendant\"\nimport {\n createContext,\n cx,\n filterUndefined,\n getValidChildren,\n handlerAll,\n mergeRefs,\n splitObject,\n} from \"@yamada-ui/utils\"\nimport { useCallback, useEffect, useId, useState } from \"react\"\n\nconst toArray = (value?: string) => value?.split(\"\")\n\nconst validate = (value: string, type: PinInputProps[\"type\"]) => {\n const NUMERIC_REGEX = /^[0-9]+$/\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i\n\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX\n\n return regex.test(value)\n}\n\ninterface PinInputContext {\n styles: { [key: string]: CSSUIObject | undefined }\n getInputProps: (\n props: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps,\n ) => PinInputFieldProps\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n name: \"PinInputContext\",\n errorMessage: `PinInputContext returned is 'undefined'. Seems you forgot to wrap the components in \"<PinInput />\"`,\n})\n\nconst { DescendantsContextProvider, useDescendant, useDescendants } =\n createDescendant<HTMLInputElement>()\n\ninterface PinInputOptions {\n /**\n * The top-level id string that will be applied to the input fields.\n * The index of the input will be appended to this top-level id.\n */\n id?: string\n /**\n * The type of values the pin-input should allow.\n *\n * @default 'number'\n */\n type?: \"alphanumeric\" | \"number\"\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\n /**\n * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * If `true`, focus will move automatically to the next input once filled.\n *\n * @default true\n */\n manageFocus?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\n /**\n * If `true`, the pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * The placeholder for the pin input.\n *\n * @default '○'\n */\n placeholder?: string\n /**\n * The value of the pin input.\n */\n value?: string\n /**\n * Function called on input change.\n */\n onChange?: (value: string) => void\n /**\n * Function called when all inputs have valid values.\n */\n onComplete?: (value: string) => void\n}\n\nexport interface PinInputProps\n extends Omit<HTMLUIProps, \"defaultValue\" | \"mask\" | \"onChange\">,\n ThemeProps<\"PinInput\">,\n FormControlOptions,\n PinInputOptions {}\n\n/**\n * `PinInput` is a component used to capture pin codes or OTP (One-Time Password) inputs.\n *\n * @see Docs https://yamada-ui.com/components/forms/pin-input\n */\nexport const PinInput = forwardRef<PinInputProps, \"div\">(\n ({ errorBorderColor, focusBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useComponentMultiStyle(\"PinInput\", {\n errorBorderColor,\n focusBorderColor,\n ...props,\n })\n let {\n id,\n type = \"number\",\n className,\n autoFocus,\n children,\n defaultValue,\n items = 4,\n manageFocus = true,\n mask,\n otp = false,\n placeholder = \"○\",\n value,\n onChange: onChangeProp,\n onComplete,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const [\n {\n \"aria-readonly\": _ariaReadonly,\n disabled,\n readOnly,\n ...formControlProps\n },\n containerProps,\n ] = splitObject(rest, formControlProperties)\n const uuid = useId()\n\n id ??= uuid\n\n const descendants = useDescendants()\n\n const [moveFocus, setMoveFocus] = useState<boolean>(true)\n const [focusedIndex, setFocusedIndex] = useState<number>(-1)\n\n useEffect(() => {\n if (!autoFocus) return\n\n const firstValue = descendants.firstValue()\n\n if (!firstValue) return\n\n requestAnimationFrame(() => firstValue.node.focus())\n }, [autoFocus, descendants])\n\n const [values, setValues] = useControllableState<string[]>({\n defaultValue: toArray(defaultValue) || [],\n value: toArray(value),\n onChange: (values) => onChangeProp?.(values.join(\"\")),\n })\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus || !manageFocus) return\n\n const next = descendants.nextValue(index, undefined, false)\n\n if (!next) return\n\n requestAnimationFrame(() => next.node.focus())\n },\n [descendants, moveFocus, manageFocus],\n )\n\n const focusInputField = useCallback(\n (direction: \"next\" | \"prev\", index: number) => {\n const input =\n direction === \"next\"\n ? descendants.nextValue(index, undefined, false)\n : descendants.prevValue(index, undefined, false)\n\n if (!input) return\n\n const valueLength = input.node.value.length\n\n requestAnimationFrame(() => {\n input.node.focus()\n input.node.setSelectionRange(0, valueLength)\n })\n },\n [descendants],\n )\n\n const setValue = useCallback(\n (value: string, index: number, isFocus = true) => {\n let nextValues = [...values]\n\n nextValues[index] = value\n\n setValues(nextValues)\n\n nextValues = nextValues.filter(Boolean)\n\n const isComplete =\n value !== \"\" && nextValues.length === descendants.count()\n\n if (isComplete) {\n onComplete?.(nextValues.join(\"\"))\n descendants.value(index)?.node.blur()\n } else if (isFocus) {\n focusNext(index)\n }\n },\n [values, setValues, descendants, onComplete, focusNext],\n )\n\n const getNextValue = useCallback(\n (value: string | undefined, eventValue: string) => {\n let nextValue = eventValue\n\n if (!value?.length) return nextValue\n\n if (value.startsWith(eventValue.charAt(0))) {\n nextValue = eventValue.charAt(1)\n } else if (value.startsWith(eventValue.charAt(1))) {\n nextValue = eventValue.charAt(0)\n }\n\n return nextValue\n },\n [],\n )\n\n const onChange = useCallback(\n (index: number) =>\n ({ target }: ChangeEvent<HTMLInputElement>) => {\n const eventValue = target.value\n const currentValue = values[index]\n const nextValue = getNextValue(currentValue, eventValue)\n\n if (nextValue === \"\") {\n setValue(\"\", index)\n\n return\n }\n\n if (eventValue.length > 2) {\n if (!validate(eventValue, type)) return\n\n const nextValue = eventValue\n .split(\"\")\n .filter((_, index) => index < descendants.count())\n\n setValues(nextValue)\n\n if (nextValue.length === descendants.count()) {\n onComplete?.(nextValue.join(\"\"))\n descendants.value(index)?.node.blur()\n }\n } else {\n if (validate(nextValue, type)) setValue(nextValue, index)\n\n setMoveFocus(true)\n }\n },\n [\n descendants,\n getNextValue,\n onComplete,\n setValue,\n setValues,\n type,\n values,\n ],\n )\n\n const onKeyDown = useCallback(\n (index: number) => (ev: KeyboardEvent<HTMLInputElement>) => {\n if (!manageFocus) return\n\n const actions: { [key: string]: Function | undefined } = {\n ArrowLeft: () => {\n ev.preventDefault()\n focusInputField(\"prev\", index)\n },\n ArrowRight: () => {\n ev.preventDefault()\n focusInputField(\"next\", index)\n },\n Backspace: () => {\n if ((ev.target as HTMLInputElement).value === \"\") {\n const prevInput = descendants.prevValue(index, undefined, false)\n\n if (!prevInput) return\n\n setValue(\"\", index - 1, false)\n prevInput.node.focus()\n setMoveFocus(true)\n } else {\n setMoveFocus(false)\n }\n },\n }\n\n const action = actions[ev.key]\n\n if (!action) return\n\n action()\n },\n [descendants, focusInputField, manageFocus, setValue],\n )\n\n const onFocus = useCallback(\n (index: number) => () => setFocusedIndex(index),\n [],\n )\n\n const onBlur = useCallback(() => setFocusedIndex(-1), [])\n\n const getInputProps = useCallback(\n ({\n index,\n ...props\n }: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps): PinInputFieldProps => ({\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n disabled,\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n readOnly,\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\n value: values[index] || \"\",\n onBlur: handlerAll(props.onBlur, onBlur),\n onChange: handlerAll(props.onChange, onChange(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n }),\n [\n type,\n mask,\n formControlProps,\n id,\n values,\n onChange,\n onKeyDown,\n onFocus,\n onBlur,\n otp,\n focusedIndex,\n disabled,\n readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n alignItems: \"center\",\n display: \"flex\",\n ...styles.container,\n }\n\n let cloneChildren = getValidChildren(children)\n\n if (!cloneChildren.length)\n for (let i = 0; i < items; i++) {\n cloneChildren.push(<PinInputField key={i} />)\n }\n\n return (\n <DescendantsContextProvider value={descendants}>\n <PinInputProvider value={{ styles, getInputProps }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n role=\"group\"\n __css={css}\n {...formControlProps}\n {...containerProps}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nPinInput.displayName = \"PinInput\"\nPinInput.__ui__ = \"PinInput\"\n\nexport interface PinInputFieldProps\n extends HTMLUIProps<\"input\">,\n FormControlOptions {}\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { styles, getInputProps } = usePinInputContext()\n const { index, register } = useDescendant()\n\n rest = useFormControlProps(rest)\n\n const css: CSSUIObject = { ...styles.field }\n\n return (\n <ui.input\n className={cx(\"ui-pin-input__field\", className)}\n {...getInputProps({ ...rest, ref: mergeRefs(register, ref), index })}\n __css={css}\n />\n )\n },\n)\n\nPinInputField.displayName = \"PinInputField\"\nPinInputField.__ui__ = \"PinInputField\"\n"],"mappings":"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","names":["values","value","nextValue","index","props"]}
|
package/dist/index.mjs
CHANGED
package/dist/pin-input.js
CHANGED
@@ -102,6 +102,18 @@ var PinInput = (0, import_core.forwardRef)(
|
|
102
102
|
},
|
103
103
|
[descendants, moveFocus, manageFocus]
|
104
104
|
);
|
105
|
+
const focusInputField = (0, import_react.useCallback)(
|
106
|
+
(direction, index) => {
|
107
|
+
const input = direction === "next" ? descendants.nextValue(index, void 0, false) : descendants.prevValue(index, void 0, false);
|
108
|
+
if (!input) return;
|
109
|
+
const valueLength = input.node.value.length;
|
110
|
+
requestAnimationFrame(() => {
|
111
|
+
input.node.focus();
|
112
|
+
input.node.setSelectionRange(0, valueLength);
|
113
|
+
});
|
114
|
+
},
|
115
|
+
[descendants]
|
116
|
+
);
|
105
117
|
const setValue = (0, import_react.useCallback)(
|
106
118
|
(value2, index, isFocus = true) => {
|
107
119
|
var _a;
|
@@ -166,19 +178,34 @@ var PinInput = (0, import_core.forwardRef)(
|
|
166
178
|
]
|
167
179
|
);
|
168
180
|
const onKeyDown = (0, import_react.useCallback)(
|
169
|
-
(index) => (
|
170
|
-
if (
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
181
|
+
(index) => (ev) => {
|
182
|
+
if (!manageFocus) return;
|
183
|
+
const actions = {
|
184
|
+
ArrowLeft: () => {
|
185
|
+
ev.preventDefault();
|
186
|
+
focusInputField("prev", index);
|
187
|
+
},
|
188
|
+
ArrowRight: () => {
|
189
|
+
ev.preventDefault();
|
190
|
+
focusInputField("next", index);
|
191
|
+
},
|
192
|
+
Backspace: () => {
|
193
|
+
if (ev.target.value === "") {
|
194
|
+
const prevInput = descendants.prevValue(index, void 0, false);
|
195
|
+
if (!prevInput) return;
|
196
|
+
setValue("", index - 1, false);
|
197
|
+
prevInput.node.focus();
|
198
|
+
setMoveFocus(true);
|
199
|
+
} else {
|
200
|
+
setMoveFocus(false);
|
201
|
+
}
|
202
|
+
}
|
203
|
+
};
|
204
|
+
const action = actions[ev.key];
|
205
|
+
if (!action) return;
|
206
|
+
action();
|
180
207
|
},
|
181
|
-
[descendants, manageFocus, setValue]
|
208
|
+
[descendants, focusInputField, manageFocus, setValue]
|
182
209
|
);
|
183
210
|
const onFocus = (0, import_react.useCallback)(
|
184
211
|
(index) => () => setFocusedIndex(index),
|
package/dist/pin-input.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/pin-input.tsx"],"sourcesContent":["import type {\n ColorModeToken,\n CSS,\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\nimport {\n forwardRef,\n omitThemeProps,\n ui,\n useComponentMultiStyle,\n} from \"@yamada-ui/core\"\nimport {\n formControlProperties,\n useFormControlProps,\n} from \"@yamada-ui/form-control\"\nimport { useControllableState } from \"@yamada-ui/use-controllable-state\"\nimport { createDescendant } from \"@yamada-ui/use-descendant\"\nimport {\n createContext,\n cx,\n filterUndefined,\n getValidChildren,\n handlerAll,\n mergeRefs,\n splitObject,\n} from \"@yamada-ui/utils\"\nimport { useCallback, useEffect, useId, useState } from \"react\"\n\nconst toArray = (value?: string) => value?.split(\"\")\n\nconst validate = (value: string, type: PinInputProps[\"type\"]) => {\n const NUMERIC_REGEX = /^[0-9]+$/\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i\n\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX\n\n return regex.test(value)\n}\n\ninterface PinInputContext {\n styles: { [key: string]: CSSUIObject | undefined }\n getInputProps: (\n props: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps,\n ) => PinInputFieldProps\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n name: \"PinInputContext\",\n errorMessage: `PinInputContext returned is 'undefined'. Seems you forgot to wrap the components in \"<PinInput />\"`,\n})\n\nconst { DescendantsContextProvider, useDescendant, useDescendants } =\n createDescendant<HTMLInputElement>()\n\ninterface PinInputOptions {\n /**\n * The top-level id string that will be applied to the input fields.\n * The index of the input will be appended to this top-level id.\n */\n id?: string\n /**\n * The type of values the pin-input should allow.\n *\n * @default 'number'\n */\n type?: \"alphanumeric\" | \"number\"\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\n /**\n * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * If `true`, focus will move automatically to the next input once filled.\n *\n * @default true\n */\n manageFocus?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\n /**\n * If `true`, the pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * The placeholder for the pin input.\n *\n * @default '○'\n */\n placeholder?: string\n /**\n * The value of the pin input.\n */\n value?: string\n /**\n * Function called on input change.\n */\n onChange?: (value: string) => void\n /**\n * Function called when all inputs have valid values.\n */\n onComplete?: (value: string) => void\n}\n\nexport interface PinInputProps\n extends Omit<HTMLUIProps, \"defaultValue\" | \"mask\" | \"onChange\">,\n ThemeProps<\"PinInput\">,\n FormControlOptions,\n PinInputOptions {}\n\n/**\n * `PinInput` is a component used to capture pin codes or OTP (One-Time Password) inputs.\n *\n * @see Docs https://yamada-ui.com/components/forms/pin-input\n */\nexport const PinInput = forwardRef<PinInputProps, \"div\">(\n ({ errorBorderColor, focusBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useComponentMultiStyle(\"PinInput\", {\n errorBorderColor,\n focusBorderColor,\n ...props,\n })\n let {\n id,\n type = \"number\",\n className,\n autoFocus,\n children,\n defaultValue,\n items = 4,\n manageFocus = true,\n mask,\n otp = false,\n placeholder = \"○\",\n value,\n onChange: onChangeProp,\n onComplete,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const [\n {\n \"aria-readonly\": _ariaReadonly,\n disabled,\n readOnly,\n ...formControlProps\n },\n containerProps,\n ] = splitObject(rest, formControlProperties)\n const uuid = useId()\n\n id ??= uuid\n\n const descendants = useDescendants()\n\n const [moveFocus, setMoveFocus] = useState<boolean>(true)\n const [focusedIndex, setFocusedIndex] = useState<number>(-1)\n\n useEffect(() => {\n if (!autoFocus) return\n\n const firstValue = descendants.firstValue()\n\n if (!firstValue) return\n\n requestAnimationFrame(() => firstValue.node.focus())\n }, [autoFocus, descendants])\n\n const [values, setValues] = useControllableState<string[]>({\n defaultValue: toArray(defaultValue) || [],\n value: toArray(value),\n onChange: (values) => onChangeProp?.(values.join(\"\")),\n })\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus || !manageFocus) return\n\n const next = descendants.nextValue(index, undefined, false)\n\n if (!next) return\n\n requestAnimationFrame(() => next.node.focus())\n },\n [descendants, moveFocus, manageFocus],\n )\n\n const setValue = useCallback(\n (value: string, index: number, isFocus = true) => {\n let nextValues = [...values]\n\n nextValues[index] = value\n\n setValues(nextValues)\n\n nextValues = nextValues.filter(Boolean)\n\n const isComplete =\n value !== \"\" && nextValues.length === descendants.count()\n\n if (isComplete) {\n onComplete?.(nextValues.join(\"\"))\n descendants.value(index)?.node.blur()\n } else if (isFocus) {\n focusNext(index)\n }\n },\n [values, setValues, descendants, onComplete, focusNext],\n )\n\n const getNextValue = useCallback(\n (value: string | undefined, eventValue: string) => {\n let nextValue = eventValue\n\n if (!value?.length) return nextValue\n\n if (value.startsWith(eventValue.charAt(0))) {\n nextValue = eventValue.charAt(1)\n } else if (value.startsWith(eventValue.charAt(1))) {\n nextValue = eventValue.charAt(0)\n }\n\n return nextValue\n },\n [],\n )\n\n const onChange = useCallback(\n (index: number) =>\n ({ target }: ChangeEvent<HTMLInputElement>) => {\n const eventValue = target.value\n const currentValue = values[index]\n const nextValue = getNextValue(currentValue, eventValue)\n\n if (nextValue === \"\") {\n setValue(\"\", index)\n\n return\n }\n\n if (eventValue.length > 2) {\n if (!validate(eventValue, type)) return\n\n const nextValue = eventValue\n .split(\"\")\n .filter((_, index) => index < descendants.count())\n\n setValues(nextValue)\n\n if (nextValue.length === descendants.count()) {\n onComplete?.(nextValue.join(\"\"))\n descendants.value(index)?.node.blur()\n }\n } else {\n if (validate(nextValue, type)) setValue(nextValue, index)\n\n setMoveFocus(true)\n }\n },\n [\n descendants,\n getNextValue,\n onComplete,\n setValue,\n setValues,\n type,\n values,\n ],\n )\n\n const onKeyDown = useCallback(\n (index: number) =>\n ({ key, target }: KeyboardEvent<HTMLInputElement>) => {\n if (key !== \"Backspace\" || !manageFocus) return\n\n if ((target as HTMLInputElement).value === \"\") {\n const prevInput = descendants.prevValue(index, undefined, false)\n\n if (!prevInput) return\n\n setValue(\"\", index - 1, false)\n prevInput.node.focus()\n setMoveFocus(true)\n } else {\n setMoveFocus(false)\n }\n },\n [descendants, manageFocus, setValue],\n )\n\n const onFocus = useCallback(\n (index: number) => () => setFocusedIndex(index),\n [],\n )\n\n const onBlur = useCallback(() => setFocusedIndex(-1), [])\n\n const getInputProps = useCallback(\n ({\n index,\n ...props\n }: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps): PinInputFieldProps => ({\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n disabled,\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n readOnly,\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\n value: values[index] || \"\",\n onBlur: handlerAll(props.onBlur, onBlur),\n onChange: handlerAll(props.onChange, onChange(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n }),\n [\n type,\n mask,\n formControlProps,\n id,\n values,\n onChange,\n onKeyDown,\n onFocus,\n onBlur,\n otp,\n focusedIndex,\n disabled,\n readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n alignItems: \"center\",\n display: \"flex\",\n ...styles.container,\n }\n\n let cloneChildren = getValidChildren(children)\n\n if (!cloneChildren.length)\n for (let i = 0; i < items; i++) {\n cloneChildren.push(<PinInputField key={i} />)\n }\n\n return (\n <DescendantsContextProvider value={descendants}>\n <PinInputProvider value={{ styles, getInputProps }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n role=\"group\"\n __css={css}\n {...formControlProps}\n {...containerProps}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nPinInput.displayName = \"PinInput\"\nPinInput.__ui__ = \"PinInput\"\n\nexport interface PinInputFieldProps\n extends HTMLUIProps<\"input\">,\n FormControlOptions {}\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { styles, getInputProps } = usePinInputContext()\n const { index, register } = useDescendant()\n\n rest = useFormControlProps(rest)\n\n const css: CSSUIObject = { ...styles.field }\n\n return (\n <ui.input\n className={cx(\"ui-pin-input__field\", className)}\n {...getInputProps({ ...rest, ref: mergeRefs(register, ref), index })}\n __css={css}\n />\n )\n },\n)\n\nPinInputField.displayName = \"PinInputField\"\nPinInputField.__ui__ = \"PinInputField\"\n"],"mappings":"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","names":["values","value","nextValue","index","props"]}
|
1
|
+
{"version":3,"sources":["../src/pin-input.tsx"],"sourcesContent":["import type {\n ColorModeToken,\n CSS,\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\nimport {\n forwardRef,\n omitThemeProps,\n ui,\n useComponentMultiStyle,\n} from \"@yamada-ui/core\"\nimport {\n formControlProperties,\n useFormControlProps,\n} from \"@yamada-ui/form-control\"\nimport { useControllableState } from \"@yamada-ui/use-controllable-state\"\nimport { createDescendant } from \"@yamada-ui/use-descendant\"\nimport {\n createContext,\n cx,\n filterUndefined,\n getValidChildren,\n handlerAll,\n mergeRefs,\n splitObject,\n} from \"@yamada-ui/utils\"\nimport { useCallback, useEffect, useId, useState } from \"react\"\n\nconst toArray = (value?: string) => value?.split(\"\")\n\nconst validate = (value: string, type: PinInputProps[\"type\"]) => {\n const NUMERIC_REGEX = /^[0-9]+$/\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i\n\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX\n\n return regex.test(value)\n}\n\ninterface PinInputContext {\n styles: { [key: string]: CSSUIObject | undefined }\n getInputProps: (\n props: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps,\n ) => PinInputFieldProps\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n name: \"PinInputContext\",\n errorMessage: `PinInputContext returned is 'undefined'. Seems you forgot to wrap the components in \"<PinInput />\"`,\n})\n\nconst { DescendantsContextProvider, useDescendant, useDescendants } =\n createDescendant<HTMLInputElement>()\n\ninterface PinInputOptions {\n /**\n * The top-level id string that will be applied to the input fields.\n * The index of the input will be appended to this top-level id.\n */\n id?: string\n /**\n * The type of values the pin-input should allow.\n *\n * @default 'number'\n */\n type?: \"alphanumeric\" | \"number\"\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\n /**\n * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * If `true`, focus will move automatically to the next input once filled.\n *\n * @default true\n */\n manageFocus?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\n /**\n * If `true`, the pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * The placeholder for the pin input.\n *\n * @default '○'\n */\n placeholder?: string\n /**\n * The value of the pin input.\n */\n value?: string\n /**\n * Function called on input change.\n */\n onChange?: (value: string) => void\n /**\n * Function called when all inputs have valid values.\n */\n onComplete?: (value: string) => void\n}\n\nexport interface PinInputProps\n extends Omit<HTMLUIProps, \"defaultValue\" | \"mask\" | \"onChange\">,\n ThemeProps<\"PinInput\">,\n FormControlOptions,\n PinInputOptions {}\n\n/**\n * `PinInput` is a component used to capture pin codes or OTP (One-Time Password) inputs.\n *\n * @see Docs https://yamada-ui.com/components/forms/pin-input\n */\nexport const PinInput = forwardRef<PinInputProps, \"div\">(\n ({ errorBorderColor, focusBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useComponentMultiStyle(\"PinInput\", {\n errorBorderColor,\n focusBorderColor,\n ...props,\n })\n let {\n id,\n type = \"number\",\n className,\n autoFocus,\n children,\n defaultValue,\n items = 4,\n manageFocus = true,\n mask,\n otp = false,\n placeholder = \"○\",\n value,\n onChange: onChangeProp,\n onComplete,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const [\n {\n \"aria-readonly\": _ariaReadonly,\n disabled,\n readOnly,\n ...formControlProps\n },\n containerProps,\n ] = splitObject(rest, formControlProperties)\n const uuid = useId()\n\n id ??= uuid\n\n const descendants = useDescendants()\n\n const [moveFocus, setMoveFocus] = useState<boolean>(true)\n const [focusedIndex, setFocusedIndex] = useState<number>(-1)\n\n useEffect(() => {\n if (!autoFocus) return\n\n const firstValue = descendants.firstValue()\n\n if (!firstValue) return\n\n requestAnimationFrame(() => firstValue.node.focus())\n }, [autoFocus, descendants])\n\n const [values, setValues] = useControllableState<string[]>({\n defaultValue: toArray(defaultValue) || [],\n value: toArray(value),\n onChange: (values) => onChangeProp?.(values.join(\"\")),\n })\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus || !manageFocus) return\n\n const next = descendants.nextValue(index, undefined, false)\n\n if (!next) return\n\n requestAnimationFrame(() => next.node.focus())\n },\n [descendants, moveFocus, manageFocus],\n )\n\n const focusInputField = useCallback(\n (direction: \"next\" | \"prev\", index: number) => {\n const input =\n direction === \"next\"\n ? descendants.nextValue(index, undefined, false)\n : descendants.prevValue(index, undefined, false)\n\n if (!input) return\n\n const valueLength = input.node.value.length\n\n requestAnimationFrame(() => {\n input.node.focus()\n input.node.setSelectionRange(0, valueLength)\n })\n },\n [descendants],\n )\n\n const setValue = useCallback(\n (value: string, index: number, isFocus = true) => {\n let nextValues = [...values]\n\n nextValues[index] = value\n\n setValues(nextValues)\n\n nextValues = nextValues.filter(Boolean)\n\n const isComplete =\n value !== \"\" && nextValues.length === descendants.count()\n\n if (isComplete) {\n onComplete?.(nextValues.join(\"\"))\n descendants.value(index)?.node.blur()\n } else if (isFocus) {\n focusNext(index)\n }\n },\n [values, setValues, descendants, onComplete, focusNext],\n )\n\n const getNextValue = useCallback(\n (value: string | undefined, eventValue: string) => {\n let nextValue = eventValue\n\n if (!value?.length) return nextValue\n\n if (value.startsWith(eventValue.charAt(0))) {\n nextValue = eventValue.charAt(1)\n } else if (value.startsWith(eventValue.charAt(1))) {\n nextValue = eventValue.charAt(0)\n }\n\n return nextValue\n },\n [],\n )\n\n const onChange = useCallback(\n (index: number) =>\n ({ target }: ChangeEvent<HTMLInputElement>) => {\n const eventValue = target.value\n const currentValue = values[index]\n const nextValue = getNextValue(currentValue, eventValue)\n\n if (nextValue === \"\") {\n setValue(\"\", index)\n\n return\n }\n\n if (eventValue.length > 2) {\n if (!validate(eventValue, type)) return\n\n const nextValue = eventValue\n .split(\"\")\n .filter((_, index) => index < descendants.count())\n\n setValues(nextValue)\n\n if (nextValue.length === descendants.count()) {\n onComplete?.(nextValue.join(\"\"))\n descendants.value(index)?.node.blur()\n }\n } else {\n if (validate(nextValue, type)) setValue(nextValue, index)\n\n setMoveFocus(true)\n }\n },\n [\n descendants,\n getNextValue,\n onComplete,\n setValue,\n setValues,\n type,\n values,\n ],\n )\n\n const onKeyDown = useCallback(\n (index: number) => (ev: KeyboardEvent<HTMLInputElement>) => {\n if (!manageFocus) return\n\n const actions: { [key: string]: Function | undefined } = {\n ArrowLeft: () => {\n ev.preventDefault()\n focusInputField(\"prev\", index)\n },\n ArrowRight: () => {\n ev.preventDefault()\n focusInputField(\"next\", index)\n },\n Backspace: () => {\n if ((ev.target as HTMLInputElement).value === \"\") {\n const prevInput = descendants.prevValue(index, undefined, false)\n\n if (!prevInput) return\n\n setValue(\"\", index - 1, false)\n prevInput.node.focus()\n setMoveFocus(true)\n } else {\n setMoveFocus(false)\n }\n },\n }\n\n const action = actions[ev.key]\n\n if (!action) return\n\n action()\n },\n [descendants, focusInputField, manageFocus, setValue],\n )\n\n const onFocus = useCallback(\n (index: number) => () => setFocusedIndex(index),\n [],\n )\n\n const onBlur = useCallback(() => setFocusedIndex(-1), [])\n\n const getInputProps = useCallback(\n ({\n index,\n ...props\n }: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps): PinInputFieldProps => ({\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n disabled,\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n readOnly,\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\n value: values[index] || \"\",\n onBlur: handlerAll(props.onBlur, onBlur),\n onChange: handlerAll(props.onChange, onChange(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n }),\n [\n type,\n mask,\n formControlProps,\n id,\n values,\n onChange,\n onKeyDown,\n onFocus,\n onBlur,\n otp,\n focusedIndex,\n disabled,\n readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n alignItems: \"center\",\n display: \"flex\",\n ...styles.container,\n }\n\n let cloneChildren = getValidChildren(children)\n\n if (!cloneChildren.length)\n for (let i = 0; i < items; i++) {\n cloneChildren.push(<PinInputField key={i} />)\n }\n\n return (\n <DescendantsContextProvider value={descendants}>\n <PinInputProvider value={{ styles, getInputProps }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n role=\"group\"\n __css={css}\n {...formControlProps}\n {...containerProps}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nPinInput.displayName = \"PinInput\"\nPinInput.__ui__ = \"PinInput\"\n\nexport interface PinInputFieldProps\n extends HTMLUIProps<\"input\">,\n FormControlOptions {}\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { styles, getInputProps } = usePinInputContext()\n const { index, register } = useDescendant()\n\n rest = useFormControlProps(rest)\n\n const css: CSSUIObject = { ...styles.field }\n\n return (\n <ui.input\n className={cx(\"ui-pin-input__field\", className)}\n {...getInputProps({ ...rest, ref: mergeRefs(register, ref), index })}\n __css={css}\n />\n )\n },\n)\n\nPinInputField.displayName = \"PinInputField\"\nPinInputField.__ui__ = \"PinInputField\"\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,kBAKO;AACP,0BAGO;AACP,oCAAqC;AACrC,4BAAiC;AACjC,mBAQO;AACP,mBAAwD;AA+X7B;AA7X3B,IAAM,UAAU,CAAC,UAAmB,+BAAO,MAAM;AAEjD,IAAM,WAAW,CAAC,OAAe,SAAgC;AAC/D,QAAM,gBAAgB;AACtB,QAAM,sBAAsB;AAE5B,QAAM,QAAQ,SAAS,iBAAiB,sBAAsB;AAE9D,SAAO,MAAM,KAAK,KAAK;AACzB;AAYA,IAAM,CAAC,kBAAkB,kBAAkB,QAAI,4BAA+B;AAAA,EAC5E,MAAM;AAAA,EACN,cAAc;AAChB,CAAC;AAED,IAAM,EAAE,4BAA4B,eAAe,eAAe,QAChE,wCAAmC;AAmF9B,IAAM,eAAW;AAAA,EACtB,CAAC,EAAE,kBAAkB,kBAAkB,GAAG,MAAM,GAAG,QAAQ;AACzD,UAAM,CAAC,QAAQ,WAAW,QAAI,oCAAuB,YAAY;AAAA,MAC/D;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,CAAC;AACD,QAAI;AAAA,MACF;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,cAAc;AAAA,MACd;AAAA,MACA,MAAM;AAAA,MACN,cAAc;AAAA,MACd;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA,GAAG;AAAA,IACL,QAAI,6CAAoB,4BAAe,WAAW,CAAC;AACnD,UAAM;AAAA,MACJ;AAAA,QACE,iBAAiB;AAAA,QACjB;AAAA,QACA;AAAA,QACA,GAAG;AAAA,MACL;AAAA,MACA;AAAA,IACF,QAAI,0BAAY,MAAM,yCAAqB;AAC3C,UAAM,WAAO,oBAAM;AAEnB,2BAAO;AAEP,UAAM,cAAc,eAAe;AAEnC,UAAM,CAAC,WAAW,YAAY,QAAI,uBAAkB,IAAI;AACxD,UAAM,CAAC,cAAc,eAAe,QAAI,uBAAiB,EAAE;AAE3D,gCAAU,MAAM;AACd,UAAI,CAAC,UAAW;AAEhB,YAAM,aAAa,YAAY,WAAW;AAE1C,UAAI,CAAC,WAAY;AAEjB,4BAAsB,MAAM,WAAW,KAAK,MAAM,CAAC;AAAA,IACrD,GAAG,CAAC,WAAW,WAAW,CAAC;AAE3B,UAAM,CAAC,QAAQ,SAAS,QAAI,oDAA+B;AAAA,MACzD,cAAc,QAAQ,YAAY,KAAK,CAAC;AAAA,MACxC,OAAO,QAAQ,KAAK;AAAA,MACpB,UAAU,CAACA,YAAW,6CAAeA,QAAO,KAAK,EAAE;AAAA,IACrD,CAAC;AAED,UAAM,gBAAY;AAAA,MAChB,CAAC,UAAkB;AACjB,YAAI,CAAC,aAAa,CAAC,YAAa;AAEhC,cAAM,OAAO,YAAY,UAAU,OAAO,QAAW,KAAK;AAE1D,YAAI,CAAC,KAAM;AAEX,8BAAsB,MAAM,KAAK,KAAK,MAAM,CAAC;AAAA,MAC/C;AAAA,MACA,CAAC,aAAa,WAAW,WAAW;AAAA,IACtC;AAEA,UAAM,sBAAkB;AAAA,MACtB,CAAC,WAA4B,UAAkB;AAC7C,cAAM,QACJ,cAAc,SACV,YAAY,UAAU,OAAO,QAAW,KAAK,IAC7C,YAAY,UAAU,OAAO,QAAW,KAAK;AAEnD,YAAI,CAAC,MAAO;AAEZ,cAAM,cAAc,MAAM,KAAK,MAAM;AAErC,8BAAsB,MAAM;AAC1B,gBAAM,KAAK,MAAM;AACjB,gBAAM,KAAK,kBAAkB,GAAG,WAAW;AAAA,QAC7C,CAAC;AAAA,MACH;AAAA,MACA,CAAC,WAAW;AAAA,IACd;AAEA,UAAM,eAAW;AAAA,MACf,CAACC,QAAe,OAAe,UAAU,SAAS;AAzOxD;AA0OQ,YAAI,aAAa,CAAC,GAAG,MAAM;AAE3B,mBAAW,KAAK,IAAIA;AAEpB,kBAAU,UAAU;AAEpB,qBAAa,WAAW,OAAO,OAAO;AAEtC,cAAM,aACJA,WAAU,MAAM,WAAW,WAAW,YAAY,MAAM;AAE1D,YAAI,YAAY;AACd,mDAAa,WAAW,KAAK,EAAE;AAC/B,4BAAY,MAAM,KAAK,MAAvB,mBAA0B,KAAK;AAAA,QACjC,WAAW,SAAS;AAClB,oBAAU,KAAK;AAAA,QACjB;AAAA,MACF;AAAA,MACA,CAAC,QAAQ,WAAW,aAAa,YAAY,SAAS;AAAA,IACxD;AAEA,UAAM,mBAAe;AAAA,MACnB,CAACA,QAA2B,eAAuB;AACjD,YAAI,YAAY;AAEhB,YAAI,EAACA,UAAA,gBAAAA,OAAO,QAAQ,QAAO;AAE3B,YAAIA,OAAM,WAAW,WAAW,OAAO,CAAC,CAAC,GAAG;AAC1C,sBAAY,WAAW,OAAO,CAAC;AAAA,QACjC,WAAWA,OAAM,WAAW,WAAW,OAAO,CAAC,CAAC,GAAG;AACjD,sBAAY,WAAW,OAAO,CAAC;AAAA,QACjC;AAEA,eAAO;AAAA,MACT;AAAA,MACA,CAAC;AAAA,IACH;AAEA,UAAM,eAAW;AAAA,MACf,CAAC,UACC,CAAC,EAAE,OAAO,MAAqC;AAlRvD;AAmRU,cAAM,aAAa,OAAO;AAC1B,cAAM,eAAe,OAAO,KAAK;AACjC,cAAM,YAAY,aAAa,cAAc,UAAU;AAEvD,YAAI,cAAc,IAAI;AACpB,mBAAS,IAAI,KAAK;AAElB;AAAA,QACF;AAEA,YAAI,WAAW,SAAS,GAAG;AACzB,cAAI,CAAC,SAAS,YAAY,IAAI,EAAG;AAEjC,gBAAMC,aAAY,WACf,MAAM,EAAE,EACR,OAAO,CAAC,GAAGC,WAAUA,SAAQ,YAAY,MAAM,CAAC;AAEnD,oBAAUD,UAAS;AAEnB,cAAIA,WAAU,WAAW,YAAY,MAAM,GAAG;AAC5C,qDAAaA,WAAU,KAAK,EAAE;AAC9B,8BAAY,MAAM,KAAK,MAAvB,mBAA0B,KAAK;AAAA,UACjC;AAAA,QACF,OAAO;AACL,cAAI,SAAS,WAAW,IAAI,EAAG,UAAS,WAAW,KAAK;AAExD,uBAAa,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,MACF;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,gBAAY;AAAA,MAChB,CAAC,UAAkB,CAAC,OAAwC;AAC1D,YAAI,CAAC,YAAa;AAElB,cAAM,UAAmD;AAAA,UACvD,WAAW,MAAM;AACf,eAAG,eAAe;AAClB,4BAAgB,QAAQ,KAAK;AAAA,UAC/B;AAAA,UACA,YAAY,MAAM;AAChB,eAAG,eAAe;AAClB,4BAAgB,QAAQ,KAAK;AAAA,UAC/B;AAAA,UACA,WAAW,MAAM;AACf,gBAAK,GAAG,OAA4B,UAAU,IAAI;AAChD,oBAAM,YAAY,YAAY,UAAU,OAAO,QAAW,KAAK;AAE/D,kBAAI,CAAC,UAAW;AAEhB,uBAAS,IAAI,QAAQ,GAAG,KAAK;AAC7B,wBAAU,KAAK,MAAM;AACrB,2BAAa,IAAI;AAAA,YACnB,OAAO;AACL,2BAAa,KAAK;AAAA,YACpB;AAAA,UACF;AAAA,QACF;AAEA,cAAM,SAAS,QAAQ,GAAG,GAAG;AAE7B,YAAI,CAAC,OAAQ;AAEb,eAAO;AAAA,MACT;AAAA,MACA,CAAC,aAAa,iBAAiB,aAAa,QAAQ;AAAA,IACtD;AAEA,UAAM,cAAU;AAAA,MACd,CAAC,UAAkB,MAAM,gBAAgB,KAAK;AAAA,MAC9C,CAAC;AAAA,IACH;AAEA,UAAM,aAAS,0BAAY,MAAM,gBAAgB,EAAE,GAAG,CAAC,CAAC;AAExD,UAAM,oBAAgB;AAAA,MACpB,CAAC;AAAA,QACC;AAAA,QACA,GAAGE;AAAA,MACL,OAGgD;AAAA,QAC9C,MAAM,OAAO,aAAa,SAAS,WAAW,QAAQ;AAAA,QACtD;AAAA,QACA,WAAW,SAAS,WAAW,YAAY;AAAA,QAC3C;AAAA,QACA,GAAG;AAAA,QACH,OAAG,8BAAgBA,MAAK;AAAA,QACxB,IAAI,GAAG,EAAE,IAAI,KAAK;AAAA,QAClB,cAAc,MAAM,kBAAkB;AAAA,QACtC,aACE,iBAAiB,SAAS,CAAC,YAAY,CAACA,OAAM,WAC1C,KACA;AAAA,QACN,OAAO,OAAO,KAAK,KAAK;AAAA,QACxB,YAAQ,yBAAWA,OAAM,QAAQ,MAAM;AAAA,QACvC,cAAU,yBAAWA,OAAM,UAAU,SAAS,KAAK,CAAC;AAAA,QACpD,aAAS,yBAAWA,OAAM,SAAS,QAAQ,KAAK,CAAC;AAAA,QACjD,eAAW,yBAAWA,OAAM,WAAW,UAAU,KAAK,CAAC;AAAA,MACzD;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAmB;AAAA,MACvB,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,GAAG,OAAO;AAAA,IACZ;AAEA,QAAI,oBAAgB,+BAAiB,QAAQ;AAE7C,QAAI,CAAC,cAAc;AACjB,eAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,sBAAc,KAAK,4CAAC,mBAAmB,CAAG,CAAE;AAAA,MAC9C;AAEF,WACE,4CAAC,8BAA2B,OAAO,aACjC,sDAAC,oBAAiB,OAAO,EAAE,QAAQ,cAAc,GAC/C;AAAA,MAAC,eAAG;AAAA,MAAH;AAAA,QACC;AAAA,QACA,eAAW,iBAAG,gBAAgB,SAAS;AAAA,QACvC,MAAK;AAAA,QACL,OAAO;AAAA,QACN,GAAG;AAAA,QACH,GAAG;AAAA,QAEH;AAAA;AAAA,IACH,GACF,GACF;AAAA,EAEJ;AACF;AAEA,SAAS,cAAc;AACvB,SAAS,SAAS;AAMX,IAAM,oBAAgB;AAAA,EAC3B,CAAC,EAAE,WAAW,GAAG,KAAK,GAAG,QAAQ;AAC/B,UAAM,EAAE,QAAQ,cAAc,IAAI,mBAAmB;AACrD,UAAM,EAAE,OAAO,SAAS,IAAI,cAAc;AAE1C,eAAO,yCAAoB,IAAI;AAE/B,UAAM,MAAmB,EAAE,GAAG,OAAO,MAAM;AAE3C,WACE;AAAA,MAAC,eAAG;AAAA,MAAH;AAAA,QACC,eAAW,iBAAG,uBAAuB,SAAS;AAAA,QAC7C,GAAG,cAAc,EAAE,GAAG,MAAM,SAAK,wBAAU,UAAU,GAAG,GAAG,MAAM,CAAC;AAAA,QACnE,OAAO;AAAA;AAAA,IACT;AAAA,EAEJ;AACF;AAEA,cAAc,cAAc;AAC5B,cAAc,SAAS;","names":["values","value","nextValue","index","props"]}
|
package/dist/pin-input.mjs
CHANGED
package/package.json
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"sources":["../src/pin-input.tsx"],"sourcesContent":["import type {\n ColorModeToken,\n CSS,\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\nimport {\n forwardRef,\n omitThemeProps,\n ui,\n useComponentMultiStyle,\n} from \"@yamada-ui/core\"\nimport {\n formControlProperties,\n useFormControlProps,\n} from \"@yamada-ui/form-control\"\nimport { useControllableState } from \"@yamada-ui/use-controllable-state\"\nimport { createDescendant } from \"@yamada-ui/use-descendant\"\nimport {\n createContext,\n cx,\n filterUndefined,\n getValidChildren,\n handlerAll,\n mergeRefs,\n splitObject,\n} from \"@yamada-ui/utils\"\nimport { useCallback, useEffect, useId, useState } from \"react\"\n\nconst toArray = (value?: string) => value?.split(\"\")\n\nconst validate = (value: string, type: PinInputProps[\"type\"]) => {\n const NUMERIC_REGEX = /^[0-9]+$/\n const ALPHA_NUMERIC_REGEX = /^[a-zA-Z0-9]+$/i\n\n const regex = type === \"alphanumeric\" ? ALPHA_NUMERIC_REGEX : NUMERIC_REGEX\n\n return regex.test(value)\n}\n\ninterface PinInputContext {\n styles: { [key: string]: CSSUIObject | undefined }\n getInputProps: (\n props: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps,\n ) => PinInputFieldProps\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n name: \"PinInputContext\",\n errorMessage: `PinInputContext returned is 'undefined'. Seems you forgot to wrap the components in \"<PinInput />\"`,\n})\n\nconst { DescendantsContextProvider, useDescendant, useDescendants } =\n createDescendant<HTMLInputElement>()\n\ninterface PinInputOptions {\n /**\n * The top-level id string that will be applied to the input fields.\n * The index of the input will be appended to this top-level id.\n */\n id?: string\n /**\n * The type of values the pin-input should allow.\n *\n * @default 'number'\n */\n type?: \"alphanumeric\" | \"number\"\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\n /**\n * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * If `true`, focus will move automatically to the next input once filled.\n *\n * @default true\n */\n manageFocus?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\n /**\n * If `true`, the pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * The placeholder for the pin input.\n *\n * @default '○'\n */\n placeholder?: string\n /**\n * The value of the pin input.\n */\n value?: string\n /**\n * Function called on input change.\n */\n onChange?: (value: string) => void\n /**\n * Function called when all inputs have valid values.\n */\n onComplete?: (value: string) => void\n}\n\nexport interface PinInputProps\n extends Omit<HTMLUIProps, \"defaultValue\" | \"mask\" | \"onChange\">,\n ThemeProps<\"PinInput\">,\n FormControlOptions,\n PinInputOptions {}\n\n/**\n * `PinInput` is a component used to capture pin codes or OTP (One-Time Password) inputs.\n *\n * @see Docs https://yamada-ui.com/components/forms/pin-input\n */\nexport const PinInput = forwardRef<PinInputProps, \"div\">(\n ({ errorBorderColor, focusBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useComponentMultiStyle(\"PinInput\", {\n errorBorderColor,\n focusBorderColor,\n ...props,\n })\n let {\n id,\n type = \"number\",\n className,\n autoFocus,\n children,\n defaultValue,\n items = 4,\n manageFocus = true,\n mask,\n otp = false,\n placeholder = \"○\",\n value,\n onChange: onChangeProp,\n onComplete,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const [\n {\n \"aria-readonly\": _ariaReadonly,\n disabled,\n readOnly,\n ...formControlProps\n },\n containerProps,\n ] = splitObject(rest, formControlProperties)\n const uuid = useId()\n\n id ??= uuid\n\n const descendants = useDescendants()\n\n const [moveFocus, setMoveFocus] = useState<boolean>(true)\n const [focusedIndex, setFocusedIndex] = useState<number>(-1)\n\n useEffect(() => {\n if (!autoFocus) return\n\n const firstValue = descendants.firstValue()\n\n if (!firstValue) return\n\n requestAnimationFrame(() => firstValue.node.focus())\n }, [autoFocus, descendants])\n\n const [values, setValues] = useControllableState<string[]>({\n defaultValue: toArray(defaultValue) || [],\n value: toArray(value),\n onChange: (values) => onChangeProp?.(values.join(\"\")),\n })\n\n const focusNext = useCallback(\n (index: number) => {\n if (!moveFocus || !manageFocus) return\n\n const next = descendants.nextValue(index, undefined, false)\n\n if (!next) return\n\n requestAnimationFrame(() => next.node.focus())\n },\n [descendants, moveFocus, manageFocus],\n )\n\n const setValue = useCallback(\n (value: string, index: number, isFocus = true) => {\n let nextValues = [...values]\n\n nextValues[index] = value\n\n setValues(nextValues)\n\n nextValues = nextValues.filter(Boolean)\n\n const isComplete =\n value !== \"\" && nextValues.length === descendants.count()\n\n if (isComplete) {\n onComplete?.(nextValues.join(\"\"))\n descendants.value(index)?.node.blur()\n } else if (isFocus) {\n focusNext(index)\n }\n },\n [values, setValues, descendants, onComplete, focusNext],\n )\n\n const getNextValue = useCallback(\n (value: string | undefined, eventValue: string) => {\n let nextValue = eventValue\n\n if (!value?.length) return nextValue\n\n if (value.startsWith(eventValue.charAt(0))) {\n nextValue = eventValue.charAt(1)\n } else if (value.startsWith(eventValue.charAt(1))) {\n nextValue = eventValue.charAt(0)\n }\n\n return nextValue\n },\n [],\n )\n\n const onChange = useCallback(\n (index: number) =>\n ({ target }: ChangeEvent<HTMLInputElement>) => {\n const eventValue = target.value\n const currentValue = values[index]\n const nextValue = getNextValue(currentValue, eventValue)\n\n if (nextValue === \"\") {\n setValue(\"\", index)\n\n return\n }\n\n if (eventValue.length > 2) {\n if (!validate(eventValue, type)) return\n\n const nextValue = eventValue\n .split(\"\")\n .filter((_, index) => index < descendants.count())\n\n setValues(nextValue)\n\n if (nextValue.length === descendants.count()) {\n onComplete?.(nextValue.join(\"\"))\n descendants.value(index)?.node.blur()\n }\n } else {\n if (validate(nextValue, type)) setValue(nextValue, index)\n\n setMoveFocus(true)\n }\n },\n [\n descendants,\n getNextValue,\n onComplete,\n setValue,\n setValues,\n type,\n values,\n ],\n )\n\n const onKeyDown = useCallback(\n (index: number) =>\n ({ key, target }: KeyboardEvent<HTMLInputElement>) => {\n if (key !== \"Backspace\" || !manageFocus) return\n\n if ((target as HTMLInputElement).value === \"\") {\n const prevInput = descendants.prevValue(index, undefined, false)\n\n if (!prevInput) return\n\n setValue(\"\", index - 1, false)\n prevInput.node.focus()\n setMoveFocus(true)\n } else {\n setMoveFocus(false)\n }\n },\n [descendants, manageFocus, setValue],\n )\n\n const onFocus = useCallback(\n (index: number) => () => setFocusedIndex(index),\n [],\n )\n\n const onBlur = useCallback(() => setFocusedIndex(-1), [])\n\n const getInputProps = useCallback(\n ({\n index,\n ...props\n }: {\n index: number\n ref?: Ref<HTMLInputElement>\n } & PinInputFieldProps): PinInputFieldProps => ({\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n disabled,\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n readOnly,\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\n value: values[index] || \"\",\n onBlur: handlerAll(props.onBlur, onBlur),\n onChange: handlerAll(props.onChange, onChange(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n }),\n [\n type,\n mask,\n formControlProps,\n id,\n values,\n onChange,\n onKeyDown,\n onFocus,\n onBlur,\n otp,\n focusedIndex,\n disabled,\n readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n alignItems: \"center\",\n display: \"flex\",\n ...styles.container,\n }\n\n let cloneChildren = getValidChildren(children)\n\n if (!cloneChildren.length)\n for (let i = 0; i < items; i++) {\n cloneChildren.push(<PinInputField key={i} />)\n }\n\n return (\n <DescendantsContextProvider value={descendants}>\n <PinInputProvider value={{ styles, getInputProps }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n role=\"group\"\n __css={css}\n {...formControlProps}\n {...containerProps}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nPinInput.displayName = \"PinInput\"\nPinInput.__ui__ = \"PinInput\"\n\nexport interface PinInputFieldProps\n extends HTMLUIProps<\"input\">,\n FormControlOptions {}\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { styles, getInputProps } = usePinInputContext()\n const { index, register } = useDescendant()\n\n rest = useFormControlProps(rest)\n\n const css: CSSUIObject = { ...styles.field }\n\n return (\n <ui.input\n className={cx(\"ui-pin-input__field\", className)}\n {...getInputProps({ ...rest, ref: mergeRefs(register, ref), index })}\n __css={css}\n />\n )\n },\n)\n\nPinInputField.displayName = \"PinInputField\"\nPinInputField.__ui__ = \"PinInputField\"\n"],"mappings":"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","names":["values","value","nextValue","index","props"]}
|