Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion docusaurus/docs/date-picker/input-date-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ The value used to populate the component.

**onChange**
`Type: Function`
Event handler when the component changes.
Callback event when the component date mask length matches the text input length.

**onChangeText**
`Type: Function`
Callback event when the component text input changes.

**inputMode (Required)**
`Type: String`
Expand All @@ -63,4 +67,36 @@ The type of input needed for the the picker component.
`Type: 'flat' | 'outlined'`
See [react-native-paper text-input](https://callstack.github.io/react-native-paper/text-input.html#mode).

**withDateFormatInLabel**
`Type: boolean | undefined`
Flag indicating if the date format should be inside the components label.

**hasError**
`Type: boolean | undefined`
Flag indicating if the the component should display error styles.

**hideValidationErrors**
`Type: boolean | undefined`
Flag indicating if the the component should hide error styles along with the `helperText` component displaying the error message.

**onValidationError**
`Type: Function | undefined`
Callback used to return any error messages from the components validation.

**saveLabelDisabled**
`Type: boolean | undefined`
Flag indicating if the save label should be disabled and unable to receive events. Defaults to `false`.

**uppercase**
`Type: boolean | undefined`
Flag indicating if the text in the component should be uppercase. Defaults to `true`.

**startYear**
`Type: number | undefined`
The start year when the component is rendered. Defaults to `1800`.

**endYear**
`Type: number | undefined`
The end year when the component is rendered. Defaults to `2200`.

* Other [react-native TextInput props](https://reactnative.dev/docs/textinput#props).*
8 changes: 8 additions & 0 deletions src/Date/DatePickerInput.shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@ export type DatePickerInputProps = {
validRange?: ValidRangeType | undefined
withModal?: boolean
withDateFormatInLabel?: boolean
hideValidationErrors?: boolean
hasError?: boolean
onValidationError?: ((error: string | null) => void) | undefined
calendarIcon?: string
saveLabel?: string
saveLabelDisabled?: boolean
uppercase?: boolean
startYear?: number
endYear?: number
onChangeText?: (text: string | undefined) => void
} & Omit<
React.ComponentProps<typeof TextInput>,
'value' | 'onChange' | 'onChangeText'
Expand Down
17 changes: 16 additions & 1 deletion src/Date/DatePickerInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,18 @@ function DatePickerInput(
/>
) : null
}
modal={({ value, locale, inputMode, validRange, saveLabel }) =>
// eslint-disable-next-line react/no-unstable-nested-components
modal={({
value,
locale,
inputMode,
validRange,
saveLabel,
saveLabelDisabled,
uppercase,
startYear,
endYear,
}) =>
withModal ? (
<DatePickerModal
date={value}
Expand All @@ -54,6 +65,10 @@ function DatePickerInput(
dateMode={inputMode}
validRange={validRange}
saveLabel={saveLabel}
saveLabelDisabled={saveLabelDisabled ?? false}
uppercase={uppercase ?? true}
startYear={startYear ?? 1800}
endYear={endYear ?? 2200}
/>
) : null
}
Expand Down
47 changes: 36 additions & 11 deletions src/Date/DatePickerInputWithoutModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ function DatePickerInputWithoutModal(
validRange,
inputMode,
withDateFormatInLabel = true,
hasError,
hideValidationErrors,
onValidationError,
modal,
inputButtons,
saveLabel,
saveLabelDisabled,
uppercase,
startYear,
endYear,
onChangeText,
...rest
}: DatePickerInputProps & {
modal?: (params: {
Expand All @@ -27,18 +35,28 @@ function DatePickerInputWithoutModal(
inputMode: DatePickerInputProps['inputMode']
validRange: DatePickerInputProps['validRange']
saveLabel: DatePickerInputProps['saveLabel']
saveLabelDisabled: DatePickerInputProps['saveLabelDisabled']
uppercase: DatePickerInputProps['uppercase']
startYear: DatePickerInputProps['startYear']
endYear: DatePickerInputProps['endYear']
}) => any
inputButtons?: any
},
ref: any
) {
const theme = useTheme()
const { formattedValue, inputFormat, onChangeText, error } = useDateInput({
const {
formattedValue,
inputFormat,
onChangeText: onDateInputChangeText,
error,
} = useDateInput({
locale,
value,
validRange,
inputMode,
onChange,
onValidationError,
})

return (
Expand All @@ -55,23 +73,33 @@ function DatePickerInputWithoutModal(
withDateFormatInLabel,
})}
value={formattedValue}
keyboardType={'number-pad'}
placeholder={inputFormat}
keyboardType={rest.keyboardType ?? 'number-pad'}
mask={inputFormat}
onChangeText={onChangeText}
onChangeText={onDateInputChangeText}
onChange={(e) => onChangeText && onChangeText(e.nativeEvent.text)}
keyboardAppearance={theme.dark ? 'dark' : 'default'}
error={!!error}
error={(!!error && !hideValidationErrors) || !!hasError}
style={[styles.input, style]}
/>
{inputButtons}
</View>
{error ? (
<HelperText style={styles.helperText} type="error" visible={!!error}>
{error && !hideValidationErrors ? (
<HelperText type="error" visible={!!error}>
{error}
</HelperText>
) : null}
</View>
{modal?.({ value, locale, inputMode, validRange, saveLabel })}
{modal?.({
value,
locale,
inputMode,
validRange,
saveLabel,
saveLabelDisabled,
uppercase,
startYear,
endYear,
})}
</>
)
}
Expand Down Expand Up @@ -104,8 +132,5 @@ const styles = StyleSheet.create({
input: {
flexGrow: 1,
},
helperText: {
// flex: 1,
},
})
export default React.forwardRef(DatePickerInputWithoutModal)
25 changes: 16 additions & 9 deletions src/Date/inputUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,21 @@ export default function useDateInput({
validRange,
inputMode,
onChange,
onValidationError,
}: {
onChange: (d: Date) => void
locale: undefined | string
value: Date | undefined
validRange: ValidRangeType | undefined
inputMode: 'start' | 'end'
onValidationError?: ((error: string | null) => void) | undefined
}) {
const { isDisabled, isWithinValidRange, validStart, validEnd } =
useRangeChecker(validRange)
const [error, setError] = React.useState<null | string>(null)
const formatter = useInputFormatter({ locale })
const inputFormat = useInputFormat({ formatter, locale })
const formattedValue = value !== null ? formatter.format(value) : ''
const formattedValue = value ? formatter.format(value) : ''
const onChangeText = (date: string) => {
const dayIndex = inputFormat.indexOf('DD')
const monthIndex = inputFormat.indexOf('MM')
Expand All @@ -35,13 +37,13 @@ export default function useDateInput({
const month = Number(date.slice(monthIndex, monthIndex + 2))

if (Number.isNaN(day) || Number.isNaN(year) || Number.isNaN(month)) {
setError(
getTranslation(
locale,
'notAccordingToDateFormat',
() => 'notAccordingToDateFormat'
)(inputFormat)
)
const inputError = getTranslation(
locale,
'notAccordingToDateFormat',
() => 'notAccordingToDateFormat'
)(inputFormat)
setError(inputError)
onValidationError && onValidationError(inputError)
return
}

Expand All @@ -51,7 +53,9 @@ export default function useDateInput({
: new Date(year, month - 1, day)

if (isDisabled(finalDate)) {
setError(getTranslation(locale, 'dateIsDisabled'))
const inputError = getTranslation(locale, 'dateIsDisabled')
setError(inputError)
onValidationError && onValidationError(inputError)
return
}
if (!isWithinValidRange(finalDate)) {
Expand Down Expand Up @@ -80,11 +84,14 @@ export default function useDateInput({
)(formatter.format(validEnd))
: '',
]
const inputError = errors.filter((n) => n).join(' ')
setError(errors.filter((n) => n).join(' '))
onValidationError && onValidationError(inputError)
return
}

setError(null)
onValidationError && onValidationError(null)
if (inputMode === 'end') {
onChange(finalDate)
} else {
Expand Down
4 changes: 4 additions & 0 deletions src/TextInputMask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ function enhanceTextWithMask(
function TextInputWithMask(
{
onChangeText,
onChange,
value,
mask,
...rest
Expand Down Expand Up @@ -101,6 +102,9 @@ function TextInputWithMask(
{...rest}
value={controlledValue}
onChangeText={onInnerChange}
onChange={(e) => {
onChange && onChange(e)
}}
onBlur={onInnerBlur}
/>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3593,6 +3593,7 @@ exports[`renders collapsed AnimatedCrossView 1`] = `
maxFontSizeMultiplier={1.5}
multiline={false}
onBlur={[Function]}
onChange={[Function]}
onChangeText={[Function]}
onFocus={[Function]}
onSubmitEditing={[Function]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ exports[`renders CalendarEdit 1`] = `
maxFontSizeMultiplier={1.5}
multiline={false}
onBlur={[Function]}
onChange={[Function]}
onChangeText={[Function]}
onFocus={[Function]}
onSubmitEditing={[Function]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ exports[`renders DatePickerInput 1`] = `
maxFontSizeMultiplier={1.5}
multiline={false}
onBlur={[Function]}
onChange={[Function]}
onChangeText={[Function]}
onFocus={[Function]}
placeholder=" "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ exports[`renders DatePickerInput 1`] = `
maxFontSizeMultiplier={1.5}
multiline={false}
onBlur={[Function]}
onChange={[Function]}
onChangeText={[Function]}
onFocus={[Function]}
placeholder=" "
Expand Down