Initial commit MKD fixes
This commit is contained in:
78
components/building/EditableField.tsx
Executable file
78
components/building/EditableField.tsx
Executable file
@@ -0,0 +1,78 @@
|
||||
|
||||
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()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user