From cbad0ebf5e1d8069df9380408e7619e328315020 Mon Sep 17 00:00:00 2001 From: Tsu-ba-me Date: Tue, 26 Jul 2022 19:06:55 -0400 Subject: [PATCH] feat(striker-ui): add InputWithRef --- striker-ui/components/InputWithRef.tsx | 86 ++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 striker-ui/components/InputWithRef.tsx diff --git a/striker-ui/components/InputWithRef.tsx b/striker-ui/components/InputWithRef.tsx new file mode 100644 index 00000000..13688f5b --- /dev/null +++ b/striker-ui/components/InputWithRef.tsx @@ -0,0 +1,86 @@ +import { ForwardedRef, forwardRef, useImperativeHandle, useState } from 'react'; + +import createInputOnChangeHandler, { + CreateInputOnChangeHandlerOptions, + MapToStateSetter, +} from '../lib/createInputOnChangeHandler'; +import OutlinedInputWithLabel, { + OutlinedInputWithLabelProps, +} from './OutlinedInputWithLabel'; + +type InputWithRefOptionalProps = { + createInputOnChangeHandlerOptions?: Omit< + CreateInputOnChangeHandlerOptions, + 'set' + >; + valueType?: TypeName | 'string'; +}; + +type InputWithRefProps = + OutlinedInputWithLabelProps & InputWithRefOptionalProps; + +type InputForwardedRefContent = { + isChangedByUser?: boolean; + setValue?: MapToStateSetter[TypeName]; + value?: MapToType[TypeName]; +}; + +const MAP_TO_INITIAL_VALUE: MapToType = { + number: 0, + string: '', +}; + +const INPUT_WITH_REF_DEFAULT_PROPS: Required< + InputWithRefOptionalProps<'string'> +> = { + createInputOnChangeHandlerOptions: {}, + valueType: 'string', +}; + +const InputWithRef = forwardRef( + ( + { + createInputOnChangeHandlerOptions: { + postSet: postSetAppend, + ...restCreateInputOnChangeHandlerOptions + } = INPUT_WITH_REF_DEFAULT_PROPS.createInputOnChangeHandlerOptions, + valueType = INPUT_WITH_REF_DEFAULT_PROPS.valueType, + ...restProps + }: InputWithRefProps, + ref: ForwardedRef>, + ) => { + const [value, setValue] = useState( + MAP_TO_INITIAL_VALUE[valueType] as MapToType[TypeName], + ) as [MapToType[TypeName], MapToStateSetter[TypeName]]; + const [isChangedByUser, setIsChangedByUser] = useState(false); + + const onChange = createInputOnChangeHandler({ + postSet: (...args) => { + setIsChangedByUser(true); + postSetAppend?.call(null, ...args); + }, + set: setValue, + setType: valueType, + ...restCreateInputOnChangeHandlerOptions, + }); + + useImperativeHandle( + ref, + () => ({ + isChangedByUser, + setValue, + value, + }), + [isChangedByUser, value], + ); + + return ; + }, +); + +InputWithRef.defaultProps = INPUT_WITH_REF_DEFAULT_PROPS; +InputWithRef.displayName = 'InputWithRef'; + +export type { InputForwardedRefContent, InputWithRefProps }; + +export default InputWithRef;