Bluesky app fork with some witchin' additions 馃挮
at main 118 lines 3.4 kB view raw
1import {useCallback, useImperativeHandle} from 'react' 2import {Keyboard, View} from 'react-native' 3import DatePicker from 'react-native-date-picker' 4import {msg} from '@lingui/core/macro' 5import {useLingui} from '@lingui/react' 6import {Trans} from '@lingui/react/macro' 7 8import {atoms as a, useTheme} from '#/alf' 9import {Button, ButtonText} from '#/components/Button' 10import * as Dialog from '#/components/Dialog' 11import {type DateFieldProps} from '#/components/forms/DateField/types' 12import {toSimpleDateString} from '#/components/forms/DateField/utils' 13import * as TextField from '#/components/forms/TextField' 14import {DateFieldButton} from './index.shared' 15 16export * as utils from '#/components/forms/DateField/utils' 17export const LabelText = TextField.LabelText 18 19/** 20 * Date-only input. Accepts a string in the format YYYY-MM-DD, or a Date object. 21 * Date objects are converted to strings in the format YYYY-MM-DD. 22 * Returns a string in the format YYYY-MM-DD. 23 * 24 * To generate a string in the format YYYY-MM-DD from a Date object, use the 25 * `utils.toSimpleDateString(Date)` export of this file. 26 */ 27export function DateField({ 28 value, 29 inputRef, 30 onChangeDate, 31 testID, 32 label, 33 isInvalid, 34 accessibilityHint, 35 maximumDate, 36}: DateFieldProps) { 37 const {_, i18n} = useLingui() 38 const t = useTheme() 39 const control = Dialog.useDialogControl() 40 41 const onChangeInternal = useCallback( 42 (date: Date | undefined) => { 43 if (date) { 44 const formatted = toSimpleDateString(date) 45 onChangeDate(formatted) 46 } 47 }, 48 [onChangeDate], 49 ) 50 51 useImperativeHandle( 52 inputRef, 53 () => ({ 54 focus: () => { 55 Keyboard.dismiss() 56 control.open() 57 }, 58 blur: () => { 59 control.close() 60 }, 61 }), 62 [control], 63 ) 64 65 return ( 66 <> 67 <DateFieldButton 68 label={label} 69 value={value} 70 onPress={() => { 71 Keyboard.dismiss() 72 control.open() 73 }} 74 isInvalid={isInvalid} 75 accessibilityHint={accessibilityHint} 76 /> 77 <Dialog.Outer 78 control={control} 79 testID={testID} 80 nativeOptions={{preventExpansion: true}}> 81 <Dialog.Handle /> 82 <Dialog.ScrollableInner label={label}> 83 <View style={a.gap_lg}> 84 <View style={[a.relative, a.w_full, a.align_center]}> 85 <DatePicker 86 timeZoneOffsetInMinutes={0} 87 theme={t.scheme} 88 date={new Date(toSimpleDateString(value))} 89 onDateChange={onChangeInternal} 90 mode="date" 91 locale={i18n.locale} 92 testID={`${testID}-datepicker`} 93 aria-label={label} 94 accessibilityLabel={label} 95 accessibilityHint={accessibilityHint} 96 maximumDate={ 97 maximumDate 98 ? new Date(toSimpleDateString(maximumDate)) 99 : undefined 100 } 101 /> 102 </View> 103 <Button 104 label={_(msg`Done`)} 105 onPress={() => control.close()} 106 size="large" 107 color="primary" 108 variant="solid"> 109 <ButtonText> 110 <Trans>Done</Trans> 111 </ButtonText> 112 </Button> 113 </View> 114 </Dialog.ScrollableInner> 115 </Dialog.Outer> 116 </> 117 ) 118}