Dialog text input
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user