Add placeholder, empty-value, and onConfirm support to DateField (#10993)
Co-authored-by: DS Boyce <260543580+ds-boyce@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import {useCallback, useImperativeHandle} from 'react'
|
||||
import {useCallback, useImperativeHandle, useState} from 'react'
|
||||
import {Keyboard, View} from 'react-native'
|
||||
import DatePicker from 'react-native-date-picker'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -28,6 +28,8 @@ export function DateField({
|
||||
value,
|
||||
inputRef,
|
||||
onChangeDate,
|
||||
onConfirm,
|
||||
placeholder,
|
||||
testID,
|
||||
label,
|
||||
isInvalid,
|
||||
@@ -38,10 +40,23 @@ export function DateField({
|
||||
const t = useTheme()
|
||||
const control = Dialog.useDialogControl()
|
||||
|
||||
/*
|
||||
* The picker requires a valid date, so when value is empty we fall back to
|
||||
* maximumDate (if set) or today. Draft state lets the picker scroll even when
|
||||
* the parent does not echo value back (e.g. a clearable field).
|
||||
*/
|
||||
const fallbackDate = maximumDate
|
||||
? toSimpleDateString(maximumDate)
|
||||
: toSimpleDateString(new Date())
|
||||
const [draft, setDraft] = useState(() =>
|
||||
value === '' ? fallbackDate : toSimpleDateString(value),
|
||||
)
|
||||
|
||||
const onChangeInternal = useCallback(
|
||||
(date: Date | undefined) => {
|
||||
if (date) {
|
||||
const formatted = toSimpleDateString(date)
|
||||
setDraft(formatted)
|
||||
onChangeDate(formatted)
|
||||
}
|
||||
},
|
||||
@@ -53,13 +68,14 @@ export function DateField({
|
||||
() => ({
|
||||
focus: () => {
|
||||
Keyboard.dismiss()
|
||||
setDraft(value === '' ? fallbackDate : toSimpleDateString(value))
|
||||
control.open()
|
||||
},
|
||||
blur: () => {
|
||||
control.close()
|
||||
},
|
||||
}),
|
||||
[control],
|
||||
[control, value, fallbackDate],
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -67,8 +83,10 @@ export function DateField({
|
||||
<DateFieldButton
|
||||
label={label}
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
onPress={() => {
|
||||
Keyboard.dismiss()
|
||||
setDraft(value === '' ? fallbackDate : toSimpleDateString(value))
|
||||
control.open()
|
||||
}}
|
||||
isInvalid={isInvalid}
|
||||
@@ -85,7 +103,7 @@ export function DateField({
|
||||
<DatePicker
|
||||
timeZoneOffsetInMinutes={0}
|
||||
theme={t.scheme}
|
||||
date={new Date(toSimpleDateString(value))}
|
||||
date={new Date(draft)}
|
||||
onDateChange={onChangeInternal}
|
||||
mode="date"
|
||||
locale={i18n.locale}
|
||||
@@ -102,7 +120,18 @@ export function DateField({
|
||||
</View>
|
||||
<Button
|
||||
label={_(msg`Done`)}
|
||||
onPress={() => control.close()}
|
||||
onPress={() => {
|
||||
/*
|
||||
* Commit the currently shown date even if the user never
|
||||
* scrolled (onDateChange only fires on scroll). This keeps
|
||||
* onChangeDate firing alongside onConfirm, matching Android and
|
||||
* web, so an empty field confirmed without scrolling does not
|
||||
* report a date via onConfirm while onChangeDate stays silent.
|
||||
*/
|
||||
onChangeDate(draft)
|
||||
onConfirm?.(draft)
|
||||
control.close()
|
||||
}}
|
||||
size="large"
|
||||
color="primary"
|
||||
variant="solid">
|
||||
|
||||
Reference in New Issue
Block a user