پرتوپرتو

ورودی عدد بومی (NumberInputLocale)

ورودی عددی بومی‌ساز — ارقام فارسی، عربی یا لاتین را می‌پذیرد، نمایش را با locale انتخابی هماهنگ می‌کند و همیشه یک عدد جاوااسکریپتی تمیز به فرم تحویل می‌دهد.

معرفی

NumberInputLocale یک ورودی عددی است که ارقام تایپ‌شده با هر صفحه‌کلیدی (فارسی، عربی یا لاتین) را می‌پذیرد، نمایش را مطابق locale انتخابی (پیش‌فرض فارسی) بازآرایی می‌کند و از طریق onValueChange همیشه یک number استاندارد جاوااسکریپت — یا null برای فیلد خالی — به فرم تحویل می‌دهد.

چه زمانی استفاده کنیم:

  • هر فیلد عددی در فرم‌های فارسی/عربی که کاربر ممکن است با صفحه‌کلید بومی تایپ کند (بودجه کمپین تخفیف فصلی، سقف هزینه، تعداد پست)
  • وقتی نمایش باید ارقام بومی و جداکننده هزارگان داشته باشد اما مقدار ذخیره‌شده باید عدد خام باشد
  • فیلدهای دارای واحد (تومان، درصد، نفر) که واحد باید داخل خود ورودی دیده شود

چه زمانی استفاده نکنیم:

  • برای متن آزاد یا رشته‌هایی که فقط شبیه عدد هستند (شماره تلفن، کد پستی) — از Input استفاده کنید؛ صفر ابتدای این مقادیر نباید حذف شود
  • برای انتخاب بصری یک عدد در بازه بسته و کوچک — از Slider استفاده کنید
  • برای کد تأیید چندرقمی — از InputOTP استفاده کنید
تومان

مقدار عددی خروجی: 2500000

استفاده

import { NumberInputLocale } from '@partodata/ui'
const [budget, setBudget] = React.useState<number | null>(null)

<NumberInputLocale
  value={budget}
  onValueChange={setBudget}
  unit="تومان"
  min={0}
  allowNegative={false}
  placeholder="مبلغ را وارد کنید"
/>

رفتار نمایش دو مرحله‌ای است: تا وقتی فیلد فوکوس دارد، همان متن تایپ‌شده کاربر (بدون جداکننده هزارگان) نمایش داده می‌شود تا مکان‌نما هنگام ویرایش وسط عدد نپرد؛ با خروج فوکوس (blur) مقدار به بازه min و max محدود شده و با ارقام locale، جداکننده هزارگان و تعداد اعشار مشخص‌شده بازنویسی می‌شود. onValueChange در حین تایپ نیز به‌صورت زنده صدا زده می‌شود تا اعتبارسنجی فرم عقب نماند.

حالت‌ها و انواع

زبان ارقام (locale)

سه مقدار fa، ar و en پشتیبانی می‌شود. ورودی کاربر با هر مجموعه رقمی پذیرفته و پیش از پارس به لاتین نرمال می‌شود؛ خروجیِ نمایشی همیشه با ارقام locale انتخابی است.

بازدید
نفر
٪
<NumberInputLocale locale="fa" defaultValue={1250000} unit="بازدید" />
<NumberInputLocale locale="ar" defaultValue={1250000} unit="نفر" />
<NumberInputLocale locale="en" defaultValue={4.8} decimals={1} unit="٪" />

واحد (unit)

با prop unit یک پسوند واحد در سمت انتهایی ورودی نمایش داده می‌شود. این پسوند صرفاً بصری است و روی مقدار اثری ندارد.

<NumberInputLocale unit="تومان" min={0} allowNegative={false} />

محدوده مجاز (min و max)

مقادیر min و max شامل خود کران هستند و فقط هنگام blur اعمال می‌شوند — وسط تایپ مقدار کاربر دستکاری نمی‌شود. اگر مقدار پس از blur تغییر کند، onValueChange یک بار دیگر با مقدار محدودشده فراخوانی می‌شود.

<NumberInputLocale min={0} max={100} decimals={1} unit="٪" />

اعشار و جداکننده هزارگان

پیش‌فرض ورودی عدد صحیح است (decimals={0}). با مقدار بزرگ‌تر، نقطه اعشار پذیرفته و هنگام blur به همان تعداد رقم گرد و صفرپر می‌شود. جداکننده هزارگان به‌صورت پیش‌فرض فعال است و با thousandSeparator={false} خاموش می‌شود.

<NumberInputLocale decimals={2} thousandSeparator={false} />

اعداد منفی

به‌صورت پیش‌فرض علامت منفی پذیرفته می‌شود. برای فیلدهایی مانند مبلغ یا تعداد، آن را خاموش کنید:

<NumberInputLocale allowNegative={false} min={0} />

کنترل‌شده و کنترل‌نشده

مانند سایر ورودی‌ها هر دو حالت پشتیبانی می‌شود: با value و onValueChange کنترل‌شده، و با defaultValue کنترل‌نشده. مقدار null در هر دو حالت به معنای فیلد خالی است.

// کنترل‌نشده — فقط مقدار اولیه
<NumberInputLocale defaultValue={5000} onValueChange={(next) => console.log(next)} />

راهنمای استفاده

بکنید

  • مقدار را همیشه به‌صورت number یا null نگه دارید و از onValueChange بخوانید — پارس و نرمال‌سازی ارقام کار خود کامپوننت است.
  • برای مبالغ و شمارش‌ها min={0} و allowNegative={false} را با هم تنظیم کنید تا هم تایپ منفی مسدود شود و هم مقدار نهایی محدود بماند.
  • واحد فیلد را با prop unit نشان دهید و همان واحد را در Label یا aria-label هم تکرار کنید تا برای صفحه‌خوان‌ها نیز روشن باشد.
  • برای فرم‌های چندزبانه، locale را از تنظیمات زبان کاربر بگیرید تا نمایش ارقام با بقیه رابط هماهنگ بماند.

نکنید

  • از این کامپوننت برای شماره تلفن، کد ملی یا کد پستی استفاده نکنید — این مقادیر رشته هستند و صفر ابتدایشان نباید حذف شود؛ از Input استفاده کنید.
  • مقدار نمایشی داخل فیلد را خودتان دوباره فرمت نکنید (مثلاً با افزودن جداکننده در onValueChange) — چرخه فرمت‌مجدد، مکان‌نمای کاربر را می‌پراند.
  • انتظار نداشته باشید min و max وسط تایپ اعمال شوند — محدودسازی عمداً به blur موکول شده تا ویرایش نیمه‌کاره خراب نشود؛ اعتبارسنجی لحظه‌ای فرم را جداگانه انجام دهید.
  • واحد را به‌صورت متن داخل placeholder یا بعد از فیلد تکرار نکنید وقتی unit تنظیم شده — دو بار نمایش واحد گیج‌کننده است.

Props

کامپوننت علاوه بر موارد زیر، همه ویژگی‌های بومی input (مانند id، placeholder، disabled، readOnly و صفات aria-*) را می‌پذیرد؛ فقط type، value، defaultValue، onChange و size بومی کنار گذاشته شده‌اند. ref نیز مستقیماً به المنت input می‌رسد.

Prop

Type

دسترسی‌پذیری

  • از یک input بومی با type="text" و inputMode="decimal" استفاده می‌کند — موبایل‌ها صفحه‌کلید عددی نشان می‌دهند بدون رفتارهای ناخواسته type="number" مرورگر.
  • جهت فیلد همیشه dir="ltr" با تراز انتهایی است تا عدد در فرم‌های RTL هم به شکل طبیعی خوانده شود.
  • کاربر با هر صفحه‌کلیدی (فارسی، عربی، لاتین) می‌تواند تایپ کند؛ نرمال‌سازی ارقام خودکار است و خطای «رقم نامعتبر» رخ نمی‌دهد.
  • پسوند unit یک عنصر تزئینی است و به‌صورت برنامه‌ای به فیلد متصل نیست — واحد را در Label متصل با htmlFor یا در aria-label هم ذکر کنید.
  • همه صفات بومی از جمله aria-invalid عبور داده می‌شوند و استایل حالت خطا از Input پایه به ارث می‌رسد.
  • این کامپوننت spinbutton نیست: دکمه افزایش/کاهش و کلیدهای جهت‌نما برای تغییر مقدار ندارد؛ تعامل همان تایپ آزاد است.

تعامل با کیبورد

  • Tab: انتقال فوکوس به فیلد؛ با ورود فوکوس، جداکننده‌های هزارگان حذف می‌شوند تا ویرایش ساده‌تر شود - خروج فوکوس: محدودسازی به بازه مجاز و بازنویسی نمایش با ارقام locale - در حالت disabled فیلد از ترتیب فوکوس خارج می‌شود

کامپوننت‌های مرتبط

  • Input — اگر مقدار در واقع رشته است (شماره تلفن، کد پستی، متن آزاد) و نباید به عدد تبدیل شود
  • InputGroup — اگر لازم است ورودی با دکمه یا افزودنی‌های دیگر در یک گروه ترکیب شود
  • Slider — اگر انتخاب عدد در یک بازه بسته و کوچک است و بازخورد بصری مهم‌تر از تایپ دقیق است
  • InputOTP — اگر ورودی یک کد عددی چندرقمی با خانه‌های جدا است، نه یک مقدار عددی