@yamada-ui/pin-input 1.0.40-dev-20240907124054 → 1.0.40-dev-20240908075149

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.
@@ -22,7 +22,7 @@ import {
22
22
  filterUndefined,
23
23
  getValidChildren
24
24
  } from "@yamada-ui/utils";
25
- import { useCallback, useEffect, useId, useMemo, useState } from "react";
25
+ import { useCallback, useEffect, useId, useState } from "react";
26
26
  import { jsx } from "react/jsx-runtime";
27
27
  var toArray = (value) => value == null ? void 0 : value.split("");
28
28
  var validate = (value, type) => {
@@ -54,22 +54,17 @@ var PinInput = forwardRef(
54
54
  manageFocus = true,
55
55
  otp = false,
56
56
  mask,
57
- readOnly,
58
- "aria-readonly": ariaReadonly,
59
57
  onChange: onChangeProp,
60
58
  onComplete,
61
59
  items = 4,
62
60
  children,
63
61
  ...rest
64
62
  } = useFormControlProps(omitThemeProps(mergedProps));
65
- const formControlProps = useMemo(
66
- () => ({
67
- ...pickObject(rest, formControlProperties),
68
- readOnly,
69
- "aria-readonly": ariaReadonly
70
- }),
71
- [ariaReadonly, readOnly, rest]
72
- );
63
+ const {
64
+ readOnly,
65
+ "aria-readonly": _ariaReadonly,
66
+ ...formControlProps
67
+ } = pickObject(rest, formControlProperties);
73
68
  id != null ? id : id = useId();
74
69
  const descendants = useDescendants();
75
70
  const [moveFocus, setMoveFocus] = useState(true);
@@ -255,4 +250,4 @@ export {
255
250
  PinInput,
256
251
  PinInputField
257
252
  };
258
- //# sourceMappingURL=chunk-FSK2DY7Q.mjs.map
253
+ //# sourceMappingURL=chunk-E4A3WHRG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pin-input.tsx"],"sourcesContent":["import type {\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n ColorModeToken,\n CSS,\n} from \"@yamada-ui/core\"\nimport {\n ui,\n forwardRef,\n useMultiComponentStyle,\n omitThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\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 handlerAll,\n mergeRefs,\n pickObject,\n filterUndefined,\n getValidChildren,\n} from \"@yamada-ui/utils\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\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\ntype PinInputContext = {\n getInputProps: (\n props: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n },\n ) => PinInputFieldProps\n styles: Record<string, CSSUIObject>\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n strict: false,\n name: \"PinInputContext\",\n})\n\nconst { DescendantsContextProvider, useDescendants, useDescendant } =\n createDescendant<HTMLInputElement>()\n\ntype 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 * 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 * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\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 pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\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 * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n}\n\nexport type PinInputProps = Omit<HTMLUIProps<\"div\">, \"onChange\" | \"mask\"> &\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 ({ focusBorderColor, errorBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useMultiComponentStyle(\"PinInput\", {\n focusBorderColor,\n errorBorderColor,\n ...props,\n })\n let {\n id,\n className,\n type = \"number\",\n placeholder = \"○\",\n value,\n defaultValue,\n autoFocus,\n manageFocus = true,\n otp = false,\n mask,\n onChange: onChangeProp,\n onComplete,\n items = 4,\n children,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const {\n readOnly,\n \"aria-readonly\": _ariaReadonly,\n ...formControlProps\n } = pickObject(rest, formControlProperties)\n\n id ??= useId()\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 value: toArray(value),\n defaultValue: toArray(defaultValue) || [],\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: boolean = 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 !== \"\" &&\n nextValues.length === descendants.count() &&\n nextValues.every((value) => value != null && value !== \"\")\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[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1)\n } else if (value[0] === 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 }: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n }): PinInputFieldProps => ({\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n value: values[index] || \"\",\n onChange: handlerAll(props.onChange, onChange(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onBlur: handlerAll(props.onBlur, onBlur),\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\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 readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n display: \"flex\",\n alignItems: \"center\",\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={{ getInputProps, styles }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n __css={css}\n {...rest}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nexport type PinInputFieldProps = HTMLUIProps<\"input\"> & FormControlOptions\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { getInputProps, styles } = 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"],"mappings":"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","names":["values","value","nextValue","index","props"]}
package/dist/index.js CHANGED
@@ -64,22 +64,17 @@ var PinInput = (0, import_core.forwardRef)(
64
64
  manageFocus = true,
65
65
  otp = false,
66
66
  mask,
67
- readOnly,
68
- "aria-readonly": ariaReadonly,
69
67
  onChange: onChangeProp,
70
68
  onComplete,
71
69
  items = 4,
72
70
  children,
73
71
  ...rest
74
72
  } = (0, import_form_control.useFormControlProps)((0, import_core.omitThemeProps)(mergedProps));
75
- const formControlProps = (0, import_react.useMemo)(
76
- () => ({
77
- ...(0, import_utils.pickObject)(rest, import_form_control.formControlProperties),
78
- readOnly,
79
- "aria-readonly": ariaReadonly
80
- }),
81
- [ariaReadonly, readOnly, rest]
82
- );
73
+ const {
74
+ readOnly,
75
+ "aria-readonly": _ariaReadonly,
76
+ ...formControlProps
77
+ } = (0, import_utils.pickObject)(rest, import_form_control.formControlProperties);
83
78
  id != null ? id : id = (0, import_react.useId)();
84
79
  const descendants = useDescendants();
85
80
  const [moveFocus, setMoveFocus] = (0, import_react.useState)(true);
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 { PinInputProps, PinInputFieldProps } from \"./pin-input\"\n","import type {\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n ColorModeToken,\n CSS,\n} from \"@yamada-ui/core\"\nimport {\n ui,\n forwardRef,\n useMultiComponentStyle,\n omitThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\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 handlerAll,\n mergeRefs,\n pickObject,\n filterUndefined,\n getValidChildren,\n} from \"@yamada-ui/utils\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\nimport { useCallback, useEffect, useId, useMemo, 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\ntype PinInputContext = {\n getInputProps: (\n props: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n },\n ) => PinInputFieldProps\n styles: Record<string, CSSUIObject>\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n strict: false,\n name: \"PinInputContext\",\n})\n\nconst { DescendantsContextProvider, useDescendants, useDescendant } =\n createDescendant<HTMLInputElement>()\n\ntype 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 * 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 * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\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 pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\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 * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n}\n\nexport type PinInputProps = Omit<HTMLUIProps<\"div\">, \"onChange\" | \"mask\"> &\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 ({ focusBorderColor, errorBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useMultiComponentStyle(\"PinInput\", {\n focusBorderColor,\n errorBorderColor,\n ...props,\n })\n let {\n id,\n className,\n type = \"number\",\n placeholder = \"○\",\n value,\n defaultValue,\n autoFocus,\n manageFocus = true,\n otp = false,\n mask,\n readOnly,\n \"aria-readonly\": ariaReadonly,\n onChange: onChangeProp,\n onComplete,\n items = 4,\n children,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const formControlProps = useMemo(\n () => ({\n ...pickObject(rest, formControlProperties),\n readOnly,\n \"aria-readonly\": ariaReadonly,\n }),\n [ariaReadonly, readOnly, rest],\n )\n\n id ??= useId()\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 value: toArray(value),\n defaultValue: toArray(defaultValue) || [],\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: boolean = 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 !== \"\" &&\n nextValues.length === descendants.count() &&\n nextValues.every((value) => value != null && value !== \"\")\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[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1)\n } else if (value[0] === 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 }: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n }): PinInputFieldProps => ({\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n value: values[index] || \"\",\n onChange: handlerAll(props.onChange, onChange(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onBlur: handlerAll(props.onBlur, onBlur),\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\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 readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n display: \"flex\",\n alignItems: \"center\",\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={{ getInputProps, styles }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n __css={css}\n {...rest}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nexport type PinInputFieldProps = HTMLUIProps<\"input\"> & FormControlOptions\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { getInputProps, styles } = 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"],"mappings":"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","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 { PinInputProps, PinInputFieldProps } from \"./pin-input\"\n","import type {\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n ColorModeToken,\n CSS,\n} from \"@yamada-ui/core\"\nimport {\n ui,\n forwardRef,\n useMultiComponentStyle,\n omitThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\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 handlerAll,\n mergeRefs,\n pickObject,\n filterUndefined,\n getValidChildren,\n} from \"@yamada-ui/utils\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\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\ntype PinInputContext = {\n getInputProps: (\n props: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n },\n ) => PinInputFieldProps\n styles: Record<string, CSSUIObject>\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n strict: false,\n name: \"PinInputContext\",\n})\n\nconst { DescendantsContextProvider, useDescendants, useDescendant } =\n createDescendant<HTMLInputElement>()\n\ntype 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 * 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 * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\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 pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\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 * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n}\n\nexport type PinInputProps = Omit<HTMLUIProps<\"div\">, \"onChange\" | \"mask\"> &\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 ({ focusBorderColor, errorBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useMultiComponentStyle(\"PinInput\", {\n focusBorderColor,\n errorBorderColor,\n ...props,\n })\n let {\n id,\n className,\n type = \"number\",\n placeholder = \"○\",\n value,\n defaultValue,\n autoFocus,\n manageFocus = true,\n otp = false,\n mask,\n onChange: onChangeProp,\n onComplete,\n items = 4,\n children,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const {\n readOnly,\n \"aria-readonly\": _ariaReadonly,\n ...formControlProps\n } = pickObject(rest, formControlProperties)\n\n id ??= useId()\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 value: toArray(value),\n defaultValue: toArray(defaultValue) || [],\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: boolean = 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 !== \"\" &&\n nextValues.length === descendants.count() &&\n nextValues.every((value) => value != null && value !== \"\")\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[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1)\n } else if (value[0] === 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 }: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n }): PinInputFieldProps => ({\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n value: values[index] || \"\",\n onChange: handlerAll(props.onChange, onChange(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onBlur: handlerAll(props.onBlur, onBlur),\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\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 readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n display: \"flex\",\n alignItems: \"center\",\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={{ getInputProps, styles }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n __css={css}\n {...rest}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nexport type PinInputFieldProps = HTMLUIProps<\"input\"> & FormControlOptions\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { getInputProps, styles } = 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"],"mappings":"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","names":["values","value","nextValue","index","props"]}
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  PinInput,
4
4
  PinInputField
5
- } from "./chunk-FSK2DY7Q.mjs";
5
+ } from "./chunk-E4A3WHRG.mjs";
6
6
  export {
7
7
  PinInput,
8
8
  PinInputField
package/dist/pin-input.js CHANGED
@@ -62,22 +62,17 @@ var PinInput = (0, import_core.forwardRef)(
62
62
  manageFocus = true,
63
63
  otp = false,
64
64
  mask,
65
- readOnly,
66
- "aria-readonly": ariaReadonly,
67
65
  onChange: onChangeProp,
68
66
  onComplete,
69
67
  items = 4,
70
68
  children,
71
69
  ...rest
72
70
  } = (0, import_form_control.useFormControlProps)((0, import_core.omitThemeProps)(mergedProps));
73
- const formControlProps = (0, import_react.useMemo)(
74
- () => ({
75
- ...(0, import_utils.pickObject)(rest, import_form_control.formControlProperties),
76
- readOnly,
77
- "aria-readonly": ariaReadonly
78
- }),
79
- [ariaReadonly, readOnly, rest]
80
- );
71
+ const {
72
+ readOnly,
73
+ "aria-readonly": _ariaReadonly,
74
+ ...formControlProps
75
+ } = (0, import_utils.pickObject)(rest, import_form_control.formControlProperties);
81
76
  id != null ? id : id = (0, import_react.useId)();
82
77
  const descendants = useDescendants();
83
78
  const [moveFocus, setMoveFocus] = (0, import_react.useState)(true);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pin-input.tsx"],"sourcesContent":["import type {\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n ColorModeToken,\n CSS,\n} from \"@yamada-ui/core\"\nimport {\n ui,\n forwardRef,\n useMultiComponentStyle,\n omitThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\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 handlerAll,\n mergeRefs,\n pickObject,\n filterUndefined,\n getValidChildren,\n} from \"@yamada-ui/utils\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\nimport { useCallback, useEffect, useId, useMemo, 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\ntype PinInputContext = {\n getInputProps: (\n props: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n },\n ) => PinInputFieldProps\n styles: Record<string, CSSUIObject>\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n strict: false,\n name: \"PinInputContext\",\n})\n\nconst { DescendantsContextProvider, useDescendants, useDescendant } =\n createDescendant<HTMLInputElement>()\n\ntype 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 * 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 * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\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 pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\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 * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n}\n\nexport type PinInputProps = Omit<HTMLUIProps<\"div\">, \"onChange\" | \"mask\"> &\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 ({ focusBorderColor, errorBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useMultiComponentStyle(\"PinInput\", {\n focusBorderColor,\n errorBorderColor,\n ...props,\n })\n let {\n id,\n className,\n type = \"number\",\n placeholder = \"○\",\n value,\n defaultValue,\n autoFocus,\n manageFocus = true,\n otp = false,\n mask,\n readOnly,\n \"aria-readonly\": ariaReadonly,\n onChange: onChangeProp,\n onComplete,\n items = 4,\n children,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const formControlProps = useMemo(\n () => ({\n ...pickObject(rest, formControlProperties),\n readOnly,\n \"aria-readonly\": ariaReadonly,\n }),\n [ariaReadonly, readOnly, rest],\n )\n\n id ??= useId()\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 value: toArray(value),\n defaultValue: toArray(defaultValue) || [],\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: boolean = 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 !== \"\" &&\n nextValues.length === descendants.count() &&\n nextValues.every((value) => value != null && value !== \"\")\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[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1)\n } else if (value[0] === 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 }: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n }): PinInputFieldProps => ({\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n value: values[index] || \"\",\n onChange: handlerAll(props.onChange, onChange(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onBlur: handlerAll(props.onBlur, onBlur),\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\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 readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n display: \"flex\",\n alignItems: \"center\",\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={{ getInputProps, styles }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n __css={css}\n {...rest}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nexport type PinInputFieldProps = HTMLUIProps<\"input\"> & FormControlOptions\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { getInputProps, styles } = 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"],"mappings":"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","names":["values","value","nextValue","index","props"]}
1
+ {"version":3,"sources":["../src/pin-input.tsx"],"sourcesContent":["import type {\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n ColorModeToken,\n CSS,\n} from \"@yamada-ui/core\"\nimport {\n ui,\n forwardRef,\n useMultiComponentStyle,\n omitThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\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 handlerAll,\n mergeRefs,\n pickObject,\n filterUndefined,\n getValidChildren,\n} from \"@yamada-ui/utils\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\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\ntype PinInputContext = {\n getInputProps: (\n props: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n },\n ) => PinInputFieldProps\n styles: Record<string, CSSUIObject>\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n strict: false,\n name: \"PinInputContext\",\n})\n\nconst { DescendantsContextProvider, useDescendants, useDescendant } =\n createDescendant<HTMLInputElement>()\n\ntype 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 * 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 * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\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 pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\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 * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n}\n\nexport type PinInputProps = Omit<HTMLUIProps<\"div\">, \"onChange\" | \"mask\"> &\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 ({ focusBorderColor, errorBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useMultiComponentStyle(\"PinInput\", {\n focusBorderColor,\n errorBorderColor,\n ...props,\n })\n let {\n id,\n className,\n type = \"number\",\n placeholder = \"○\",\n value,\n defaultValue,\n autoFocus,\n manageFocus = true,\n otp = false,\n mask,\n onChange: onChangeProp,\n onComplete,\n items = 4,\n children,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const {\n readOnly,\n \"aria-readonly\": _ariaReadonly,\n ...formControlProps\n } = pickObject(rest, formControlProperties)\n\n id ??= useId()\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 value: toArray(value),\n defaultValue: toArray(defaultValue) || [],\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: boolean = 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 !== \"\" &&\n nextValues.length === descendants.count() &&\n nextValues.every((value) => value != null && value !== \"\")\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[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1)\n } else if (value[0] === 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 }: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n }): PinInputFieldProps => ({\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n value: values[index] || \"\",\n onChange: handlerAll(props.onChange, onChange(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onBlur: handlerAll(props.onBlur, onBlur),\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\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 readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n display: \"flex\",\n alignItems: \"center\",\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={{ getInputProps, styles }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n __css={css}\n {...rest}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nexport type PinInputFieldProps = HTMLUIProps<\"input\"> & FormControlOptions\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { getInputProps, styles } = 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"],"mappings":"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","names":["values","value","nextValue","index","props"]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  PinInput,
4
4
  PinInputField
5
- } from "./chunk-FSK2DY7Q.mjs";
5
+ } from "./chunk-E4A3WHRG.mjs";
6
6
  export {
7
7
  PinInput,
8
8
  PinInputField
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yamada-ui/pin-input",
3
- "version": "1.0.40-dev-20240907124054",
3
+ "version": "1.0.40-dev-20240908075149",
4
4
  "description": "Yamada UI pin input component",
5
5
  "keywords": [
6
6
  "yamada",
@@ -36,11 +36,11 @@
36
36
  "url": "https://github.com/yamada-ui/yamada-ui/issues"
37
37
  },
38
38
  "dependencies": {
39
- "@yamada-ui/core": "1.13.1-dev-20240907124054",
40
- "@yamada-ui/form-control": "2.1.1-dev-20240907124054",
41
- "@yamada-ui/use-controllable-state": "1.0.18",
42
- "@yamada-ui/use-descendant": "1.0.19",
43
- "@yamada-ui/utils": "1.4.0"
39
+ "@yamada-ui/core": "1.14.0-dev-20240908075149",
40
+ "@yamada-ui/form-control": "2.1.1-dev-20240908075149",
41
+ "@yamada-ui/use-controllable-state": "1.0.19-dev-20240908075149",
42
+ "@yamada-ui/use-descendant": "1.0.20-dev-20240908075149",
43
+ "@yamada-ui/utils": "1.4.1-dev-20240908075149"
44
44
  },
45
45
  "devDependencies": {
46
46
  "clean-package": "2.2.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pin-input.tsx"],"sourcesContent":["import type {\n CSSUIObject,\n HTMLUIProps,\n ThemeProps,\n ColorModeToken,\n CSS,\n} from \"@yamada-ui/core\"\nimport {\n ui,\n forwardRef,\n useMultiComponentStyle,\n omitThemeProps,\n} from \"@yamada-ui/core\"\nimport type { FormControlOptions } from \"@yamada-ui/form-control\"\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 handlerAll,\n mergeRefs,\n pickObject,\n filterUndefined,\n getValidChildren,\n} from \"@yamada-ui/utils\"\nimport type { ChangeEvent, KeyboardEvent, Ref } from \"react\"\nimport { useCallback, useEffect, useId, useMemo, 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\ntype PinInputContext = {\n getInputProps: (\n props: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n },\n ) => PinInputFieldProps\n styles: Record<string, CSSUIObject>\n}\n\nconst [PinInputProvider, usePinInputContext] = createContext<PinInputContext>({\n strict: false,\n name: \"PinInputContext\",\n})\n\nconst { DescendantsContextProvider, useDescendants, useDescendant } =\n createDescendant<HTMLInputElement>()\n\ntype 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 * 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 * The initial value of the pin input.\n */\n defaultValue?: string\n /**\n * If `true`, the pin input receives focus on mount.\n *\n * @default false\n */\n autoFocus?: boolean\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 pin input component signals to its fields that they should.\n */\n otp?: boolean\n /**\n * If `true`, the input's value will be masked just like `type=password`.\n */\n mask?: boolean\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 * The number of inputs to display.\n *\n * @default 4\n */\n items?: number\n /**\n * The border color when the input is focused.\n */\n focusBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n /**\n * The border color when the input is invalid.\n */\n errorBorderColor?: ColorModeToken<CSS.Property.BorderColor, \"colors\">\n}\n\nexport type PinInputProps = Omit<HTMLUIProps<\"div\">, \"onChange\" | \"mask\"> &\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 ({ focusBorderColor, errorBorderColor, ...props }, ref) => {\n const [styles, mergedProps] = useMultiComponentStyle(\"PinInput\", {\n focusBorderColor,\n errorBorderColor,\n ...props,\n })\n let {\n id,\n className,\n type = \"number\",\n placeholder = \"○\",\n value,\n defaultValue,\n autoFocus,\n manageFocus = true,\n otp = false,\n mask,\n readOnly,\n \"aria-readonly\": ariaReadonly,\n onChange: onChangeProp,\n onComplete,\n items = 4,\n children,\n ...rest\n } = useFormControlProps(omitThemeProps(mergedProps))\n const formControlProps = useMemo(\n () => ({\n ...pickObject(rest, formControlProperties),\n readOnly,\n \"aria-readonly\": ariaReadonly,\n }),\n [ariaReadonly, readOnly, rest],\n )\n\n id ??= useId()\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 value: toArray(value),\n defaultValue: toArray(defaultValue) || [],\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: boolean = 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 !== \"\" &&\n nextValues.length === descendants.count() &&\n nextValues.every((value) => value != null && value !== \"\")\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[0] === eventValue.charAt(0)) {\n nextValue = eventValue.charAt(1)\n } else if (value[0] === 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 }: PinInputFieldProps & {\n index: number\n ref?: Ref<HTMLInputElement>\n }): PinInputFieldProps => ({\n inputMode: type === \"number\" ? \"numeric\" : \"text\",\n type: mask ? \"password\" : type === \"number\" ? \"tel\" : \"text\",\n ...formControlProps,\n ...filterUndefined(props),\n id: `${id}-${index}`,\n value: values[index] || \"\",\n onChange: handlerAll(props.onChange, onChange(index)),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown(index)),\n onFocus: handlerAll(props.onFocus, onFocus(index)),\n onBlur: handlerAll(props.onBlur, onBlur),\n autoComplete: otp ? \"one-time-code\" : \"off\",\n placeholder:\n focusedIndex === index && !readOnly && !props.readOnly\n ? \"\"\n : placeholder,\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 readOnly,\n placeholder,\n ],\n )\n\n const css: CSSUIObject = {\n display: \"flex\",\n alignItems: \"center\",\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={{ getInputProps, styles }}>\n <ui.div\n ref={ref}\n className={cx(\"ui-pin-input\", className)}\n __css={css}\n {...rest}\n >\n {cloneChildren}\n </ui.div>\n </PinInputProvider>\n </DescendantsContextProvider>\n )\n },\n)\n\nexport type PinInputFieldProps = HTMLUIProps<\"input\"> & FormControlOptions\n\nexport const PinInputField = forwardRef<PinInputFieldProps, \"input\">(\n ({ className, ...rest }, ref) => {\n const { getInputProps, styles } = 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"],"mappings":"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","names":["values","value","nextValue","index","props"]}