/** * Copyright (c) Paymium. * * This source code is licensed under the MIT license found in the * LICENSE file in the root of this projects source tree. */ import { TextInput, type TextInputProps } from 'react-native'; import { cloneElement, forwardRef, isValidElement, useCallback, useState, type ReactNode, } from 'react'; import { form } from '../styles/form'; import { gapStyles } from '../styles/gap'; import { useInteraction, createStyles, composeStyles, CrossedMethods, inlineStyle, useTheme, } from '@crossed/styled'; import { FormControl, FormField, FormLabel } from './Form'; import { CloseButton } from '../buttons/CloseButton'; import { useUncontrolled } from '@crossed/core'; import { XBox } from '../layout/XBox'; import { Text } from '../typography/Text'; import { YBox } from '../layout/YBox'; const styles = createStyles(() => ({ close: { base: { paddingLeft: 0, paddingRight: 0, paddingTop: 0, paddingBottom: 0 }, }, })); export type InputProps = Omit< TextInputProps, 'editable' | 'onChange' | 'style' > & { /** * Label of input */ label?: string; /** * Render clearable button if value is filled */ clearable?: boolean; elementLeft?: ReactNode; elementRight?: ReactNode; /** * Error to render */ error?: string; /** * Description of input */ description?: string; /** * Extra of label */ extra?: string; /** * Disabled state */ disabled?: boolean; /** * style to extends */ style?: CrossedMethods; /** * formField style to extends */ formFieldStyle?: CrossedMethods; }; export const Input = forwardRef((allProps, ref) => { const { error, label, clearable, defaultValue, value: valueProps, onChangeText, disabled, elementRight, elementLeft, description, extra, formFieldStyle, ...props } = allProps; const [value, setValue] = useUncontrolled({ value: valueProps, defaultValue, onChange: onChangeText, }); const [elementLeftWidth, setElementLeftWidth] = useState(0); const [elementRightWidth, setElementRightWidth] = useState(0); const { state, props: propsInteraction } = useInteraction(allProps); const { colors } = useTheme(); const color = colors.text.secondary; const onClear = useCallback(() => { setValue(''); }, [setValue]); const showClear = !!(clearable && value); return ( ({ base: { flexGrow: 1 } })), formFieldStyle ).rnw()} > {!!(label || description || extra) && ( {!!label && {label}} {!!description && ( {description} )} {!!extra && ( {extra} )} )} {elementLeft && ( setElementLeftWidth(layout.width) } > {isValidElement(elementLeft) && typeof elementLeft.type !== 'string' && (elementLeft.type as any).displayName === 'CrossedText' ? cloneElement(elementLeft, { style: [(elementLeft as any).style, { color }], } as any) : elementLeft} )} {(!!elementRight || !!showClear) && ( setElementRightWidth(layout.width) } > {isValidElement(elementRight) && typeof elementRight.type !== 'string' && (elementRight.type as any).displayName === 'CrossedText' ? cloneElement(elementRight, { style: [(elementRight as any).style, { color }], } as any) : elementRight} {!!showClear && ( )} )} {error && {error.toString()}} ); }); Input.displayName = 'Input';