import { type ChangeEvent, type FocusEvent, type KeyboardEvent, useState, } from 'react'; import MenuItem from '@mui/material/MenuItem'; import TextField from '@mui/material/TextField'; import { type TextFieldProps } from '@mui/material/TextField'; import { type MRT_Cell, type MRT_RowData, type MRT_TableInstance, } from '../../types'; import { getValueAndLabel, parseFromValuesOrFunc } from '../../utils/utils'; export interface MRT_EditCellTextFieldProps extends TextFieldProps<'standard'> { cell: MRT_Cell; table: MRT_TableInstance; } export const MRT_EditCellTextField = ({ cell, table, ...rest }: MRT_EditCellTextFieldProps) => { const { getState, options: { createDisplayMode, editDisplayMode, muiEditTextFieldProps }, refs: { editInputRefs }, setCreatingRow, setEditingCell, setEditingRow, } = table; const { column, row } = cell; const { columnDef } = column; const { creatingRow, editingRow } = getState(); const { editSelectOptions, editVariant } = columnDef; const isCreating = creatingRow?.id === row.id; const isEditing = editingRow?.id === row.id; const [value, setValue] = useState(() => cell.getValue()); const [completesComposition, setCompletesComposition] = useState(true); const textFieldProps: TextFieldProps = { ...parseFromValuesOrFunc(muiEditTextFieldProps, { cell, column, row, table, }), ...parseFromValuesOrFunc(columnDef.muiEditTextFieldProps, { cell, column, row, table, }), ...rest, }; const selectOptions = parseFromValuesOrFunc(editSelectOptions, { cell, column, row, table, }); const isSelectEdit = editVariant === 'select' || textFieldProps?.select; const saveInputValueToRowCache = (newValue: string) => { //@ts-expect-error row._valuesCache[column.id] = newValue; if (isCreating) { setCreatingRow(row); } else if (isEditing) { setEditingRow(row); } }; const handleChange = (event: ChangeEvent) => { textFieldProps.onChange?.(event); setValue(event.target.value); if (isSelectEdit) { saveInputValueToRowCache(event.target.value); } }; const handleBlur = (event: FocusEvent) => { textFieldProps.onBlur?.(event); saveInputValueToRowCache(value); setEditingCell(null); }; const handleEnterKeyDown = (event: KeyboardEvent) => { textFieldProps.onKeyDown?.(event); if (event.key === 'Enter' && !event.shiftKey && completesComposition) { editInputRefs.current?.[column.id]?.blur(); } }; if (columnDef.Edit) { return <>{columnDef.Edit?.({ cell, column, row, table })}; } return ( { if (inputRef) { editInputRefs.current![column.id] = isSelectEdit ? inputRef.node : inputRef; if (textFieldProps.inputRef) { textFieldProps.inputRef = inputRef; } } }} label={ ['custom', 'modal'].includes( (isCreating ? createDisplayMode : editDisplayMode) as string, ) ? columnDef.header : undefined } margin="none" name={column.id} placeholder={ !['custom', 'modal'].includes( (isCreating ? createDisplayMode : editDisplayMode) as string, ) ? columnDef.header : undefined } select={isSelectEdit} size="small" value={value ?? ''} variant="standard" {...textFieldProps} InputProps={{ ...(textFieldProps.variant !== 'outlined' ? { disableUnderline: editDisplayMode === 'table' } : {}), ...textFieldProps.InputProps, sx: (theme) => ({ mb: 0, ...(parseFromValuesOrFunc( textFieldProps?.InputProps?.sx, theme, ) as any), }), }} SelectProps={{ MenuProps: { disableScrollLock: true }, ...textFieldProps.SelectProps, }} inputProps={{ autoComplete: 'off', ...textFieldProps.inputProps, }} onBlur={handleBlur} onChange={handleChange} onClick={(e) => { e.stopPropagation(); textFieldProps?.onClick?.(e); }} onKeyDown={handleEnterKeyDown} onCompositionStart={() => setCompletesComposition(false)} onCompositionEnd={() => setCompletesComposition(true)} > {textFieldProps.children ?? selectOptions?.map((option) => { const { label, value } = getValueAndLabel(option); return ( {label} ); })} ); };