persian-number-input 4.2.0 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.fa.md +458 -0
- package/README.md +342 -270
- package/dist/components/PersianNumberInput.test.d.ts.map +1 -1
- package/dist/components/PersianNumberInput.test.js.map +1 -1
- package/dist/setupTests.d.ts +2 -0
- package/dist/setupTests.d.ts.map +1 -0
- package/dist/setupTests.js +4 -0
- package/dist/setupTests.js.map +1 -0
- package/package.json +2 -1
package/README.fa.md
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
# ورودی اعداد فارسی و عربی
|
|
2
|
+
|
|
3
|
+
یک کتابخانه React سبک و قدرتمند برای مدیریت ورودی اعداد فارسی و عربی با تبدیل خودکار ارقام، فرمتدهی و پشتیبانی از چند زبان.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/persian-number-input)
|
|
6
|
+
[](https://www.npmjs.com/package/persian-number-input)
|
|
7
|
+
[](https://bundlephobia.com/package/persian-number-input)
|
|
8
|
+
[](https://github.com/javadSharifi/persian-number-input/blob/main/LICENSE)
|
|
9
|
+
|
|
10
|
+
## 🚀 [دموی آنلاین](https://persian-number-input.netlify.app/)
|
|
11
|
+
|
|
12
|
+
کامپوننت را به صورت زنده تجربه کنید!
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 📊 حجم باندل
|
|
17
|
+
|
|
18
|
+
این کتابخانه فوقالعاده سبک است:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
persian-number-input: تنها ~1KB (فشرده شده)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ✨ امکانات
|
|
29
|
+
|
|
30
|
+
- 🔢 **تبدیل خودکار ارقام** - تبدیل یکپارچه ارقام فارسی (۰-۹) و عربی (٠-٩) به انگلیسی و بالعکس
|
|
31
|
+
- 🌍 **پشتیبانی چندزبانه** - پشتیبانی داخلی از فارسی (fa)، عربی (ar) و انگلیسی (en)
|
|
32
|
+
- 📊 **فرمتدهی اعداد** - جداکننده هزارگان خودکار با کاراکترهای قابل تنظیم
|
|
33
|
+
- 💰 **آماده برای ارز** - امکان افزودن پیشوند، پسوند و جداکننده اعشاری سفارشی
|
|
34
|
+
- ⚡ **سبک و سریع** - حجم بسیار کم با صفر وابستگی (به جز decimal.js برای دقت)
|
|
35
|
+
- 🎯 **Type-Safe** - پشتیبانی کامل TypeScript با تعاریف تایپ کامل
|
|
36
|
+
- ♿ **قابل دسترس** - پیروی از بهترین شیوههای دسترسیپذیری
|
|
37
|
+
- 🎨 **قابل سفارشیسازی** - گزینههای پیکربندی گسترده برای هر نیازی
|
|
38
|
+
- 🔄 **فرمتدهی لحظهای** - فرمت کردن اعداد همزمان با تایپ کاربر با حفظ موقعیت مکاننما
|
|
39
|
+
- ✅ **اعتبارسنجی** - کنترل داخلی مقادیر min/max و دقت اعشاری
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 📦 نصب
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install persian-number-input
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
yarn add persian-number-input
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm add persian-number-input
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 🎯 شروع سریع
|
|
60
|
+
|
|
61
|
+
### استفاده ساده
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { PersianNumberInput } from "persian-number-input";
|
|
65
|
+
|
|
66
|
+
function App() {
|
|
67
|
+
return (
|
|
68
|
+
<PersianNumberInput
|
|
69
|
+
initialValue={1234567}
|
|
70
|
+
locale="fa"
|
|
71
|
+
onValueChange={(value) => console.log(value)}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**خروجی:** `۱,۲۳۴,۵۶۷`
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 📚 نمونههای کاربردی
|
|
82
|
+
|
|
83
|
+
### ورودی مبلغ (تومان ایران)
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
<PersianNumberInput
|
|
87
|
+
initialValue={5000000}
|
|
88
|
+
locale="fa"
|
|
89
|
+
suffix="تومان"
|
|
90
|
+
separatorCount={3}
|
|
91
|
+
separatorChar=","
|
|
92
|
+
onValueChange={(value) => console.log(value)}
|
|
93
|
+
/>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**خروجی:** `۵,۰۰۰,۰۰۰ تومان`
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### اعداد اعشاری با جداکننده سفارشی
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
<PersianNumberInput
|
|
104
|
+
initialValue={1234.56}
|
|
105
|
+
locale="fa"
|
|
106
|
+
maxDecimals={2}
|
|
107
|
+
decimalChar="٫"
|
|
108
|
+
separatorChar=","
|
|
109
|
+
onValueChange={(value) => console.log(value)}
|
|
110
|
+
/>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**خروجی:** `۱,۲۳۴٫۵۶`
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
### ورودی قیمت با اعتبارسنجی
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<PersianNumberInput
|
|
121
|
+
initialValue={0}
|
|
122
|
+
locale="fa"
|
|
123
|
+
min={0}
|
|
124
|
+
max={999999999}
|
|
125
|
+
suffix="ریال"
|
|
126
|
+
showZero={true}
|
|
127
|
+
onValueChange={(value) => console.log(value)}
|
|
128
|
+
/>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**خروجی:** `۰ ریال`
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### زبان عربی
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
<PersianNumberInput
|
|
139
|
+
initialValue={987654}
|
|
140
|
+
locale="ar"
|
|
141
|
+
separatorChar=","
|
|
142
|
+
suffix="ر.س"
|
|
143
|
+
onValueChange={(value) => console.log(value)}
|
|
144
|
+
/>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**خروجی:** `٩٨٧,٦٥٤ ر.س`
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### استفاده از Hook (پیشرفته)
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import { usePersianNumberInput } from "persian-number-input";
|
|
155
|
+
|
|
156
|
+
function CustomInput() {
|
|
157
|
+
const { value, onChange, onBlur, rawValue } = usePersianNumberInput({
|
|
158
|
+
initialValue: 1000,
|
|
159
|
+
locale: "fa",
|
|
160
|
+
separatorCount: 3,
|
|
161
|
+
maxDecimals: 2,
|
|
162
|
+
min: 0,
|
|
163
|
+
max: 1000000,
|
|
164
|
+
onValueChange: (val) => {
|
|
165
|
+
console.log("مقدار خام:", val); // "1000"
|
|
166
|
+
console.log("مقدار نمایشی:", value); // "۱,۰۰۰"
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<input
|
|
172
|
+
type="text"
|
|
173
|
+
value={value}
|
|
174
|
+
onChange={onChange}
|
|
175
|
+
onBlur={onBlur}
|
|
176
|
+
className="custom-input"
|
|
177
|
+
/>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 🛠️ مرجع API
|
|
185
|
+
|
|
186
|
+
### Props کامپوننت PersianNumberInput
|
|
187
|
+
|
|
188
|
+
| ویژگی | نوع | پیشفرض | توضیحات |
|
|
189
|
+
| ---------------- | -------------------------------------- | ----------- | --------------------------------------------------------------- |
|
|
190
|
+
| `initialValue` | `number \| string` | `undefined` | مقدار اولیه ورودی |
|
|
191
|
+
| `locale` | `"fa" \| "ar" \| "en"` | `"fa"` | زبان برای تبدیل ارقام |
|
|
192
|
+
| `separatorCount` | `number` | `3` | تعداد ارقام بین جداکنندهها |
|
|
193
|
+
| `separatorChar` | `string` | `","` | کاراکتر جداکننده هزارگان |
|
|
194
|
+
| `decimalChar` | `string` | خودکار | کاراکتر جداکننده اعشار |
|
|
195
|
+
| `suffix` | `string` | `undefined` | متن پسوند (مثل واحد پول) |
|
|
196
|
+
| `maxDecimals` | `number` | `undefined` | حداکثر رقم اعشار مجاز |
|
|
197
|
+
| `min` | `number` | `undefined` | کمترین مقدار مجاز |
|
|
198
|
+
| `max` | `number` | `undefined` | بیشترین مقدار مجاز |
|
|
199
|
+
| `showZero` | `boolean` | `false` | نمایش صفر وقتی مقدار خالی است |
|
|
200
|
+
| `onValueChange` | `(value: string \| undefined) => void` | `undefined` | تابع فراخوانی هنگام تغییر مقدار (ارقام انگلیسی خام برمیگرداند) |
|
|
201
|
+
|
|
202
|
+
تمام props استاندارد HTML input نیز پشتیبانی میشوند.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### توابع کمکی
|
|
207
|
+
|
|
208
|
+
#### `transformNumber(rawValue, options)`
|
|
209
|
+
|
|
210
|
+
یک رشته عددی را بر اساس زبان و تنظیمات فرمت میکند.
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
import { transformNumber } from "persian-number-input";
|
|
214
|
+
|
|
215
|
+
const formatted = transformNumber("1234567.89", {
|
|
216
|
+
locale: "fa",
|
|
217
|
+
separatorCount: 3,
|
|
218
|
+
separatorChar: ",",
|
|
219
|
+
maxDecimals: 2,
|
|
220
|
+
suffix: "تومان",
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
console.log(formatted); // "۱,۲۳۴,۵۶۷٫۸۹ تومان"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### `toEnglishDigits(str, decimalChar?)`
|
|
227
|
+
|
|
228
|
+
ارقام فارسی/عربی را به انگلیسی تبدیل میکند.
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import { toEnglishDigits } from "persian-number-input";
|
|
232
|
+
|
|
233
|
+
console.log(toEnglishDigits("۱۲۳۴")); // "1234"
|
|
234
|
+
console.log(toEnglishDigits("٩٨٧٦")); // "9876"
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
#### `toLocalizedDigits(numStr, locale)`
|
|
238
|
+
|
|
239
|
+
ارقام انگلیسی را به ارقام محلی تبدیل میکند.
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
import { toLocalizedDigits } from "persian-number-input";
|
|
243
|
+
|
|
244
|
+
console.log(toLocalizedDigits("1234", "fa")); // "۱۲۳۴"
|
|
245
|
+
console.log(toLocalizedDigits("5678", "ar")); // "٥٦٧٨"
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### `sanitizeNumericInput(value, maxDecimals?, decimalChar?)`
|
|
249
|
+
|
|
250
|
+
ورودی عددی را پاکسازی و اعتبارسنجی میکند.
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
import { sanitizeNumericInput } from "persian-number-input";
|
|
254
|
+
|
|
255
|
+
console.log(sanitizeNumericInput("۱۲۳abc۴۵۶", 2)); // "123456"
|
|
256
|
+
console.log(sanitizeNumericInput("12.345.67", 2)); // "12.34"
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 🎨 استایلدهی
|
|
262
|
+
|
|
263
|
+
کامپوننت تمام props استاندارد input را میپذیرد، از جمله `className` و `style`:
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
<PersianNumberInput
|
|
267
|
+
initialValue={1000}
|
|
268
|
+
locale="fa"
|
|
269
|
+
className="custom-input"
|
|
270
|
+
style={{
|
|
271
|
+
padding: "12px",
|
|
272
|
+
fontSize: "16px",
|
|
273
|
+
border: "2px solid #4F46E5",
|
|
274
|
+
borderRadius: "8px",
|
|
275
|
+
textAlign: "right",
|
|
276
|
+
}}
|
|
277
|
+
/>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### با Tailwind CSS
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
<PersianNumberInput
|
|
284
|
+
initialValue={1000}
|
|
285
|
+
locale="fa"
|
|
286
|
+
className="w-full px-4 py-3 text-lg border-2 border-indigo-500 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-600 text-right"
|
|
287
|
+
/>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 🌟 مثالهای پیشرفته
|
|
293
|
+
|
|
294
|
+
### ماشین حساب مالی
|
|
295
|
+
|
|
296
|
+
```tsx
|
|
297
|
+
import { useState } from "react";
|
|
298
|
+
import { PersianNumberInput } from "persian-number-input";
|
|
299
|
+
|
|
300
|
+
function LoanCalculator() {
|
|
301
|
+
const [principal, setPrincipal] = useState<string>();
|
|
302
|
+
const [rate, setRate] = useState<string>();
|
|
303
|
+
const [years, setYears] = useState<string>();
|
|
304
|
+
|
|
305
|
+
const calculateMonthlyPayment = () => {
|
|
306
|
+
if (!principal || !rate || !years) return 0;
|
|
307
|
+
const p = parseFloat(principal);
|
|
308
|
+
const r = parseFloat(rate) / 100 / 12;
|
|
309
|
+
const n = parseFloat(years) * 12;
|
|
310
|
+
return (p * r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
return (
|
|
314
|
+
<div className="space-y-4">
|
|
315
|
+
<div>
|
|
316
|
+
<label>مبلغ وام:</label>
|
|
317
|
+
<PersianNumberInput
|
|
318
|
+
locale="fa"
|
|
319
|
+
suffix="تومان"
|
|
320
|
+
onValueChange={setPrincipal}
|
|
321
|
+
min={0}
|
|
322
|
+
/>
|
|
323
|
+
</div>
|
|
324
|
+
<div>
|
|
325
|
+
<label>نرخ سود (٪):</label>
|
|
326
|
+
<PersianNumberInput
|
|
327
|
+
locale="fa"
|
|
328
|
+
maxDecimals={2}
|
|
329
|
+
onValueChange={setRate}
|
|
330
|
+
min={0}
|
|
331
|
+
max={100}
|
|
332
|
+
/>
|
|
333
|
+
</div>
|
|
334
|
+
<div>
|
|
335
|
+
<label>مدت زمان (سال):</label>
|
|
336
|
+
<PersianNumberInput
|
|
337
|
+
locale="fa"
|
|
338
|
+
onValueChange={setYears}
|
|
339
|
+
min={1}
|
|
340
|
+
max={30}
|
|
341
|
+
/>
|
|
342
|
+
</div>
|
|
343
|
+
<p>
|
|
344
|
+
پرداخت ماهیانه: {calculateMonthlyPayment().toLocaleString("fa-IR")}{" "}
|
|
345
|
+
تومان
|
|
346
|
+
</p>
|
|
347
|
+
</div>
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### یکپارچگی با فرم
|
|
355
|
+
|
|
356
|
+
```tsx
|
|
357
|
+
import { useForm, Controller } from "react-hook-form";
|
|
358
|
+
import { PersianNumberInput } from "persian-number-input";
|
|
359
|
+
|
|
360
|
+
function ProductForm() {
|
|
361
|
+
const { control, handleSubmit } = useForm();
|
|
362
|
+
|
|
363
|
+
const onSubmit = (data) => {
|
|
364
|
+
console.log(data);
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
return (
|
|
368
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
369
|
+
<Controller
|
|
370
|
+
name="price"
|
|
371
|
+
control={control}
|
|
372
|
+
rules={{ required: true }}
|
|
373
|
+
render={({ field }) => (
|
|
374
|
+
<PersianNumberInput
|
|
375
|
+
locale="fa"
|
|
376
|
+
suffix="تومان"
|
|
377
|
+
onValueChange={field.onChange}
|
|
378
|
+
initialValue={field.value}
|
|
379
|
+
/>
|
|
380
|
+
)}
|
|
381
|
+
/>
|
|
382
|
+
<button type="submit">ثبت</button>
|
|
383
|
+
</form>
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## 🔍 چرا ورودی اعداد فارسی؟
|
|
391
|
+
|
|
392
|
+
### مشکل
|
|
393
|
+
|
|
394
|
+
کار با ارقام فارسی و عربی در برنامههای وب چالشبرانگیز است:
|
|
395
|
+
|
|
396
|
+
- کاربران با ارقام بومی خود تایپ میکنند، اما فرمها ارقام انگلیسی انتظار دارند
|
|
397
|
+
- فرمتدهی اعداد در زبانهای مختلف متفاوت است
|
|
398
|
+
- حفظ موقعیت مکاننما هنگام فرمتدهی پیچیده است
|
|
399
|
+
- مدیریت دقت اعشاری نیاز به پیادهسازی دقیق دارد
|
|
400
|
+
|
|
401
|
+
### راهحل
|
|
402
|
+
|
|
403
|
+
ورودی اعداد فارسی تمام این پیچیدگیها را به صورت خودکار مدیریت میکند:
|
|
404
|
+
|
|
405
|
+
```tsx
|
|
406
|
+
// کاربر تایپ میکند: ۱۲۳۴۵۶۷
|
|
407
|
+
// کامپوننت نمایش میدهد: ۱,۲۳۴,۵۶۷
|
|
408
|
+
// فرم دریافت میکند: "1234567"
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## 🏆 مقایسه
|
|
414
|
+
|
|
415
|
+
| امکانات | ورودی اعداد فارسی | Input معمولی | کتابخانههای دیگر |
|
|
416
|
+
| ------------------- | ----------------- | ------------ | ----------------- |
|
|
417
|
+
| تبدیل خودکار ارقام | ✅ | ❌ | ⚠️ جزئی |
|
|
418
|
+
| حفظ مکاننما | ✅ | ❌ | ⚠️ باگدار |
|
|
419
|
+
| پشتیبانی TypeScript | ✅ | ✅ | ⚠️ متغیر |
|
|
420
|
+
| چند زبانه | ✅ | ❌ | ❌ |
|
|
421
|
+
| حجم باندل | 🟢 کم | 🟢 - | 🔴 زیاد |
|
|
422
|
+
| دقت اعشاری | ✅ | ❌ | ⚠️ محدود |
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## 🤝 مشارکت
|
|
427
|
+
|
|
428
|
+
مشارکت شما استقبال میشود! لطفاً از ارسال Pull Request دریغ نکنید.
|
|
429
|
+
|
|
430
|
+
1. مخزن را Fork کنید
|
|
431
|
+
2. شاخه ویژگی خود را ایجاد کنید (`git checkout -b feature/AmazingFeature`)
|
|
432
|
+
3. تغییرات خود را Commit کنید (`git commit -m 'Add some AmazingFeature'`)
|
|
433
|
+
4. به شاخه Push کنید (`git push origin feature/AmazingFeature`)
|
|
434
|
+
5. یک Pull Request باز کنید
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## 📄 مجوز
|
|
439
|
+
|
|
440
|
+
MIT © javad Sharifi
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## 🙏 تشکرات
|
|
445
|
+
|
|
446
|
+
- ساخته شده با TypeScript و React
|
|
447
|
+
- استفاده از [decimal.js](https://github.com/MikeMcl/decimal.js/) برای محاسبات دقیق اعشاری
|
|
448
|
+
- الهامگرفته از نیازهای توسعهدهندگان فارسی و عربیزبان
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## 📞 پشتیبانی
|
|
453
|
+
|
|
454
|
+
- 📧 telegram: [Javad Sharifi](https://t.me/Javad_sharifi98)
|
|
455
|
+
- 🐛 [گزارش مشکلات](https://github.com/javadSharifi/persian-number-input/issues)
|
|
456
|
+
- 💬 [بحث و گفتگو](https://github.com/javadSharifi/persian-number-input/discussions)
|
|
457
|
+
|
|
458
|
+
**ساخته شده با ❤️ برای جامعه توسعهدهندگان فارسی و عربیزبان**
|
package/README.md
CHANGED
|
@@ -1,389 +1,461 @@
|
|
|
1
1
|
# Persian Number Input
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[فارسی](./README.fa.md) | English
|
|
4
|
+
A lightweight, powerful React library for handling Persian (Farsi) and Arabic number inputs with automatic digit conversion, formatting, and localization support.
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/persian-number-input)
|
|
7
|
+
[](https://www.npmjs.com/package/persian-number-input)
|
|
8
|
+
[](https://bundlephobia.com/package/persian-number-input)
|
|
9
|
+
[](https://github.com/javadSharifi/persian-number-input/blob/main/LICENSE)
|
|
10
|
+
|
|
11
|
+
## 🚀 [Live Demo](https://persian-number-input.netlify.app/)
|
|
4
12
|
|
|
5
13
|
---
|
|
6
14
|
|
|
7
|
-
|
|
15
|
+
Experience the component in action with our interactive demo!
|
|
16
|
+
|
|
17
|
+
## 📊 Bundle Size
|
|
18
|
+
|
|
19
|
+
This library is extremely lightweight:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
persian-number-input: ~1KB (minified + gzipped)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+

|
|
8
26
|
|
|
9
27
|
---
|
|
10
28
|
|
|
11
|
-
##
|
|
29
|
+
## ✨ Features
|
|
12
30
|
|
|
13
|
-
**
|
|
31
|
+
- 🔢 **Automatic Digit Conversion** - Seamlessly converts Persian (۰-۹) and Arabic (٠-٩) digits to English and vice versa
|
|
32
|
+
- 🌍 **Multi-locale Support** - Built-in support for Persian (fa), Arabic (ar), and English (en)
|
|
33
|
+
- 📊 **Number Formatting** - Automatic thousand separators with customizable characters
|
|
34
|
+
- 💰 **Currency Ready** - Add prefixes, suffixes, and custom decimal separators
|
|
35
|
+
- ⚡ **Lightweight** - Tiny bundle size with zero dependencies (except decimal.js for precision)
|
|
36
|
+
- 🎯 **Type-Safe** - Full TypeScript support with complete type definitions
|
|
37
|
+
- ♿ **Accessible** - Follows best practices for input accessibility
|
|
38
|
+
- 🎨 **Customizable** - Extensive configuration options for any use case
|
|
39
|
+
- 🔄 **Real-time Formatting** - Format numbers as users type with cursor position preservation
|
|
40
|
+
- ✅ **Validation** - Built-in min/max value validation and decimal precision control
|
|
14
41
|
|
|
15
|
-
|
|
42
|
+
---
|
|
16
43
|
|
|
17
|
-
|
|
18
|
-
- Customizable digit grouping (e.g., thousands separator)
|
|
19
|
-
- Handles decimal numbers with configurable precision using ``
|
|
20
|
-
- Min/max value constraints for input validation, including decimals
|
|
21
|
-
- Converts localized digits to standard English digits for processing
|
|
22
|
-
- Lightweight and compatible with React 16 to 19
|
|
23
|
-
- TypeScript support for robust development
|
|
44
|
+
## 📦 Installation
|
|
24
45
|
|
|
25
|
-
|
|
46
|
+
```bash
|
|
47
|
+
npm install persian-number-input
|
|
48
|
+
```
|
|
26
49
|
|
|
27
|
-
|
|
50
|
+
```bash
|
|
51
|
+
yarn add persian-number-input
|
|
52
|
+
```
|
|
28
53
|
|
|
29
54
|
```bash
|
|
30
|
-
|
|
55
|
+
pnpm add persian-number-input
|
|
31
56
|
```
|
|
32
57
|
|
|
33
|
-
|
|
58
|
+
---
|
|
34
59
|
|
|
35
|
-
|
|
60
|
+
## 🎯 Quick Start
|
|
36
61
|
|
|
37
|
-
|
|
62
|
+
### Basic Usage
|
|
38
63
|
|
|
39
|
-
```
|
|
40
|
-
import React, { useState } from "react";
|
|
64
|
+
```tsx
|
|
41
65
|
import { PersianNumberInput } from "persian-number-input";
|
|
42
66
|
|
|
43
|
-
|
|
44
|
-
const [number, setNumber] = useState("");
|
|
45
|
-
|
|
67
|
+
function App() {
|
|
46
68
|
return (
|
|
47
69
|
<PersianNumberInput
|
|
48
|
-
initialValue=
|
|
49
|
-
separatorCount={3}
|
|
50
|
-
separatorChar=","
|
|
70
|
+
initialValue={1234567}
|
|
51
71
|
locale="fa"
|
|
52
|
-
|
|
53
|
-
min={0.5}
|
|
54
|
-
max={1000000.999}
|
|
55
|
-
showZero={true}
|
|
56
|
-
onValueChange={(val) => setNumber(val || "")}
|
|
57
|
-
placeholder="Enter a number"
|
|
58
|
-
className="numeric-input"
|
|
72
|
+
onValueChange={(value) => console.log(value)}
|
|
59
73
|
/>
|
|
60
74
|
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export default App;
|
|
75
|
+
}
|
|
64
76
|
```
|
|
65
77
|
|
|
66
|
-
**Output
|
|
78
|
+
**Output:** `۱,۲۳۴,۵۶۷`
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 📚 Usage Examples
|
|
83
|
+
|
|
84
|
+
### Currency Input (Persian Toman)
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
<PersianNumberInput
|
|
88
|
+
initialValue={5000000}
|
|
89
|
+
locale="fa"
|
|
90
|
+
suffix="تومان"
|
|
91
|
+
separatorCount={3}
|
|
92
|
+
separatorChar=","
|
|
93
|
+
onValueChange={(value) => console.log(value)}
|
|
94
|
+
/>
|
|
67
95
|
```
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
96
|
+
|
|
97
|
+
**Output:** `۵,۰۰۰,۰۰۰ تومان`
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### Decimal Numbers with Custom Separator
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<PersianNumberInput
|
|
105
|
+
initialValue={1234.56}
|
|
106
|
+
locale="fa"
|
|
107
|
+
maxDecimals={2}
|
|
108
|
+
decimalChar="٫"
|
|
109
|
+
separatorChar=","
|
|
110
|
+
onValueChange={(value) => console.log(value)}
|
|
111
|
+
/>
|
|
71
112
|
```
|
|
72
113
|
|
|
73
|
-
|
|
114
|
+
**Output:** `۱,۲۳۴٫۵۶`
|
|
115
|
+
|
|
116
|
+
---
|
|
74
117
|
|
|
75
|
-
|
|
118
|
+
### Price Input with Validation
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
<PersianNumberInput
|
|
122
|
+
initialValue={0}
|
|
123
|
+
locale="fa"
|
|
124
|
+
min={0}
|
|
125
|
+
max={999999999}
|
|
126
|
+
suffix="ریال"
|
|
127
|
+
showZero={true}
|
|
128
|
+
onValueChange={(value) => console.log(value)}
|
|
129
|
+
/>
|
|
130
|
+
```
|
|
76
131
|
|
|
77
|
-
|
|
78
|
-
import React from "react";
|
|
79
|
-
import { usePersianNumberInput } from "persian-number-input";
|
|
132
|
+
**Output:** `۰ ریال`
|
|
80
133
|
|
|
81
|
-
|
|
82
|
-
const { value, onChange, rawValue } = usePersianNumberInput({
|
|
83
|
-
initialValue: "5000.25",
|
|
84
|
-
separatorCount: 3,
|
|
85
|
-
separatorChar: ",",
|
|
86
|
-
locale: "fa",
|
|
87
|
-
maxDecimals: 2,
|
|
88
|
-
min: 0.5,
|
|
89
|
-
max: 10000.999,
|
|
90
|
-
showZero: true,
|
|
91
|
-
});
|
|
134
|
+
---
|
|
92
135
|
|
|
93
|
-
|
|
94
|
-
<div>
|
|
95
|
-
<input
|
|
96
|
-
type="text"
|
|
97
|
-
inputMode="decimal"
|
|
98
|
-
value={value}
|
|
99
|
-
onChange={onChange}
|
|
100
|
-
placeholder="Enter a number"
|
|
101
|
-
/>
|
|
102
|
-
<p>Raw Value: {rawValue || "N/A"}</p>
|
|
103
|
-
</div>
|
|
104
|
-
);
|
|
105
|
-
};
|
|
136
|
+
### Arabic Locale
|
|
106
137
|
|
|
107
|
-
|
|
138
|
+
```tsx
|
|
139
|
+
<PersianNumberInput
|
|
140
|
+
initialValue={987654}
|
|
141
|
+
locale="ar"
|
|
142
|
+
separatorChar=","
|
|
143
|
+
suffix="ر.س"
|
|
144
|
+
onValueChange={(value) => console.log(value)}
|
|
145
|
+
/>
|
|
108
146
|
```
|
|
109
147
|
|
|
110
|
-
**
|
|
111
|
-
- The hook manages the input state and formatting, returning `value` (formatted for display) and `rawValue` (English digits).
|
|
112
|
-
- Use this for custom input components or non-standard form controls.
|
|
113
|
-
- **Output**:
|
|
114
|
-
```
|
|
115
|
-
Displayed Input:ავ۰٫۲۵
|
|
116
|
-
Raw Value: 5000.25
|
|
117
|
-
```
|
|
148
|
+
**Output:** `٩٨٧,٦٥٤ ر.س`
|
|
118
149
|
|
|
119
|
-
|
|
150
|
+
---
|
|
120
151
|
|
|
121
|
-
|
|
152
|
+
### Using the Hook (Advanced)
|
|
122
153
|
|
|
123
|
-
```
|
|
124
|
-
import {
|
|
154
|
+
```tsx
|
|
155
|
+
import { usePersianNumberInput } from "persian-number-input";
|
|
125
156
|
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
157
|
+
function CustomInput() {
|
|
158
|
+
const { value, onChange, onBlur, rawValue } = usePersianNumberInput({
|
|
159
|
+
initialValue: 1000,
|
|
160
|
+
locale: "fa",
|
|
161
|
+
separatorCount: 3,
|
|
162
|
+
maxDecimals: 2,
|
|
163
|
+
min: 0,
|
|
164
|
+
max: 1000000,
|
|
165
|
+
onValueChange: (val) => {
|
|
166
|
+
console.log("Raw value:", val); // "1000"
|
|
167
|
+
console.log("Displayed value:", value); // "۱,۰۰۰"
|
|
168
|
+
},
|
|
169
|
+
});
|
|
134
170
|
|
|
135
|
-
|
|
171
|
+
return (
|
|
172
|
+
<input
|
|
173
|
+
type="text"
|
|
174
|
+
value={value}
|
|
175
|
+
onChange={onChange}
|
|
176
|
+
onBlur={onBlur}
|
|
177
|
+
className="custom-input"
|
|
178
|
+
/>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
136
181
|
```
|
|
137
182
|
|
|
138
|
-
|
|
139
|
-
- Use `transformNumber` to format numbers for display in tables, labels, or other non-input contexts.
|
|
140
|
-
- Supports the same options as `PersianNumberInput` (`separatorCount`, `locale`, etc.).
|
|
141
|
-
- Returns a string with localized digits and formatting.
|
|
142
|
-
|
|
143
|
-
### 📚 Props Reference
|
|
183
|
+
---
|
|
144
184
|
|
|
145
|
-
|
|
146
|
-
| --- | --- | --- | --- |
|
|
147
|
-
| `initialValue` | `string | number` | `""` | Initial value of the input |
|
|
148
|
-
| `separatorCount` | `number` | `3` | Number of digits per group (e.g., 3 for thousands) |
|
|
149
|
-
| `separatorChar` | `string` | `","` | Character used for grouping digits (e.g., `,` or `.`) |
|
|
150
|
-
| `locale` | `string` | `"fa"` | Language for digit localization (e.g., `fa`, `en`) |
|
|
151
|
-
| `maxDecimals` | `number` | `0` | Maximum number of decimal places allowed |
|
|
152
|
-
| `showZero` | `boolean` | `false` | If `true`, displays `0` when the input is empty or zero |
|
|
153
|
-
| `min` | `number` | - | Minimum allowed value (supports decimals, e.g., `0.5`) |
|
|
154
|
-
| `max` | `number` | - | Maximum allowed value (supports decimals, e.g., `1000.201`) |
|
|
155
|
-
| `onValueChange` | `(value: string | undefined) => void` | - | Callback for value changes |
|
|
156
|
-
| `...rest` | `InputHTMLAttributes` | - | Standard HTML input attributes (e.g., `className`, `placeholder`, `style`) |
|
|
185
|
+
## 🛠️ API Reference
|
|
157
186
|
|
|
158
|
-
###
|
|
187
|
+
### PersianNumberInput Props
|
|
159
188
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
189
|
+
| Prop | Type | Default | Description |
|
|
190
|
+
| ---------------- | -------------------------------------- | ----------- | -------------------------------------------------------- |
|
|
191
|
+
| `initialValue` | `number \| string` | `undefined` | Initial value of the input |
|
|
192
|
+
| `locale` | `"fa" \| "ar" \| "en"` | `"fa"` | Locale for digit conversion |
|
|
193
|
+
| `separatorCount` | `number` | `3` | Number of digits between separators |
|
|
194
|
+
| `separatorChar` | `string` | `","` | Character used for thousand separator |
|
|
195
|
+
| `decimalChar` | `string` | Auto | Decimal separator character |
|
|
196
|
+
| `suffix` | `string` | `undefined` | Suffix text (e.g., currency symbol) |
|
|
197
|
+
| `maxDecimals` | `number` | `undefined` | Maximum decimal places allowed |
|
|
198
|
+
| `min` | `number` | `undefined` | Minimum allowed value |
|
|
199
|
+
| `max` | `number` | `undefined` | Maximum allowed value |
|
|
200
|
+
| `showZero` | `boolean` | `false` | Show zero when value is empty |
|
|
201
|
+
| `onValueChange` | `(value: string \| undefined) => void` | `undefined` | Callback when value changes (returns raw English digits) |
|
|
165
202
|
|
|
166
|
-
|
|
203
|
+
All standard HTML input props are also supported.
|
|
167
204
|
|
|
168
|
-
|
|
169
|
-
Yes, it is fully compatible with React 16 through 19.
|
|
205
|
+
---
|
|
170
206
|
|
|
171
|
-
|
|
172
|
-
Yes, set `maxDecimals` to the desired number of decimal places (e.g., `maxDecimals={2}`).
|
|
207
|
+
### Utility Functions
|
|
173
208
|
|
|
174
|
-
|
|
175
|
-
Use the `min` and `max` props, which support decimals (e.g., `min={0.5}`, `max={1000.201}`).
|
|
209
|
+
#### `transformNumber(rawValue, options)`
|
|
176
210
|
|
|
177
|
-
|
|
178
|
-
Pass `className` or `style` props to customize the input’s appearance.
|
|
211
|
+
Formats a number string according to locale and options.
|
|
179
212
|
|
|
180
|
-
|
|
181
|
-
|
|
213
|
+
```tsx
|
|
214
|
+
import { transformNumber } from "persian-number-input";
|
|
182
215
|
|
|
183
|
-
|
|
216
|
+
const formatted = transformNumber("1234567.89", {
|
|
217
|
+
locale: "fa",
|
|
218
|
+
separatorCount: 3,
|
|
219
|
+
separatorChar: ",",
|
|
220
|
+
maxDecimals: 2,
|
|
221
|
+
suffix: "تومان",
|
|
222
|
+
});
|
|
184
223
|
|
|
185
|
-
|
|
224
|
+
console.log(formatted); // "۱,۲۳۴,۵۶۷٫۸۹ تومان"
|
|
225
|
+
```
|
|
186
226
|
|
|
187
|
-
|
|
227
|
+
#### `toEnglishDigits(str, decimalChar?)`
|
|
188
228
|
|
|
189
|
-
|
|
229
|
+
Converts Persian/Arabic digits to English digits.
|
|
190
230
|
|
|
191
|
-
|
|
231
|
+
```tsx
|
|
232
|
+
import { toEnglishDigits } from "persian-number-input";
|
|
192
233
|
|
|
193
|
-
|
|
234
|
+
console.log(toEnglishDigits("۱۲۳۴")); // "1234"
|
|
235
|
+
console.log(toEnglishDigits("٩٨٧٦")); // "9876"
|
|
236
|
+
```
|
|
194
237
|
|
|
195
|
-
|
|
238
|
+
#### `toLocalizedDigits(numStr, locale)`
|
|
196
239
|
|
|
197
|
-
|
|
240
|
+
Converts English digits to localized digits.
|
|
198
241
|
|
|
199
|
-
|
|
242
|
+
```tsx
|
|
243
|
+
import { toLocalizedDigits } from "persian-number-input";
|
|
200
244
|
|
|
201
|
-
|
|
245
|
+
console.log(toLocalizedDigits("1234", "fa")); // "۱۲۳۴"
|
|
246
|
+
console.log(toLocalizedDigits("5678", "ar")); // "٥٦٧٨"
|
|
247
|
+
```
|
|
202
248
|
|
|
203
|
-
|
|
249
|
+
#### `sanitizeNumericInput(value, maxDecimals?, decimalChar?)`
|
|
204
250
|
|
|
205
|
-
|
|
251
|
+
Cleans and validates numeric input.
|
|
206
252
|
|
|
207
|
-
|
|
253
|
+
```tsx
|
|
254
|
+
import { sanitizeNumericInput } from "persian-number-input";
|
|
208
255
|
|
|
209
|
-
|
|
210
|
-
|
|
256
|
+
console.log(sanitizeNumericInput("۱۲۳abc۴۵۶", 2)); // "123456"
|
|
257
|
+
console.log(sanitizeNumericInput("12.345.67", 2)); // "12.34"
|
|
258
|
+
```
|
|
211
259
|
|
|
212
|
-
|
|
213
|
-
- تبدیل خودکار ارقام محلی به ارقام انگلیسی برای پردازش
|
|
214
|
-
- سبک و سازگار با React 16 تا 19
|
|
215
|
-
- پشتیبانی از TypeScript برای توسعه امن
|
|
260
|
+
---
|
|
216
261
|
|
|
217
|
-
|
|
262
|
+
## 🎨 Styling
|
|
263
|
+
|
|
264
|
+
The component accepts all standard input props, including `className` and `style`:
|
|
265
|
+
|
|
266
|
+
```tsx
|
|
267
|
+
<PersianNumberInput
|
|
268
|
+
initialValue={1000}
|
|
269
|
+
locale="fa"
|
|
270
|
+
className="custom-input"
|
|
271
|
+
style={{
|
|
272
|
+
padding: "12px",
|
|
273
|
+
fontSize: "16px",
|
|
274
|
+
border: "2px solid #4F46E5",
|
|
275
|
+
borderRadius: "8px",
|
|
276
|
+
textAlign: "right",
|
|
277
|
+
}}
|
|
278
|
+
/>
|
|
279
|
+
```
|
|
218
280
|
|
|
219
|
-
|
|
281
|
+
### With Tailwind CSS
|
|
220
282
|
|
|
221
|
-
```
|
|
222
|
-
|
|
283
|
+
```tsx
|
|
284
|
+
<PersianNumberInput
|
|
285
|
+
initialValue={1000}
|
|
286
|
+
locale="fa"
|
|
287
|
+
className="w-full px-4 py-3 text-lg border-2 border-indigo-500 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-600 text-right"
|
|
288
|
+
/>
|
|
223
289
|
```
|
|
224
290
|
|
|
225
|
-
|
|
291
|
+
---
|
|
226
292
|
|
|
227
|
-
|
|
293
|
+
## 🌟 Advanced Examples
|
|
228
294
|
|
|
229
|
-
|
|
295
|
+
### Financial Calculator
|
|
230
296
|
|
|
231
|
-
```
|
|
232
|
-
import
|
|
297
|
+
```tsx
|
|
298
|
+
import { useState } from "react";
|
|
233
299
|
import { PersianNumberInput } from "persian-number-input";
|
|
234
300
|
|
|
235
|
-
|
|
236
|
-
const [
|
|
301
|
+
function LoanCalculator() {
|
|
302
|
+
const [principal, setPrincipal] = useState<string>();
|
|
303
|
+
const [rate, setRate] = useState<string>();
|
|
304
|
+
const [years, setYears] = useState<string>();
|
|
305
|
+
|
|
306
|
+
const calculateMonthlyPayment = () => {
|
|
307
|
+
if (!principal || !rate || !years) return 0;
|
|
308
|
+
const p = parseFloat(principal);
|
|
309
|
+
const r = parseFloat(rate) / 100 / 12;
|
|
310
|
+
const n = parseFloat(years) * 12;
|
|
311
|
+
return (p * r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1);
|
|
312
|
+
};
|
|
237
313
|
|
|
238
314
|
return (
|
|
239
|
-
<
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
315
|
+
<div className="space-y-4">
|
|
316
|
+
<div>
|
|
317
|
+
<label>مبلغ وام:</label>
|
|
318
|
+
<PersianNumberInput
|
|
319
|
+
locale="fa"
|
|
320
|
+
suffix="تومان"
|
|
321
|
+
onValueChange={setPrincipal}
|
|
322
|
+
min={0}
|
|
323
|
+
/>
|
|
324
|
+
</div>
|
|
325
|
+
<div>
|
|
326
|
+
<label>نرخ سود (٪):</label>
|
|
327
|
+
<PersianNumberInput
|
|
328
|
+
locale="fa"
|
|
329
|
+
maxDecimals={2}
|
|
330
|
+
onValueChange={setRate}
|
|
331
|
+
min={0}
|
|
332
|
+
max={100}
|
|
333
|
+
/>
|
|
334
|
+
</div>
|
|
335
|
+
<div>
|
|
336
|
+
<label>مدت زمان (سال):</label>
|
|
337
|
+
<PersianNumberInput
|
|
338
|
+
locale="fa"
|
|
339
|
+
onValueChange={setYears}
|
|
340
|
+
min={1}
|
|
341
|
+
max={30}
|
|
342
|
+
/>
|
|
343
|
+
</div>
|
|
344
|
+
<p>
|
|
345
|
+
پرداخت ماهیانه: {calculateMonthlyPayment().toLocaleString("fa-IR")}{" "}
|
|
346
|
+
تومان
|
|
347
|
+
</p>
|
|
348
|
+
</div>
|
|
252
349
|
);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
export default App;
|
|
350
|
+
}
|
|
256
351
|
```
|
|
257
352
|
|
|
258
|
-
|
|
259
|
-
```
|
|
260
|
-
ورودی: 123456.78
|
|
261
|
-
خروجی نمایشی: ۱۲۳,۴۵۶٫۷۸
|
|
262
|
-
خروجی انگلیسی: 123456.78
|
|
263
|
-
```
|
|
353
|
+
---
|
|
264
354
|
|
|
265
|
-
|
|
355
|
+
### Form Integration
|
|
266
356
|
|
|
267
|
-
|
|
357
|
+
```tsx
|
|
358
|
+
import { useForm, Controller } from "react-hook-form";
|
|
359
|
+
import { PersianNumberInput } from "persian-number-input";
|
|
268
360
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
import { usePersianNumberInput } from "persian-number-input";
|
|
361
|
+
function ProductForm() {
|
|
362
|
+
const { control, handleSubmit } = useForm();
|
|
272
363
|
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
separatorCount: 3,
|
|
277
|
-
separatorChar: ",",
|
|
278
|
-
locale: "fa",
|
|
279
|
-
maxDecimals: 2,
|
|
280
|
-
min: 0.5,
|
|
281
|
-
max: 10000.999,
|
|
282
|
-
showZero: true,
|
|
283
|
-
});
|
|
364
|
+
const onSubmit = (data) => {
|
|
365
|
+
console.log(data);
|
|
366
|
+
};
|
|
284
367
|
|
|
285
368
|
return (
|
|
286
|
-
<
|
|
287
|
-
<
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
369
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
370
|
+
<Controller
|
|
371
|
+
name="price"
|
|
372
|
+
control={control}
|
|
373
|
+
rules={{ required: true }}
|
|
374
|
+
render={({ field }) => (
|
|
375
|
+
<PersianNumberInput
|
|
376
|
+
locale="fa"
|
|
377
|
+
suffix="تومان"
|
|
378
|
+
onValueChange={field.onChange}
|
|
379
|
+
initialValue={field.value}
|
|
380
|
+
/>
|
|
381
|
+
)}
|
|
293
382
|
/>
|
|
294
|
-
<
|
|
295
|
-
</
|
|
383
|
+
<button type="submit">ثبت</button>
|
|
384
|
+
</form>
|
|
296
385
|
);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
export default CustomInput;
|
|
386
|
+
}
|
|
300
387
|
```
|
|
301
388
|
|
|
302
|
-
|
|
303
|
-
- این هوک وضعیت ورودی و فرمتبندی را مدیریت میکند و `value` (برای نمایش) و `rawValue` (ارقام انگلیسی) را برمیگرداند.
|
|
304
|
-
- برای کامپوننتهای ورودی سفارشی یا فرمهای غیراستاندارد مناسب است.
|
|
305
|
-
- **خروجی**:
|
|
306
|
-
```
|
|
307
|
-
ورودی نمایشی: ۵,۰۰۰٫۲۵
|
|
308
|
-
مقدار خام: 5000.25
|
|
309
|
-
```
|
|
389
|
+
---
|
|
310
390
|
|
|
311
|
-
|
|
391
|
+
## 🔍 Why Persian Number Input?
|
|
312
392
|
|
|
313
|
-
|
|
393
|
+
### The Problem
|
|
314
394
|
|
|
315
|
-
|
|
316
|
-
import { transformNumber } from "persian-number-input";
|
|
395
|
+
Working with Persian and Arabic numerals in web applications is challenging:
|
|
317
396
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
locale: "fa",
|
|
323
|
-
maxDecimals: 2,
|
|
324
|
-
showZero: true,
|
|
325
|
-
});
|
|
397
|
+
- Users type in their native digits, but forms expect English digits
|
|
398
|
+
- Number formatting varies across locales
|
|
399
|
+
- Maintaining cursor position during formatting is complex
|
|
400
|
+
- Decimal precision handling requires careful implementation
|
|
326
401
|
|
|
327
|
-
|
|
328
|
-
```
|
|
402
|
+
### The Solution
|
|
329
403
|
|
|
330
|
-
|
|
331
|
-
- از `transformNumber` برای فرمتبندی اعداد در جداول، برچسبها یا سایر موارد غیرورودی استفاده کنید.
|
|
332
|
-
- همان گزینههای `PersianNumberInput` (مانند `separatorCount` و `locale`) را پشتیبانی میکند.
|
|
333
|
-
- یک رشته با ارقام محلی و فرمتبندی مناسب برمیگرداند.
|
|
404
|
+
Persian Number Input handles all these complexities automatically:
|
|
334
405
|
|
|
335
|
-
|
|
406
|
+
```tsx
|
|
407
|
+
// User types: ۱۲۳۴۵۶۷
|
|
408
|
+
// Component displays: ۱,۲۳۴,۵۶۷
|
|
409
|
+
// Form receives: "1234567"
|
|
410
|
+
```
|
|
336
411
|
|
|
337
|
-
|
|
338
|
-
| --- | --- | --- | --- |
|
|
339
|
-
| `initialValue` | `string | number` | `""` | مقدار اولیه ورودی |
|
|
340
|
-
| `separatorCount` | `number` | `3` | تعداد ارقام در هر گروه (مثلاً ۳ برای هزارگان) |
|
|
341
|
-
| `separatorChar` | `string` | `","` | کاراکتر جداکننده گروهها (مثلاً `,` یا `.`) |
|
|
342
|
-
| `locale` | `string` | `"fa"` | زبان برای محلیسازی ارقام (مثلاً `fa` یا `en`) |
|
|
343
|
-
| `maxDecimals` | `number` | `0` | حداکثر تعداد ارقام اعشاری مجاز |
|
|
344
|
-
| `showZero` | `boolean` | `false` | اگر `true` باشد، عدد `0` را در ورودی خالی یا صفر نمایش میدهد |
|
|
345
|
-
| `min` | `number` | - | حداقل مقدار مجاز (پشتیبانی از اعشار، مثلاً `0.5`) |
|
|
346
|
-
| `max` | `number` | - | حداکثر مقدار مجاز (پشتیبانی از اعشار، مثلاً `1000.201`) |
|
|
347
|
-
| `onValueChange` | `(value: string | undefined) => void` | - | فراخوانی در تغییر مقدار |
|
|
348
|
-
| `...rest` | `InputHTMLAttributes` | - | ویژگیهای استاندارد ورودی HTML (مثل `className`، `placeholder`، `style`) |
|
|
412
|
+
---
|
|
349
413
|
|
|
350
|
-
|
|
414
|
+
## 🏆 Comparison
|
|
351
415
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
416
|
+
| Feature | Persian Number Input | Native Input | Other Libraries |
|
|
417
|
+
| --------------------- | -------------------- | ------------ | --------------- |
|
|
418
|
+
| Auto digit conversion | ✅ | ❌ | ⚠️ Partial |
|
|
419
|
+
| Cursor preservation | ✅ | ❌ | ⚠️ Buggy |
|
|
420
|
+
| TypeScript support | ✅ | ✅ | ⚠️ Varies |
|
|
421
|
+
| Multi-locale | ✅ | ❌ | ❌ |
|
|
422
|
+
| Bundle size | 🟢 Small | 🟢 N/A | 🔴 Large |
|
|
423
|
+
| Decimal precision | ✅ | ❌ | ⚠️ Limited |
|
|
357
424
|
|
|
358
|
-
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## 🤝 Contributing
|
|
359
428
|
|
|
360
|
-
|
|
361
|
-
بله، کاملاً با React 16 تا 19 سازگار است.
|
|
429
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
362
430
|
|
|
363
|
-
|
|
364
|
-
|
|
431
|
+
1. Fork the repository
|
|
432
|
+
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
433
|
+
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
434
|
+
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
435
|
+
5. Open a Pull Request
|
|
365
436
|
|
|
366
|
-
|
|
367
|
-
از پراپهای `min` و `max` استفاده کنید که از اعشار پشتیبانی میکنند (مثلاً `min={0.5}` و `max={1000.201}`).
|
|
437
|
+
---
|
|
368
438
|
|
|
369
|
-
|
|
370
|
-
با پراپهای `className` یا `style` میتوانید ظاهر ورودی را تغییر دهید.
|
|
439
|
+
## 📄 License
|
|
371
440
|
|
|
372
|
-
|
|
373
|
-
کامپوننت ورودیها را پاکسازی میکند و فقط اعداد معتبر را پردازش میکند، ضمن رعایت محدودیتهای min/max.
|
|
441
|
+
MIT © javad Sharifi
|
|
374
442
|
|
|
375
|
-
|
|
443
|
+
---
|
|
376
444
|
|
|
377
|
-
|
|
445
|
+
## 🙏 Acknowledgments
|
|
378
446
|
|
|
379
|
-
|
|
447
|
+
- Built with TypeScript and React
|
|
448
|
+
- Uses [decimal.js](https://github.com/MikeMcl/decimal.js/) for precise decimal calculations
|
|
449
|
+
- Inspired by the needs of Persian and Arabic speaking developers
|
|
380
450
|
|
|
381
|
-
|
|
451
|
+
---
|
|
382
452
|
|
|
383
|
-
|
|
453
|
+
## 📞 Support
|
|
384
454
|
|
|
385
|
-
|
|
455
|
+
- 📧 telegram: [Javad Sharifi](https://t.me/Javad_sharifi98)
|
|
456
|
+
- 🐛 [Issue Tracker](https://github.com/javadSharifi/persian-number-input/issues)
|
|
457
|
+
- 💬 [Discussions](https://github.com/javadSharifi/persian-number-input/discussions)
|
|
386
458
|
|
|
387
|
-
|
|
459
|
+
---
|
|
388
460
|
|
|
389
|
-
|
|
461
|
+
**Made with ❤️ for the Persian and Arabic developer community**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersianNumberInput.test.d.ts","sourceRoot":"","sources":["../../src/components/PersianNumberInput.test.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PersianNumberInput.test.d.ts","sourceRoot":"","sources":["../../src/components/PersianNumberInput.test.tsx"],"names":[],"mappings":"AAGA,OAAO,2BAA2B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersianNumberInput.test.js","sourceRoot":"","sources":["../../src/components/PersianNumberInput.test.tsx"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"PersianNumberInput.test.js","sourceRoot":"","sources":["../../src/components/PersianNumberInput.test.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAmE;AACnE,mCAA8C;AAC9C,8EAAsD;AACtD,qCAAmC;AAEnC,IAAA,iBAAQ,EAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,IAAA,WAAE,EAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,IAAA,cAAM,EAAC,uBAAC,4BAAkB,KAAG,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,cAAM,CAAC,SAAS,CAAC,SAAS,CAAqB,CAAC;QAE9D,iBAAS,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACvD,IAAA,eAAM,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,IAAA,cAAM,EAAC,uBAAC,4BAAkB,IAAC,MAAM,EAAC,IAAI,GAAG,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,cAAM,CAAC,SAAS,CAAC,SAAS,CAAqB,CAAC;QAE9D,iBAAS,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QACzD,IAAA,eAAM,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,IAAA,cAAM,EAAC,uBAAC,4BAAkB,IAAC,MAAM,EAAC,gCAAO,EAAC,MAAM,EAAC,IAAI,GAAG,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,cAAM,CAAC,SAAS,CAAC,SAAS,CAAqB,CAAC;QAE9D,iBAAS,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACvD,IAAA,eAAM,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,IAAA,cAAM,EAAC,uBAAC,4BAAkB,IAAC,WAAW,EAAC,GAAG,EAAC,MAAM,EAAC,IAAI,GAAG,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,cAAM,CAAC,SAAS,CAAC,SAAS,CAAqB,CAAC;QAE9D,iBAAS,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACvD,IAAA,eAAM,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setupTests.d.ts","sourceRoot":"","sources":["../src/setupTests.ts"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setupTests.js","sourceRoot":"","sources":["../src/setupTests.ts"],"names":[],"mappings":";;AAAA,qCAAmC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "persian-number-input",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.1",
|
|
4
4
|
"description": "React component for Persian, Indic, or English localized number input with customizable digit grouping",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"vitest": "^4.0.16"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
56
57
|
"decimal.js": "^10.6.0"
|
|
57
58
|
}
|
|
58
59
|
}
|