import React, { forwardRef, ChangeEvent, FocusEvent, KeyboardEvent, useState, useMemo, } from 'react'; import { v4 as uuid } from 'uuid'; // eslint-disable-next-line mui-path-imports/mui-path-imports import { Autocomplete, Chip, TextField } from '@mui/material'; import { NumericFormat, NumericFormatProps } from 'react-number-format'; import type { MRT_Cell, MRT_TableInstance } from '..'; import { invertColor } from '../column.utils'; import Virtualize from './MRT_EditCellSelectField'; import type { TextFieldProps } from '@mui/material/TextField'; interface Props = {}> { cell: MRT_Cell; table: MRT_TableInstance; showLabel?: boolean; } interface CustomProps { onChange: (event: { target: { name: string; value: string } }) => void; inputRef: any; name: string; } export const MRT_EditCellTextField = = {}>({ cell, showLabel, table, }: Props) => { const { getState, options: { muiTableBodyCellEditTextFieldProps }, refs: { editInputRefs }, setEditingRow, } = table; const { column, row } = cell; const { columnDef } = column; const { editingRow } = getState(); const [value, setValue] = useState(() => { if (columnDef.accessorObjectFn) { // when it is a select edit, we need to get the value from the accessorObjectFn const accessorObject = columnDef.accessorObjectFn(cell.row.original); if (Array.isArray(accessorObject)) { return accessorObject; } return columnDef.accessorObjectFn(cell.row.original); } return cell.getValue(); }); const mTableBodyCellEditTextFieldProps = muiTableBodyCellEditTextFieldProps instanceof Function ? muiTableBodyCellEditTextFieldProps({ cell, column, row, table }) : muiTableBodyCellEditTextFieldProps; const mcTableBodyCellEditTextFieldProps = columnDef.muiTableBodyCellEditTextFieldProps instanceof Function ? columnDef.muiTableBodyCellEditTextFieldProps({ cell, column, row, table, }) : columnDef.muiTableBodyCellEditTextFieldProps; const textFieldProps: TextFieldProps = { ...mTableBodyCellEditTextFieldProps, ...mcTableBodyCellEditTextFieldProps, }; const isSelectEdit = columnDef.editVariant === 'select'; const isTagEdit = columnDef.editVariant === 'tag'; const isCurrencyEdit = columnDef.editVariant === 'currency'; const isPercentEdit = columnDef.editVariant === 'percent'; const saveRow = (newValue: string) => { if (editingRow) { setEditingRow({ ...editingRow, _valuesCache: { ...editingRow._valuesCache, [column.id]: newValue }, }); } }; const handleChange = (event: ChangeEvent | any) => { if (isTagEdit) { textFieldProps.onChange?.(event); setValue(event); // add conditional to make changes when the inpout is out of focus (instead of select the option, because it's a multiple select) saveRow(event); } else if (isSelectEdit) { textFieldProps.onChange?.(event); setValue(event.target.value); if (textFieldProps?.select) { saveRow(event.target.value?.value ?? event.target.value); } } else if (isCurrencyEdit) { textFieldProps.onChange?.(event); setValue(event.target.value); if (textFieldProps?.select) { saveRow(event.target.value); } } else { textFieldProps.onChange?.(event); setValue(event.target.value); if (textFieldProps?.select) { saveRow(event.target.value); } } }; const handleBlur = (event: FocusEvent) => { if (isTagEdit) { textFieldProps.onBlur?.(value); } else if (isSelectEdit) { textFieldProps.onBlur?.({ ...event, target: { ...event.target, value: value?.value, }, }); } else if (isCurrencyEdit) { textFieldProps.onBlur?.({ ...event, target: { ...event.target, value, }, }); } else { textFieldProps.onBlur?.(event); } saveRow(value); }; const handleEnterKeyDown = (event: KeyboardEvent) => { textFieldProps.onKeyDown?.(event); }; if (columnDef.Edit) { return <>{columnDef.Edit?.({ cell, column, row, table })}; } if (isTagEdit) { const options: any = []; if (columnDef.editSelectOptionsFn instanceof Function) { options.push(...columnDef.editSelectOptionsFn(cell.row.original)); } else if (columnDef.editSelectOptions instanceof Array) { options.push(...columnDef.editSelectOptions); } return ( option?.name} renderInput={(params) => ( { if (inputRef) { editInputRefs.current[column.id] = inputRef; if (textFieldProps.inputRef) { textFieldProps.inputRef = inputRef; } } }} /> )} onBlur={handleBlur} onChange={(_event, value) => handleChange(value)} onKeyDown={handleEnterKeyDown} autoHighlight isOptionEqualToValue={(option, value) => option?.id === value?.id} renderTags={(value, getTagProps) => { return value.map((option, index) => ( )); }} sx={{ minWidth: '180px', width: '100%' }} /> ); } if (isSelectEdit) { // prettier-ignore const options: (string | {text: string; value: string | number; label?: string; sub_label?: string; sub_label_variant?: string })[] = []; if (columnDef.editSelectOptionsFn instanceof Function) { options.push(...columnDef.editSelectOptionsFn(cell.row.original)); } else if (columnDef.editSelectOptions instanceof Array) { options.push(...columnDef.editSelectOptions); } return ( { if (typeof option === 'object') { return option.label ?? option.text ?? option.value?.toString() ?? ''; } return option; }} {...textFieldProps} onInputRef={(inputRef: any) => { if (inputRef) { editInputRefs.current[column.id] = inputRef; if (textFieldProps.inputRef) { textFieldProps.inputRef = inputRef; } } }} onBlur={handleBlur} onChange={(event: ChangeEvent | any, value: any) => { handleChange({ ...event, ...(event?.target && { target: { ...event.target, value, }, }), }); }} onKeyDown={handleEnterKeyDown} /> ); } if (isCurrencyEdit) { const NumericFormatCustom = forwardRef( (props, ref) => { const { onChange, inputRef, ...other } = props; return ( { onChange({ target: { name: props.name, value: values.value, }, }); }} thousandSeparator valueIsNumericString prefix="$ " /> ); }, ); const textFieldId = useMemo(() => uuid(), []); const endAdornment = useMemo(() => { return columnDef.getEndAdornment?.(cell.row.original); }, [columnDef.getEndAdornment]); return ( <> { if (inputRef) { editInputRefs.current[column.id] = inputRef; if (textFieldProps.inputRef) { textFieldProps.inputRef = inputRef; } } }} InputProps={{ inputComponent: NumericFormatCustom as any, endAdornment, }} type={isPercentEdit ? 'number' : 'text'} inputProps={{ ...(isPercentEdit && { step: 0.001 }), sx: { padding: '3px 0px', fontSize: 14 }, }} label={showLabel ? column.columnDef.header : undefined} margin="none" name={column.id} placeholder={columnDef.header} select={isSelectEdit} variant="standard" {...textFieldProps} onClick={(e) => { e.stopPropagation(); textFieldProps?.onClick?.(e); }} onBlur={handleBlur} onChange={handleChange} onKeyDown={handleEnterKeyDown} > {textFieldProps.children} ); } return ( { if (inputRef) { editInputRefs.current[column.id] = inputRef; if (textFieldProps.inputRef) { textFieldProps.inputRef = inputRef; } } }} type={isPercentEdit ? 'number' : 'text'} inputProps={{ ...(isPercentEdit && { step: 0.001 }), sx: { padding: '3px 0px', fontSize: 14 }, }} label={showLabel ? column.columnDef.header : undefined} margin="none" name={column.id} placeholder={columnDef.header} select={isSelectEdit} value={value} variant="standard" {...textFieldProps} onClick={(e) => { e.stopPropagation(); textFieldProps?.onClick?.(e); }} onBlur={handleBlur} onChange={handleChange} onKeyDown={handleEnterKeyDown} > {textFieldProps.children} ); };