You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
5.6 KiB
198 lines
5.6 KiB
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<MUIFormControlProps>; |
|
helpMessageBoxProps?: Partial<MessageBoxProps>; |
|
id?: string; |
|
inputProps?: Partial<OutlinedInputProps>; |
|
inputLabelProps?: Partial<OutlinedInputLabelProps>; |
|
messageBoxProps?: Partial<MessageBoxProps>; |
|
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<OutlinedInputWithLabelOptionalPropsWithDefault> & |
|
OutlinedInputWithLabelOptionalPropsWithoutDefault = { |
|
baseInputProps: undefined, |
|
fillRow: false, |
|
formControlProps: {}, |
|
helpMessageBoxProps: {}, |
|
id: '', |
|
inputProps: {}, |
|
inputLabelProps: {}, |
|
messageBoxProps: {}, |
|
onHelp: undefined, |
|
onHelpAppend: undefined, |
|
required: false, |
|
type: undefined, |
|
value: '', |
|
}; |
|
|
|
const OutlinedInputWithLabel: FC<OutlinedInputWithLabelProps> = ({ |
|
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<boolean>(false); |
|
|
|
const formControlWidth = useMemo( |
|
() => (isFillRow ? '100%' : undefined), |
|
[isFillRow], |
|
); |
|
const helpElement = useMemo( |
|
() => |
|
isShowHelp && ( |
|
<InputMessageBox |
|
onClose={() => { |
|
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 ( |
|
<MUIFormControl |
|
fullWidth |
|
{...restFormControlProps} |
|
sx={{ width: formControlWidth, ...formControlSx }} |
|
> |
|
<OutlinedInputLabel |
|
htmlFor={id} |
|
isNotifyRequired={required} |
|
{...inputLabelProps} |
|
> |
|
{label} |
|
</OutlinedInputLabel> |
|
<OutlinedInput |
|
endAdornment={ |
|
<MUIInputAdornment |
|
position="end" |
|
sx={{ |
|
display: 'flex', |
|
flexDirection: 'row', |
|
|
|
[`& > .${muiIconButtonClasses.root}`]: { |
|
color: GREY, |
|
padding: '.2em', |
|
}, |
|
|
|
[`& > :not(:first-child, .${muiIconButtonClasses.root})`]: { |
|
marginLeft: '.3em', |
|
}, |
|
}} |
|
> |
|
{endAdornment} |
|
{isShowHelpButton && ( |
|
<MUIIconButton onClick={handleHelp} tabIndex={-1}> |
|
<MUIQuestionMarkIcon /> |
|
</MUIIconButton> |
|
)} |
|
</MUIInputAdornment> |
|
} |
|
fullWidth={formControlProps.fullWidth} |
|
id={id} |
|
inputProps={baseInputProps} |
|
label={label} |
|
name={name} |
|
onBlur={onBlur} |
|
onChange={onChange} |
|
onFocus={onFocus} |
|
type={type} |
|
value={value} |
|
{...restInputProps} |
|
/> |
|
{helpElement} |
|
<InputMessageBox {...messageBoxProps} /> |
|
</MUIFormControl> |
|
); |
|
}; |
|
|
|
OutlinedInputWithLabel.defaultProps = OUTLINED_INPUT_WITH_LABEL_DEFAULT_PROPS; |
|
|
|
export type { OutlinedInputWithLabelProps }; |
|
|
|
export default OutlinedInputWithLabel;
|
|
|