import { QuestionMark as MUIQuestionMarkIcon } from '@mui/icons-material'; import { FormControl as MUIFormControl, FormControlProps as MUIFormControlProps, IconButton as MUIIconButton, IconButtonProps as MUIIconButtonProps, iconButtonClasses as muiIconButtonClasses, InputAdornment as MUIInputAdornment, InputBaseComponentProps as MUIInputBaseComponentProps, } from '@mui/material'; import { FC, useCallback, useMemo, useState } from 'react'; import { GREY } from '../lib/consts/DEFAULT_THEME'; import InputMessageBox from './InputMessageBox'; import { MessageBoxProps } from './MessageBox'; import OutlinedInput, { OutlinedInputProps } from './OutlinedInput'; import OutlinedInputLabel, { OutlinedInputLabelProps, } from './OutlinedInputLabel'; type OutlinedInputWithLabelOptionalPropsWithDefault = { fillRow?: boolean; formControlProps?: Partial; helpMessageBoxProps?: Partial; id?: string; inputProps?: Partial; inputLabelProps?: Partial; messageBoxProps?: Partial; required?: boolean; value?: OutlinedInputProps['value']; }; type OutlinedInputWithLabelOptionalPropsWithoutDefault = { baseInputProps?: MUIInputBaseComponentProps; onHelp?: MUIIconButtonProps['onClick']; onHelpAppend?: MUIIconButtonProps['onClick']; type?: string; }; type OutlinedInputWithLabelOptionalProps = OutlinedInputWithLabelOptionalPropsWithDefault & OutlinedInputWithLabelOptionalPropsWithoutDefault; type OutlinedInputWithLabelProps = Pick< OutlinedInputProps, 'name' | 'onBlur' | 'onChange' | 'onFocus' > & OutlinedInputWithLabelOptionalProps & { label: string; }; const OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS: Required & OutlinedInputWithLabelOptionalPropsWithoutDefault = { baseInputProps: undefined, fillRow: false, formControlProps: {}, helpMessageBoxProps: {}, id: '', inputProps: {}, inputLabelProps: {}, messageBoxProps: {}, onHelp: undefined, onHelpAppend: undefined, required: false, type: undefined, value: '', }; const OutlinedInputWithLabel: FC = ({ baseInputProps, fillRow: isFillRow = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS.fillRow, formControlProps = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS.formControlProps, helpMessageBoxProps = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS.helpMessageBoxProps, id = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS.id, inputProps: { endAdornment, ...restInputProps } = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS.inputProps, inputLabelProps = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS.inputLabelProps, label, messageBoxProps = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS.messageBoxProps, name, onBlur, onChange, onFocus, onHelp, onHelpAppend, required = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS.required, type, value = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS.value, }) => { const { sx: formControlSx, ...restFormControlProps } = formControlProps; const { text: helpText = '' } = helpMessageBoxProps; const [isShowHelp, setIsShowHelp] = useState(false); const formControlWidth = useMemo( () => (isFillRow ? '100%' : undefined), [isFillRow], ); const helpElement = useMemo( () => isShowHelp && ( { setIsShowHelp(false); }} {...helpMessageBoxProps} /> ), [helpMessageBoxProps, isShowHelp], ); const isShowHelpButton: boolean = useMemo( () => onHelp !== undefined || helpText.length > 0, [helpText, onHelp], ); const createHelpHandler = useCallback< () => MUIIconButtonProps['onClick'] >(() => { let handler: MUIIconButtonProps['onClick']; if (onHelp) { handler = onHelp; } else if (helpText.length > 0) { handler = (...args) => { setIsShowHelp((previous) => !previous); onHelpAppend?.call(null, ...args); }; } return handler; }, [helpText, onHelp, onHelpAppend]); const handleHelp = useMemo(createHelpHandler, [createHelpHandler]); return ( {label} .${muiIconButtonClasses.root}`]: { color: GREY, padding: '.2em', }, [`& > :not(:first-child, .${muiIconButtonClasses.root})`]: { marginLeft: '.3em', }, }} > {endAdornment} {isShowHelpButton && ( )} } fullWidth={formControlProps.fullWidth} id={id} inputProps={baseInputProps} label={label} name={name} onBlur={onBlur} onChange={onChange} onFocus={onFocus} type={type} value={value} {...restInputProps} /> {helpElement} ); }; OutlinedInputWithLabel.defaultProps = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS; export type { OutlinedInputWithLabelProps }; export default OutlinedInputWithLabel;