Files
mkd/components/building/EditableField.tsx

79 lines
2.8 KiB
TypeScript
Raw Permalink Normal View History

2026-02-04 00:17:04 +05:00
import React, { useState, useEffect, useRef } from 'react';
import { CheckCircle2, X } from 'lucide-react';
interface EditableFieldProps {
value: string | number | boolean;
onChange: (val: string) => void;
isEditing: boolean;
className?: string;
placeholder?: string;
type?: 'text' | 'number' | 'date' | 'checkbox';
}
export const EditableField: React.FC<EditableFieldProps> = ({ value, onChange, isEditing, className = "", placeholder, type = 'text' }) => {
const [localValue, setLocalValue] = useState(value);
const inputRef = useRef<HTMLInputElement>(null);
const wasFocused = useRef(false);
// Синхронизируем локальное значение с внешним
useEffect(() => {
setLocalValue(value);
}, [value]);
// Восстанавливаем фокус после обновления (setSelectionRange не поддерживается для type="number" и "date")
useEffect(() => {
if (wasFocused.current && inputRef.current && isEditing) {
const input = inputRef.current;
input.focus();
const inputType = (input.type || 'text').toLowerCase();
if (inputType === 'text' || inputType === 'search' || inputType === 'url' || inputType === 'tel' || inputType === 'password') {
const cursorPosition = input.selectionStart ?? 0;
input.setSelectionRange(cursorPosition, cursorPosition);
}
wasFocused.current = false;
}
});
if (type === 'checkbox') {
const boolValue = Boolean(value);
if (!isEditing) return boolValue ? <CheckCircle2 className="w-4 h-4 text-emerald-500" /> : <X className="w-4 h-4 text-slate-300" />;
return (
<input
type="checkbox"
checked={boolValue}
onChange={(e) => onChange(String(e.target.checked))}
className="w-5 h-5 accent-primary-600 cursor-pointer"
/>
);
}
if (!isEditing) {
return <span className={`truncate ${className}`}>{value}</span>;
}
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.value;
setLocalValue(newValue);
wasFocused.current = true;
onChange(newValue);
};
const handleFocus = () => {
wasFocused.current = true;
};
return (
<input
ref={inputRef}
type={type}
value={localValue as string | number}
onChange={handleChange}
onFocus={handleFocus}
className={`w-full bg-primary-50 border-b-2 border-primary-200 focus:border-primary-500 outline-none px-1 rounded-t transition-colors ${className}`}
placeholder={placeholder}
onClick={(e) => e.stopPropagation()}
/>
);
};