Bluesky app fork with some witchin' additions 💫

connect inputs together in signup (#7809)

authored by samuel.fm and committed by

GitHub ca7116ec 80e59d31

+70 -10
+21 -5
src/components/forms/DateField/index.android.tsx
··· 1 - import React from 'react' 2 import DatePicker from 'react-native-date-picker' 3 4 import {useTheme} from '#/alf' ··· 12 13 export function DateField({ 14 value, 15 onChangeDate, 16 label, 17 isInvalid, ··· 20 maximumDate, 21 }: DateFieldProps) { 22 const t = useTheme() 23 - const [open, setOpen] = React.useState(false) 24 25 - const onChangeInternal = React.useCallback( 26 (date: Date) => { 27 setOpen(false) 28 ··· 32 [onChangeDate, setOpen], 33 ) 34 35 - const onPress = React.useCallback(() => { 36 setOpen(true) 37 }, []) 38 39 - const onCancel = React.useCallback(() => { 40 setOpen(false) 41 }, []) 42
··· 1 + import {useCallback, useImperativeHandle, useState} from 'react' 2 + import {Keyboard} from 'react-native' 3 import DatePicker from 'react-native-date-picker' 4 5 import {useTheme} from '#/alf' ··· 13 14 export function DateField({ 15 value, 16 + inputRef, 17 onChangeDate, 18 label, 19 isInvalid, ··· 22 maximumDate, 23 }: DateFieldProps) { 24 const t = useTheme() 25 + const [open, setOpen] = useState(false) 26 27 + const onChangeInternal = useCallback( 28 (date: Date) => { 29 setOpen(false) 30 ··· 34 [onChangeDate, setOpen], 35 ) 36 37 + useImperativeHandle( 38 + inputRef, 39 + () => ({ 40 + focus: () => { 41 + Keyboard.dismiss() 42 + setOpen(true) 43 + }, 44 + blur: () => { 45 + setOpen(false) 46 + }, 47 + }), 48 + [], 49 + ) 50 + 51 + const onPress = useCallback(() => { 52 setOpen(true) 53 }, []) 54 55 + const onCancel = useCallback(() => { 56 setOpen(false) 57 }, []) 58
+17 -2
src/components/forms/DateField/index.tsx
··· 1 - import React from 'react' 2 import {Keyboard, View} from 'react-native' 3 import DatePicker from 'react-native-date-picker' 4 import {msg, Trans} from '@lingui/macro' ··· 25 */ 26 export function DateField({ 27 value, 28 onChangeDate, 29 testID, 30 label, ··· 36 const t = useTheme() 37 const control = Dialog.useDialogControl() 38 39 - const onChangeInternal = React.useCallback( 40 (date: Date | undefined) => { 41 if (date) { 42 const formatted = toSimpleDateString(date) ··· 44 } 45 }, 46 [onChangeDate], 47 ) 48 49 return (
··· 1 + import {useCallback, useImperativeHandle} from 'react' 2 import {Keyboard, View} from 'react-native' 3 import DatePicker from 'react-native-date-picker' 4 import {msg, Trans} from '@lingui/macro' ··· 25 */ 26 export function DateField({ 27 value, 28 + inputRef, 29 onChangeDate, 30 testID, 31 label, ··· 37 const t = useTheme() 38 const control = Dialog.useDialogControl() 39 40 + const onChangeInternal = useCallback( 41 (date: Date | undefined) => { 42 if (date) { 43 const formatted = toSimpleDateString(date) ··· 45 } 46 }, 47 [onChangeDate], 48 + ) 49 + 50 + useImperativeHandle( 51 + inputRef, 52 + () => ({ 53 + focus: () => { 54 + Keyboard.dismiss() 55 + control.open() 56 + }, 57 + blur: () => { 58 + control.close() 59 + }, 60 + }), 61 + [control], 62 ) 63 64 return (
+2 -1
src/components/forms/DateField/index.web.tsx
··· 34 35 export function DateField({ 36 value, 37 onChangeDate, 38 label, 39 isInvalid, ··· 58 <TextField.Icon icon={CalendarDays} /> 59 <Input 60 value={toSimpleDateString(value)} 61 label={label} 62 onChange={handleOnChange} 63 - onChangeText={() => {}} 64 testID={testID} 65 accessibilityHint={accessibilityHint} 66 // @ts-expect-error not typed as <input type="date"> even though it is one
··· 34 35 export function DateField({ 36 value, 37 + inputRef, 38 onChangeDate, 39 label, 40 isInvalid, ··· 59 <TextField.Icon icon={CalendarDays} /> 60 <Input 61 value={toSimpleDateString(value)} 62 + inputRef={inputRef as React.Ref<TextInput>} 63 label={label} 64 onChange={handleOnChange} 65 testID={testID} 66 accessibilityHint={accessibilityHint} 67 // @ts-expect-error not typed as <input type="date"> even though it is one
+5
src/components/forms/DateField/types.ts
··· 1 export type DateFieldProps = { 2 value: string | Date 3 onChangeDate: (date: string) => void 4 label: string 5 isInvalid?: boolean 6 testID?: string 7 accessibilityHint?: string
··· 1 + export type DateFieldRef = { 2 + focus: () => void 3 + blur: () => void 4 + } 5 export type DateFieldProps = { 6 value: string | Date 7 onChangeDate: (date: string) => void 8 label: string 9 + inputRef?: React.Ref<DateFieldRef> 10 isInvalid?: boolean 11 testID?: string 12 accessibilityHint?: string
+25 -2
src/screens/Signup/StepInfo/index.tsx
··· 1 import React, {useRef} from 'react' 2 - import {View} from 'react-native' 3 import {msg, Trans} from '@lingui/macro' 4 import {useLingui} from '@lingui/react' 5 import * as EmailValidator from 'email-validator' ··· 11 import {ScreenTransition} from '#/screens/Login/ScreenTransition' 12 import {is13, is18, useSignupContext} from '#/screens/Signup/state' 13 import {Policies} from '#/screens/Signup/StepInfo/Policies' 14 - import {atoms as a} from '#/alf' 15 import * as DateField from '#/components/forms/DateField' 16 import {FormError} from '#/components/forms/FormError' 17 import {HostingProvider} from '#/components/forms/HostingProvider' 18 import * as TextField from '#/components/forms/TextField' ··· 50 const emailValueRef = useRef<string>(state.email) 51 const prevEmailValueRef = useRef<string>(state.email) 52 const passwordValueRef = useRef<string>(state.password) 53 54 const [hasWarnedEmail, setHasWarnedEmail] = React.useState<boolean>(false) 55 ··· 155 autoCapitalize="none" 156 autoComplete="email" 157 keyboardType="email-address" 158 /> 159 </TextField.Root> 160 </View> ··· 167 <TextField.Icon icon={Envelope} /> 168 <TextField.Input 169 testID="emailInput" 170 onChangeText={value => { 171 emailValueRef.current = value.trim() 172 if (hasWarnedEmail) { ··· 178 autoCapitalize="none" 179 autoComplete="email" 180 keyboardType="email-address" 181 /> 182 </TextField.Root> 183 </View> ··· 189 <TextField.Icon icon={Lock} /> 190 <TextField.Input 191 testID="passwordInput" 192 onChangeText={value => { 193 passwordValueRef.current = value 194 }} ··· 197 secureTextEntry 198 autoComplete="new-password" 199 autoCapitalize="none" 200 /> 201 </TextField.Root> 202 </View> ··· 206 </DateField.LabelText> 207 <DateField.DateField 208 testID="date" 209 value={state.dateOfBirth} 210 onChangeDate={date => { 211 dispatch({
··· 1 import React, {useRef} from 'react' 2 + import {TextInput, View} from 'react-native' 3 import {msg, Trans} from '@lingui/macro' 4 import {useLingui} from '@lingui/react' 5 import * as EmailValidator from 'email-validator' ··· 11 import {ScreenTransition} from '#/screens/Login/ScreenTransition' 12 import {is13, is18, useSignupContext} from '#/screens/Signup/state' 13 import {Policies} from '#/screens/Signup/StepInfo/Policies' 14 + import {atoms as a, native} from '#/alf' 15 import * as DateField from '#/components/forms/DateField' 16 + import {DateFieldRef} from '#/components/forms/DateField/types' 17 import {FormError} from '#/components/forms/FormError' 18 import {HostingProvider} from '#/components/forms/HostingProvider' 19 import * as TextField from '#/components/forms/TextField' ··· 51 const emailValueRef = useRef<string>(state.email) 52 const prevEmailValueRef = useRef<string>(state.email) 53 const passwordValueRef = useRef<string>(state.password) 54 + 55 + const emailInputRef = useRef<TextInput>(null) 56 + const passwordInputRef = useRef<TextInput>(null) 57 + const birthdateInputRef = useRef<DateFieldRef>(null) 58 59 const [hasWarnedEmail, setHasWarnedEmail] = React.useState<boolean>(false) 60 ··· 160 autoCapitalize="none" 161 autoComplete="email" 162 keyboardType="email-address" 163 + returnKeyType="next" 164 + submitBehavior={native('submit')} 165 + onSubmitEditing={native(() => 166 + emailInputRef.current?.focus(), 167 + )} 168 /> 169 </TextField.Root> 170 </View> ··· 177 <TextField.Icon icon={Envelope} /> 178 <TextField.Input 179 testID="emailInput" 180 + inputRef={emailInputRef} 181 onChangeText={value => { 182 emailValueRef.current = value.trim() 183 if (hasWarnedEmail) { ··· 189 autoCapitalize="none" 190 autoComplete="email" 191 keyboardType="email-address" 192 + returnKeyType="next" 193 + submitBehavior={native('submit')} 194 + onSubmitEditing={native(() => 195 + passwordInputRef.current?.focus(), 196 + )} 197 /> 198 </TextField.Root> 199 </View> ··· 205 <TextField.Icon icon={Lock} /> 206 <TextField.Input 207 testID="passwordInput" 208 + inputRef={passwordInputRef} 209 onChangeText={value => { 210 passwordValueRef.current = value 211 }} ··· 214 secureTextEntry 215 autoComplete="new-password" 216 autoCapitalize="none" 217 + returnKeyType="next" 218 + submitBehavior={native('blurAndSubmit')} 219 + onSubmitEditing={native(() => 220 + birthdateInputRef.current?.focus(), 221 + )} 222 /> 223 </TextField.Root> 224 </View> ··· 228 </DateField.LabelText> 229 <DateField.DateField 230 testID="date" 231 + inputRef={birthdateInputRef} 232 value={state.dateOfBirth} 233 onChangeDate={date => { 234 dispatch({