julong-lib/components/ui/MaskedInput.tsx

94 lines
2.7 KiB
TypeScript

import React, { useRef, useState } from "react";
interface MaskedInputProps {
value: string;
onChange: (value: any) => void;
disabled?: boolean;
className?: string;
}
const MaskedInput: React.FC<MaskedInputProps> = ({
value,
onChange,
disabled = false,
className,
}) => {
const inputRef = useRef<HTMLInputElement>(null); // Referensi ke elemen input
const [localValue, setLocalValue] = useState<string>(value); // State lokal untuk kontrol input
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (disabled) return;
let input = e.target.value;
// Hapus semua karakter non-digit
input = input.replace(/\D/g, "");
// Format ke dalam bentuk HH:mm dengan padding underscore
if (input.length === 1) {
input = input + "_:__"; // Jika 1 angka
} else if (input.length === 2) {
input = input + ":__"; // Jika 2 angka
} else if (input.length > 2) {
input = input.substring(0, 2) + ":" + input.substring(2, 4);
if (input.length < 5) {
input = input.padEnd(5, "_"); // Tambahkan underscore untuk padding
}
}
// Batasi panjang maksimum
if (input.length > 5) {
input = input.substring(0, 5);
}
// Validasi batas maksimal jam
if (input.length === 5 && !input.includes("_")) {
const [hours, minutes] = input.split(":").map(Number);
// Koreksi jika jam atau menit melebihi batas
const correctedHours = Math.min(hours, 23);
const correctedMinutes = Math.min(minutes, 59);
input = `${String(correctedHours).padStart(2, "0")}:${String(
correctedMinutes
).padStart(2, "0")}`;
}
// Update state lokal
setLocalValue(input);
// Panggil `onChange` jika input lengkap (tanpa underscore) atau jika input kosong
if (input.length === 5 && !input.includes("_")) {
onChange(input); // Input lengkap
} else if (input === "__:__" || input === "") {
onChange(null); // Input kosong
}
// Atur posisi kursor
if (inputRef.current) {
const caretPosition = Math.max(
input.indexOf("_") !== -1 ? input.indexOf("_") : input.length,
0
);
let caret = caretPosition === 3 ? 2 : caretPosition;
setTimeout(() => {
inputRef.current?.setSelectionRange(caret, caret);
}, 0);
}
};
return (
<input
ref={inputRef}
id="time"
type="text"
value={localValue}
disabled={disabled}
onChange={handleInputChange}
placeholder={disabled ? "" : "__:__"}
className={cx(
"w-full px-4 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring focus:ring-blue-300 focus:border-blue-500",
className
)}
/>
);
};
export default MaskedInput;