Dialog text input

This commit is contained in:
Eric Bailey
2024-01-15 16:42:00 -06:00
parent 48abb5ac37
commit 4d3128aa12
4 changed files with 225 additions and 204 deletions
+4
View File
@@ -3,12 +3,14 @@ import {View, Dimensions} from 'react-native'
import BottomSheet, { import BottomSheet, {
BottomSheetBackdrop, BottomSheetBackdrop,
BottomSheetScrollView, BottomSheetScrollView,
BottomSheetTextInput,
BottomSheetView, BottomSheetView,
} from '@gorhom/bottom-sheet' } from '@gorhom/bottom-sheet'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {useTheme, atoms as a} from '#/alf' import {useTheme, atoms as a} from '#/alf'
import {Portal} from '#/components/Portal' import {Portal} from '#/components/Portal'
import {createTextInput} from '#/components/forms/InputText'
import { import {
DialogOuterProps, DialogOuterProps,
@@ -19,6 +21,8 @@ import {Context} from '#/components/Dialog/context'
export {useDialogControl, useDialogContext} from '#/components/Dialog/context' export {useDialogControl, useDialogContext} from '#/components/Dialog/context'
export * from '#/components/Dialog/types' export * from '#/components/Dialog/types'
// @ts-ignore
export const InputText = createTextInput(BottomSheetTextInput)
export function Outer({ export function Outer({
children, children,
+1
View File
@@ -13,6 +13,7 @@ import {Context, useDialogContext} from '#/components/Dialog/context'
export {useDialogControl, useDialogContext} from '#/components/Dialog/context' export {useDialogControl, useDialogContext} from '#/components/Dialog/context'
export * from '#/components/Dialog/types' export * from '#/components/Dialog/types'
export {InputText} from '#/components/forms/InputText'
const stopPropagation = (e: any) => e.stopPropagation() const stopPropagation = (e: any) => e.stopPropagation()
+212 -204
View File
@@ -20,221 +20,229 @@ type Props = BaseProps &
suffix?: React.FunctionComponent<any> suffix?: React.FunctionComponent<any>
} }
export function InputText({ export function createTextInput(Input: typeof TextInput) {
value: initialValue, return function InputText({
onChange, value: initialValue,
testID, onChange,
accessibilityLabel, testID,
accessibilityHint, accessibilityLabel,
label, accessibilityHint,
hasError, label,
icon: Icon, hasError,
suffix: Suffix, icon: Icon,
...props suffix: Suffix,
}: Props) { ...props
const labelId = React.useId() }: Props) {
const t = useTheme() const labelId = React.useId()
const [value, setValue] = React.useState<string>(initialValue) const t = useTheme()
const [suffixPadding, setSuffixPadding] = React.useState(0) const [value, setValue] = React.useState<string>(initialValue)
const { const [suffixPadding, setSuffixPadding] = React.useState(0)
state: hovered, const {
onIn: onHoverIn, state: hovered,
onOut: onHoverOut, onIn: onHoverIn,
} = useInteractionState() onOut: onHoverOut,
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() } = useInteractionState()
const hasIcon = !!Icon const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
const hasIcon = !!Icon
const handleSuffixLayout = React.useCallback( const handleSuffixLayout = React.useCallback(
(e: LayoutChangeEvent) => { (e: LayoutChangeEvent) => {
setSuffixPadding(e.nativeEvent.layout.width + 16) setSuffixPadding(e.nativeEvent.layout.width + 16)
}, },
[setSuffixPadding], [setSuffixPadding],
) )
const {inputBaseStyles, inputHoverStyles, inputFocusStyles} = const {inputBaseStyles, inputHoverStyles, inputFocusStyles} =
React.useMemo(() => { React.useMemo(() => {
const base: TextStyle[] = [] const base: TextStyle[] = []
const hover: TextStyle[] = [ const hover: TextStyle[] = [
{ {
borderColor: t.palette.contrast_300, borderColor: t.palette.contrast_300,
}, },
] ]
const focus: TextStyle[] = [ const focus: TextStyle[] = [
{ {
backgroundColor: t.palette.contrast_50, backgroundColor: t.palette.contrast_50,
borderColor: t.palette.primary_500, borderColor: t.palette.primary_500,
}, },
] ]
if (hasIcon) { if (hasIcon) {
base.push({ base.push({
paddingLeft: 40, paddingLeft: 40,
}) })
} }
if (hasError) { if (hasError) {
base.push({ base.push({
backgroundColor: backgroundColor:
t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900, t.name === 'light'
borderColor: ? t.palette.negative_25
t.name === 'light' : t.palette.negative_900,
? t.palette.negative_300 borderColor:
: t.palette.negative_800, t.name === 'light'
}) ? t.palette.negative_300
hover.push({ : t.palette.negative_800,
borderColor: tokens.color.red_500, })
}) hover.push({
focus.push({ borderColor: tokens.color.red_500,
backgroundColor: })
t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900, focus.push({
borderColor: tokens.color.red_500, backgroundColor:
}) t.name === 'light'
} ? t.palette.negative_25
: t.palette.negative_900,
borderColor: tokens.color.red_500,
})
}
return { return {
inputBaseStyles: base, inputBaseStyles: base,
inputHoverStyles: hover, inputHoverStyles: hover,
inputFocusStyles: focus, inputFocusStyles: focus,
} }
}, [t, hasError, hasIcon]) }, [t, hasError, hasIcon])
const {iconBaseStyles, iconHoverStyles, iconFocusStyles} = const {iconBaseStyles, iconHoverStyles, iconFocusStyles} =
React.useMemo(() => { React.useMemo(() => {
const base: TextStyle[] = [] const base: TextStyle[] = []
const hover: TextStyle[] = [ const hover: TextStyle[] = [
{ {
color: t.palette.contrast_500, color: t.palette.contrast_500,
}, },
] ]
const focus: TextStyle[] = [ const focus: TextStyle[] = [
{ {
color: t.palette.primary_500, color: t.palette.primary_500,
}, },
] ]
if (hasError) { if (hasError) {
base.push({ base.push({
color: t.palette.negative_400, color: t.palette.negative_400,
}) })
hover.push({ hover.push({
color: t.palette.negative_500, color: t.palette.negative_500,
}) })
focus.push({ focus.push({
color: t.palette.negative_500, color: t.palette.negative_500,
}) })
} }
return { return {
iconBaseStyles: base, iconBaseStyles: base,
iconHoverStyles: hover, iconHoverStyles: hover,
iconFocusStyles: focus, iconFocusStyles: focus,
} }
}, [t, hasError]) }, [t, hasError])
const handleOnChange = React.useCallback( const handleOnChange = React.useCallback(
(e: any) => { (e: any) => {
const value = e.currentTarget.value const value = e.currentTarget.value
onChange(value) onChange(value)
setValue(value) setValue(value)
}, },
[onChange, setValue], [onChange, setValue],
) )
return ( return (
<View style={[atoms.relative, atoms.w_full]}> <View style={[atoms.relative, atoms.w_full]}>
{label && ( {label && (
<Text <Text
nativeID={labelId} nativeID={labelId}
style={[
atoms.text_sm,
atoms.font_bold,
t.atoms.text_contrast_600,
atoms.mb_sm,
]}>
{label}
</Text>
)}
<TextInput
{...props}
value={value}
testID={testID}
aria-labelledby={labelId}
aria-label={label}
accessibilityLabel={accessibilityLabel}
accessibilityHint={accessibilityHint}
placeholderTextColor={t.atoms.text_contrast_400.color}
onFocus={onFocus}
onBlur={onBlur}
onChange={handleOnChange}
{...web({
onMouseEnter: onHoverIn,
onMouseLeave: onHoverOut,
})}
style={[
t.atoms.bg_contrast_50,
atoms.w_full,
atoms.px_lg,
atoms.py_md,
atoms.rounded_sm,
atoms.text_md,
t.atoms.text,
web({
paddingTop: atoms.pt_md.paddingTop - 1,
}),
{borderColor: 'transparent', paddingRight: suffixPadding},
{borderWidth: 2, lineHeight: atoms.text_md.lineHeight * 1.1875},
...inputBaseStyles,
...(hovered ? inputHoverStyles : []),
...(focused ? inputFocusStyles : []),
...(Array.isArray(props.style) ? props.style : [props.style]),
]}
/>
{Icon && (
<View
style={[
atoms.absolute,
atoms.inset_0,
atoms.align_center,
atoms.justify_center,
atoms.pl_md,
{right: 'auto'},
]}>
<Icon
style={[ style={[
{ atoms.text_sm,
color: atoms.font_bold,
t.name === 'light' t.atoms.text_contrast_600,
? t.palette.contrast_400 atoms.mb_sm,
: t.palette.contrast_700, ]}>
}, {label}
{ </Text>
width: 20, )}
pointerEvents: 'none',
},
...iconBaseStyles,
...(hovered ? iconHoverStyles : []),
...(focused ? iconFocusStyles : []),
]}
/>
</View>
)}
{Suffix && ( <Input
<View {...props}
onLayout={handleSuffixLayout} value={value}
testID={testID}
aria-labelledby={labelId}
aria-label={label}
accessibilityLabel={accessibilityLabel}
accessibilityHint={accessibilityHint}
placeholderTextColor={t.atoms.text_contrast_400.color}
onFocus={onFocus}
onBlur={onBlur}
onChange={handleOnChange}
{...web({
onMouseEnter: onHoverIn,
onMouseLeave: onHoverOut,
})}
style={[ style={[
atoms.absolute, t.atoms.bg_contrast_50,
atoms.inset_0, atoms.w_full,
atoms.align_center, atoms.px_lg,
atoms.justify_center, atoms.py_md,
atoms.pr_lg, atoms.rounded_sm,
{left: 'auto'}, atoms.text_md,
]}> t.atoms.text,
<Suffix /> web({
</View> paddingTop: atoms.pt_md.paddingTop - 1,
)} }),
</View> {borderColor: 'transparent', paddingRight: suffixPadding},
) {borderWidth: 2, lineHeight: atoms.text_md.lineHeight * 1.1875},
...inputBaseStyles,
...(hovered ? inputHoverStyles : []),
...(focused ? inputFocusStyles : []),
...(Array.isArray(props.style) ? props.style : [props.style]),
]}
/>
{Icon && (
<View
style={[
atoms.absolute,
atoms.inset_0,
atoms.align_center,
atoms.justify_center,
atoms.pl_md,
{right: 'auto'},
]}>
<Icon
style={[
{
color:
t.name === 'light'
? t.palette.contrast_400
: t.palette.contrast_700,
},
{
width: 20,
pointerEvents: 'none',
},
...iconBaseStyles,
...(hovered ? iconHoverStyles : []),
...(focused ? iconFocusStyles : []),
]}
/>
</View>
)}
{Suffix && (
<View
onLayout={handleSuffixLayout}
style={[
atoms.absolute,
atoms.inset_0,
atoms.align_center,
atoms.justify_center,
atoms.pr_lg,
{left: 'auto'},
]}>
<Suffix />
</View>
)}
</View>
)
}
} }
export const InputText = createTextInput(TextInput)
+8
View File
@@ -56,6 +56,14 @@ export function Dialogs() {
<View style={[a.relative, a.gap_md, a.w_full]}> <View style={[a.relative, a.gap_md, a.w_full]}>
<H3 nativeID="dialog-title">Dialog</H3> <H3 nativeID="dialog-title">Dialog</H3>
<P nativeID="dialog-description">Description</P> <P nativeID="dialog-description">Description</P>
<Dialog.InputText
testID=""
value=""
onChange={() => {}}
placeholder="Type here"
accessibilityLabel="Type"
accessibilityHint="Type"
/>
<View style={{height: 1000}} /> <View style={{height: 1000}} />
<View style={[a.flex_row, a.justify_end]}> <View style={[a.flex_row, a.justify_end]}>
<Button <Button