{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "use-digits-input",
  "type": "registry:lib",
  "title": "هوک فیلدهای عددی فارسی",
  "description": "هوک فیلدهای عددی فارسی",
  "dependencies": [
    "@kashi-ui/persian@^1.7.0"
  ],
  "registryDependencies": [
    "https://kashi.sepantapouya.com/r/utils.json"
  ],
  "files": [
    {
      "path": "registry/kashi/useDigitsInput.ts",
      "type": "registry:lib",
      "target": "components/kashi/useDigitsInput.ts",
      "content": "\"use client\";\n\nimport { useRef, useState, type ChangeEvent } from \"react\";\nimport { onlyDigits } from \"@kashi-ui/persian\";\nimport { useIsomorphicLayoutEffect } from \"./utils\";\n\nexport interface DigitsInputOptions {\n  value?: string;\n  defaultValue?: string;\n  /** حداکثر تعداد رقم */\n  maxDigits: number;\n  /** متن نمایشی از روی ارقام خام (با ارقام لاتین) */\n  format: (raw: string) => string;\n  /** پیش‌پردازش ارقام، مثلاً تبدیل +98 به 0 */\n  normalize?: (digits: string) => string;\n  /** خط ارقام نمایشی */\n  digits: \"fa\" | \"latin\";\n}\n\nconst FA = \"۰۱۲۳۴۵۶۷۸۹\";\nconst fa = (s: string) => s.replace(/\\d/g, (d) => FA[Number(d)]);\n\n/** موقعیت مکان‌نما پس از n رقم در متن قالب‌بندی‌شده */\nfunction caretAfter(text: string, n: number): number {\n  if (n === 0) return text.search(/[0-9۰-۹]/) === -1 ? text.length : text.search(/[0-9۰-۹]/);\n  let seen = 0;\n  for (let i = 0; i < text.length; i++) if (/[0-9۰-۹]/.test(text[i]) && ++seen === n) return i + 1;\n  return text.length;\n}\n\n/**\n * منطق مشترک فیلدهای عددی قالب‌بندی‌شده (کارت، شبا، موبایل، مبلغ):\n * ارقام فارسی و لاتین را می‌پذیرد، بقیه را حذف می‌کند و مکان‌نما را پس از قالب‌بندی سر جایش نگه می‌دارد.\n */\nexport function useDigitsInput({ value, defaultValue = \"\", maxDigits, format, normalize = (d) => d, digits }: DigitsInputOptions) {\n  const clean = (input: string) => normalize(onlyDigits(input)).slice(0, maxDigits);\n  const [inner, setInner] = useState(() => clean(defaultValue));\n  const raw = value !== undefined ? clean(value) : inner;\n  const formatted = format(raw);\n  const shown = digits === \"fa\" ? fa(formatted) : formatted;\n  const inputRef = useRef<HTMLInputElement>(null);\n  const caret = useRef<number | null>(null);\n\n  useIsomorphicLayoutEffect(() => {\n    if (caret.current !== null && inputRef.current === document.activeElement) {\n      const pos = caretAfter(shown, caret.current);\n      inputRef.current?.setSelectionRange(pos, pos);\n      caret.current = null;\n    }\n  });\n\n  /** ارقام خام جدید را برمی‌گرداند؛ حالت داخلی را هم به‌روز می‌کند */\n  const handleChange = (e: ChangeEvent<HTMLInputElement>): string => {\n    const el = e.target;\n    const before = el.value.slice(0, el.selectionStart ?? el.value.length);\n    const next = clean(el.value);\n    caret.current = Math.min(onlyDigits(before).length, next.length);\n    if (value === undefined) setInner(next);\n    return next;\n  };\n\n  return { raw, shown, inputRef, handleChange };\n}\n"
    }
  ]
}