first commit
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
/** عددِ گروهبندیشده با جداکنندهی هزارگان (مثلِ 12,500). */
|
||||
export function fmtNum(n: number | null | undefined): string {
|
||||
const v = Number(n ?? 0);
|
||||
return Number.isFinite(v) ? v.toLocaleString("en-US") : "0";
|
||||
}
|
||||
|
||||
/**
|
||||
* ورودیِ عددی با جداکنندهی هزارگان که با کیبورد هم قابلِ تایپ است.
|
||||
* برخلافِ <input type="number"> که جداکننده را نمیپذیرد، این یک ورودیِ متنی است
|
||||
* که هنگامِ تایپ زنده گروهبندی میکند و مقدارِ عددی را به onChange میدهد.
|
||||
*/
|
||||
export default function NumberInput({
|
||||
value,
|
||||
onChange,
|
||||
allowNegative = false,
|
||||
className = "inp",
|
||||
style,
|
||||
disabled,
|
||||
}: {
|
||||
value: number;
|
||||
onChange: (n: number) => void;
|
||||
allowNegative?: boolean;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
const show = (n: number) => n.toLocaleString("en-US");
|
||||
const [text, setText] = useState(show(value));
|
||||
|
||||
// اگر مقدار از بیرون عوض شد (مثلاً ریست فرم)، متن را همگام کن.
|
||||
useEffect(() => {
|
||||
const cur = parseInt(text.replace(/[^\d-]/g, "") || "0", 10) || 0;
|
||||
if (cur !== value) setText(show(value));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<input
|
||||
className={className}
|
||||
style={style}
|
||||
type="text"
|
||||
inputMode={allowNegative ? "text" : "numeric"}
|
||||
dir="ltr"
|
||||
value={text}
|
||||
disabled={disabled}
|
||||
onChange={(e) => {
|
||||
let raw = e.target.value.replace(/[^\d-]/g, "");
|
||||
if (!allowNegative) raw = raw.replace(/-/g, "");
|
||||
raw = raw.replace(/(?!^)-/g, ""); // فقط منفیِ ابتدایی
|
||||
const n = raw === "" || raw === "-" ? 0 : parseInt(raw, 10);
|
||||
const grouped =
|
||||
raw === "" ? "" : raw === "-" ? "-" : (n || 0).toLocaleString("en-US");
|
||||
setText(grouped);
|
||||
onChange(Number.isNaN(n) ? 0 : n);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user