import React from 'react' import { View, TextInput, TextInputProps, TextStyle, ViewStyle, StyleSheet, AccessibilityProps, } from 'react-native' import {HITSLOP_20} from 'lib/constants' import {useTheme, atoms as a, web, tokens, android} from '#/alf' import {Text} from '#/components/Typography' import {useInteractionState} from '#/components/hooks/useInteractionState' import {Props as SVGIconProps} from '#/components/icons/common' const Context = React.createContext<{ inputRef: React.RefObject | null isInvalid: boolean hovered: boolean onHoverIn: () => void onHoverOut: () => void focused: boolean onFocus: () => void onBlur: () => void }>({ inputRef: null, isInvalid: false, hovered: false, onHoverIn: () => {}, onHoverOut: () => {}, focused: false, onFocus: () => {}, onBlur: () => {}, }) export type RootProps = React.PropsWithChildren<{isInvalid?: boolean}> export function Root({children, isInvalid = false}: RootProps) { const inputRef = React.useRef(null) const { state: hovered, onIn: onHoverIn, onOut: onHoverOut, } = useInteractionState() const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() const context = React.useMemo( () => ({ inputRef, hovered, onHoverIn, onHoverOut, focused, onFocus, onBlur, isInvalid, }), [ inputRef, hovered, onHoverIn, onHoverOut, focused, onFocus, onBlur, isInvalid, ], ) return ( inputRef.current?.focus(), onMouseOver: onHoverIn, onMouseOut: onHoverOut, })}> {children} ) } export function useSharedInputStyles() { const t = useTheme() return React.useMemo(() => { const hover: ViewStyle[] = [ { borderColor: t.palette.contrast_100, }, ] const focus: ViewStyle[] = [ { backgroundColor: t.palette.contrast_50, borderColor: t.palette.primary_500, }, ] const error: ViewStyle[] = [ { backgroundColor: t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900, borderColor: t.name === 'light' ? t.palette.negative_300 : t.palette.negative_800, }, ] const errorHover: ViewStyle[] = [ { backgroundColor: t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900, borderColor: tokens.color.red_500, }, ] return { chromeHover: StyleSheet.flatten(hover), chromeFocus: StyleSheet.flatten(focus), chromeError: StyleSheet.flatten(error), chromeErrorHover: StyleSheet.flatten(errorHover), } }, [t]) } export type InputProps = Omit & { label: string value: string onChangeText: (value: string) => void isInvalid?: boolean } export function createInput(Component: typeof TextInput) { return function Input({ label, placeholder, value, onChangeText, isInvalid, ...rest }: InputProps) { const t = useTheme() const ctx = React.useContext(Context) const withinRoot = Boolean(ctx.inputRef) const {chromeHover, chromeFocus, chromeError, chromeErrorHover} = useSharedInputStyles() if (!withinRoot) { return ( ) } return ( <> ) } } export const Input = createInput(TextInput) export function Label({ nativeID, children, }: React.PropsWithChildren<{nativeID?: string}>) { const t = useTheme() return ( {children} ) } export function Icon({icon: Comp}: {icon: React.ComponentType}) { const t = useTheme() const ctx = React.useContext(Context) const {hover, focus, errorHover, errorFocus} = React.useMemo(() => { const hover: TextStyle[] = [ { color: t.palette.contrast_800, }, ] const focus: TextStyle[] = [ { color: t.palette.primary_500, }, ] const errorHover: TextStyle[] = [ { color: t.palette.negative_500, }, ] const errorFocus: TextStyle[] = [ { color: t.palette.negative_500, }, ] return { hover, focus, errorHover, errorFocus, } }, [t]) return ( ) } export function Suffix({ children, label, accessibilityHint, }: React.PropsWithChildren<{ label: string accessibilityHint?: AccessibilityProps['accessibilityHint'] }>) { const t = useTheme() const ctx = React.useContext(Context) return ( {children} ) }