import { TextInputProps as RNTextInputProps, TextInput as RNTextInput, StyleSheet } from "react-native"; import React, { SetStateAction, Dispatch, useContext, createContext, PropsWithChildren, useState, forwardRef, } from "react"; import { Box, BoxProps } from "design-system/primitives/Box/Box"; import { Row, RowProps } from "design-system/primitives/Row"; import { useInternalTheme } from "design-system/hooks/useInternalTheme"; import { ColorThemeKeys } from "design-system/theme/types"; import { Text } from "./Text"; import { Stack } from "design-system/primitives/Stack"; interface Props { error?: string; disabled?: boolean; height?: number; } type InputProps = Props & { inputState: "default" | "focussed" | "valid"; setInputState: Dispatch>; }; const InputContext = createContext({ disabled: false, error: undefined, inputState: "default", height: 64, setInputState: () => undefined, }); function useInputContext() { const context = useContext(InputContext); if (!context) { throw new Error("Input compound components cannot be rendered outside the Input component"); } return context; } export function TextInput(props: PropsWithChildren) { const [inputState, setInputState] = useState("default"); const { children, disabled, error, height = 64 } = props; return ( {children} {error} ); } function Container(props: PropsWithChildren) { const { children, space, ...rest } = props; const { height } = useInputContext(); const { error, inputState } = useInputContext(); let borderColor = "white" as ColorThemeKeys; if (inputState === "focussed") { borderColor = "input-focussed"; } if (error) { borderColor = "error"; } return ( {children} ); } type Input = Omit; interface TextInputProps extends RNTextInputProps { marginCorrection?: number; } const Input = forwardRef( ({ style, onFocus, onBlur, placeholder, ...props }, ref) => { const theme = useInternalTheme(); const { disabled, setInputState } = useInputContext(); const styles = StyleSheet.flatten(style); const { inputState } = useInputContext(); return ( {inputState === "focussed" && ( // height 100% overflows the label outside the container, transform will ensure its visible // absolute position not used so the text input contents push down when the inputState is focussed {placeholder} )} { onFocus?.(e); setInputState("focussed"); }} onBlur={(e) => { onBlur?.(e); setInputState("default"); }} underlineColorAndroid="transparent" textAlignVertical="center" style={[ { color: theme.colors.white, textAlign: "left", paddingHorizontal: 0, paddingVertical: 0, fontFamily: theme.config.typography.fontConfig.Lato.medium.normal, fontSize: theme.config.typography.sizes["17px"].fontSize, // required so touch to focus spans the hieght of the input container and not just height of the text height: "100%", }, styles, ]} placeholder={inputState === "focussed" ? "" : placeholder} {...props} /> ); } ); TextInput.Container = Container; TextInput.Input = Input;