import React from 'react' import { TypeGuards } from '@codeleap/types' import { forwardRef } from 'react' import { InputBase, selectInputBaseProps } from '../InputBase' import { Text } from '../Text' import { MaskedTextInput } from '../../modules/textInputMask' import { TextInput as NativeTextInput } from 'react-native' import { Touchable } from '../Touchable' import { NumberIncrementProps } from './types' import { AnyRecord, AppIcon, IJSX, StyledComponentProps, StyledComponentWithProps } from '@codeleap/styles' import { MobileStyleRegistry } from '../../Registry' import { useStylesFor } from '../../hooks' import CurrencyInput from 'react-native-currency-input' import { useInputBasePartialStyles } from '../InputBase/useInputBasePartialStyles' import { MAX_VALID_DIGITS, useNumberIncrement } from './useNumberIncrement' export * from './styles' export * from './types' const defaultParseValue = (_value: string) => { const value = _value?.length > 0 ? _value : '0' const parsedValue = value?.replace(/[^\d.]/g, '') return parseFloat(parsedValue) } export const NumberIncrement = forwardRef((props, inputRef) => { const allProps = { ...NumberIncrement.defaultProps, ...props, } const { inputBaseProps, others, } = selectInputBaseProps(allProps) const { style, disabled, onChangeMask, step, editable, onPress, forceError, masking, separator, prefix, suffix, delimiter, formatter, actionPressAutoFocus, parseValue, timeoutActionFocus, mask, actionDebounce, precision, field, ...textInputProps } = others const styles = useStylesFor(NumberIncrement.styleRegistryName, style) const { validation, min, max, innerInputRef, wrapperRef, isFocused, hasValue, hasError, incrementDisabled, decrementDisabled, handleChangeInput, handleChange, handleMaskChange, handleBlur, handleFocus, inputValue, onInputValueChange, } = useNumberIncrement(allProps) const isFormatted = TypeGuards.isFunction(formatter) const hasMaskProps = [masking, mask].some(v => !!v) const hasCurrencyProps = [prefix, suffix, delimiter, separator, precision].some(v => !!v) const isCurrency = hasCurrencyProps const isMasked = hasMaskProps && !isFormatted && !isCurrency const InputElement: any = isMasked ? MaskedTextInput : isCurrency ? CurrencyInput : NativeTextInput const partialStyles = useInputBasePartialStyles( styles, [['input', false], 'placeholder', 'selection'], { disabled, error: !!hasError, focus: isFocused, typed: hasValue, } ) const maskingExtraProps = isMasked ? { type: TypeGuards.isNil(mask) ? 'money' : 'custom', onChangeText: handleMaskChange, ...masking, options: { unit: prefix, separator: separator ?? '.', suffixUnit: suffix, delimiter: delimiter ?? ',', mask: mask, ...masking?.options, }, ref: null, refInput: (inputRef) => { if (!!inputRef) { innerInputRef.current = inputRef } }, } : {} const currencyExtraProps = isCurrency ? { value: inputValue, onChangeText: null, onChangeValue: onInputValueChange, prefix: prefix, separator: separator ?? '.', suffix: suffix, delimiter: delimiter ?? ',', minValue: min, maxValue: max, precision, } : {} const onPressInnerWrapper = () => { handleFocus(null) if (editable) innerInputRef.current?.focus?.() if (onPress) onPress?.() } return ( handleChange('increment'), debounce: actionDebounce, ...inputBaseProps.rightIcon, }} leftIcon={TypeGuards.isComponentOrElement(inputBaseProps.leftIcon) ? inputBaseProps.leftIcon : { name: 'minus' as AppIcon, disabled: disabled || decrementDisabled || !editable, onPress: () => handleChange('decrement'), debounce: actionDebounce, ...inputBaseProps.leftIcon, }} disabled={disabled} focused={isFocused} innerWrapper={Touchable} innerWrapperProps={{ ...(inputBaseProps.innerWrapperProps || {}), rippleDisabled: true, onPress: onPressInnerWrapper, }} hasValue={hasValue} > {editable && !disabled ? ( ) : ( )} ) }) as StyledComponentWithProps NumberIncrement.styleRegistryName = 'NumberIncrement' NumberIncrement.elements = [...InputBase.elements, 'input', 'placeholder', 'selection'] NumberIncrement.rootElement = 'wrapper' NumberIncrement.withVariantTypes = (styles: S) => { return NumberIncrement as (props: StyledComponentProps) => IJSX } NumberIncrement.defaultProps = { step: 1, editable: true, separator: null, formatter: null, parseValue: defaultParseValue, delimiter: null, mask: null, masking: null, timeoutActionFocus: 300, actionPressAutoFocus: true, actionDebounce: null, min: 0, max: MAX_VALID_DIGITS } as Partial MobileStyleRegistry.registerComponent(NumberIncrement)