import { FormControl, MenuItem, Select } from '@mui/material'; import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useRealtimeActions, useVspOptions } from '../../contexts/RealtimeContext'; const EDITOR_STYLES = { position: 'absolute', zIndex: 12, top: 0, }; const VspDropdownEditCell = memo(({ refCell, onChange, disabled, value, table, cell }) => { const { endEditing: contextEndEditing } = useRealtimeActions(); const vspOptions = useVspOptions(); const [selectedValue, setSelectedValue] = useState(() => value ?? ''); const [position, setPosition] = useState(); const [open, setOpen] = useState(false); const refFinished = useRef(false); // AURORA-1891: см. тот же приём в EditCell.jsx — фокус после закрытия // редактора возвращается в , чтобы клавиатурная навигация не отваливалась. const tdRef = useRef(null); useEffect(() => { const timer = setTimeout(() => { setOpen(true); }, 80); return () => clearTimeout(timer); }, []); useLayoutEffect(() => { if (!refCell?.current) return; const td = refCell.current.offsetParent; const tr = td?.offsetParent; if (td && tr) { tdRef.current = td; setPosition({ left: td.offsetLeft, width: td.offsetWidth, translateY: tr.style.transform || '', }); } }, [refCell]); useEffect(() => { return () => { tdRef.current?.focus?.(); }; }, []); const finishEditing = useCallback(() => { if (refFinished.current) return; refFinished.current = true; table.setEditingCell(null); const editingCell = table.getState().editingCell; if (editingCell) { contextEndEditing?.(editingCell.row, editingCell.column); } }, [table, contextEndEditing]); // AURORA-1891: та же клавиатурная логика, что в EditCell.jsx — Esc уже // работает через onClose MUI Select (reason !== 'selectOption' вызывает // finishEditing без onChange, т.е. без cell_updated — отмена). Здесь // добираем Tab/Shift+Tab и Enter: сохранить (для dropdown «сохранить» — // это просто закрыть без выбора, onChange уже случился в handleSelectChange, // если пользователь кликнул опцию) и перейти к следующей редактируемой ячейке. const handleKeyDown = useCallback( (event) => { if (refFinished.current) return; if (event.key === 'Tab') { event.preventDefault(); table.options.meta?.openNextEditableCell?.(cell.row, cell.column, event.shiftKey ? 'left' : 'right'); finishEditing(); return; } if (event.key === 'Enter') { event.preventDefault(); table.options.meta?.openNextEditableCell?.(cell.row, cell.column, 'down'); finishEditing(); } }, [cell, finishEditing, table], ); const handleSelectChange = useCallback( (e) => { const val = e.target.value; if (val == null || val === '') return; refFinished.current = true; setSelectedValue(val); onChange?.(val); const editingCell = table.getState().editingCell; if (editingCell) { contextEndEditing?.(editingCell.row, editingCell.column); } }, [onChange, table, contextEndEditing], ); const handleSelectClose = useCallback( (_event, reason) => { if (reason === 'selectOption') return; finishEditing(); }, [finishEditing], ); const editorStyles = useMemo( () => ({ ...EDITOR_STYLES, left: position?.left || 0, width: position?.width || 0, transform: position?.translateY || 0, }), [position], ); return ( {position && (
)} ); }); VspDropdownEditCell.displayName = 'VspDropdownEditCell'; export default VspDropdownEditCell;