diff --git a/docusaurus/docs/date-picker/input-date-picker.md b/docusaurus/docs/date-picker/input-date-picker.md index 02fb5572..d3e64c7f 100644 --- a/docusaurus/docs/date-picker/input-date-picker.md +++ b/docusaurus/docs/date-picker/input-date-picker.md @@ -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` @@ -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).* diff --git a/src/Date/DatePickerInput.shared.tsx b/src/Date/DatePickerInput.shared.tsx index 43d822f6..9c906dc0 100644 --- a/src/Date/DatePickerInput.shared.tsx +++ b/src/Date/DatePickerInput.shared.tsx @@ -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, 'value' | 'onChange' | 'onChangeText' diff --git a/src/Date/DatePickerInput.tsx b/src/Date/DatePickerInput.tsx index 5f7dc048..392e2db6 100644 --- a/src/Date/DatePickerInput.tsx +++ b/src/Date/DatePickerInput.tsx @@ -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 ? ( ) : null } diff --git a/src/Date/DatePickerInputWithoutModal.tsx b/src/Date/DatePickerInputWithoutModal.tsx index f9192cbb..3647ec4f 100644 --- a/src/Date/DatePickerInputWithoutModal.tsx +++ b/src/Date/DatePickerInputWithoutModal.tsx @@ -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: { @@ -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 ( @@ -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} - {error ? ( - + {error && !hideValidationErrors ? ( + {error} ) : null} - {modal?.({ value, locale, inputMode, validRange, saveLabel })} + {modal?.({ + value, + locale, + inputMode, + validRange, + saveLabel, + saveLabelDisabled, + uppercase, + startYear, + endYear, + })} ) } @@ -104,8 +132,5 @@ const styles = StyleSheet.create({ input: { flexGrow: 1, }, - helperText: { - // flex: 1, - }, }) export default React.forwardRef(DatePickerInputWithoutModal) diff --git a/src/Date/inputUtils.ts b/src/Date/inputUtils.ts index 16888b75..bd11af4e 100644 --- a/src/Date/inputUtils.ts +++ b/src/Date/inputUtils.ts @@ -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) 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') @@ -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 } @@ -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)) { @@ -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 { diff --git a/src/TextInputMask.tsx b/src/TextInputMask.tsx index 594db6d7..d415a80f 100644 --- a/src/TextInputMask.tsx +++ b/src/TextInputMask.tsx @@ -69,6 +69,7 @@ function enhanceTextWithMask( function TextInputWithMask( { onChangeText, + onChange, value, mask, ...rest @@ -101,6 +102,9 @@ function TextInputWithMask( {...rest} value={controlledValue} onChangeText={onInnerChange} + onChange={(e) => { + onChange && onChange(e) + }} onBlur={onInnerBlur} /> ) diff --git a/src/__tests__/Date/__snapshots__/AnimatedCrossView.test.tsx.snap b/src/__tests__/Date/__snapshots__/AnimatedCrossView.test.tsx.snap index a6333db1..571a06ad 100644 --- a/src/__tests__/Date/__snapshots__/AnimatedCrossView.test.tsx.snap +++ b/src/__tests__/Date/__snapshots__/AnimatedCrossView.test.tsx.snap @@ -3593,6 +3593,7 @@ exports[`renders collapsed AnimatedCrossView 1`] = ` maxFontSizeMultiplier={1.5} multiline={false} onBlur={[Function]} + onChange={[Function]} onChangeText={[Function]} onFocus={[Function]} onSubmitEditing={[Function]} diff --git a/src/__tests__/Date/__snapshots__/CalendarEdit.test.tsx.snap b/src/__tests__/Date/__snapshots__/CalendarEdit.test.tsx.snap index 964eed14..51b9a6e5 100644 --- a/src/__tests__/Date/__snapshots__/CalendarEdit.test.tsx.snap +++ b/src/__tests__/Date/__snapshots__/CalendarEdit.test.tsx.snap @@ -176,6 +176,7 @@ exports[`renders CalendarEdit 1`] = ` maxFontSizeMultiplier={1.5} multiline={false} onBlur={[Function]} + onChange={[Function]} onChangeText={[Function]} onFocus={[Function]} onSubmitEditing={[Function]} diff --git a/src/__tests__/Date/__snapshots__/DatePickerInput.test.tsx.snap b/src/__tests__/Date/__snapshots__/DatePickerInput.test.tsx.snap index 2c746544..8e8f30b9 100644 --- a/src/__tests__/Date/__snapshots__/DatePickerInput.test.tsx.snap +++ b/src/__tests__/Date/__snapshots__/DatePickerInput.test.tsx.snap @@ -170,6 +170,7 @@ exports[`renders DatePickerInput 1`] = ` maxFontSizeMultiplier={1.5} multiline={false} onBlur={[Function]} + onChange={[Function]} onChangeText={[Function]} onFocus={[Function]} placeholder=" " diff --git a/src/__tests__/Date/__snapshots__/DatePickerInputWithoutModal.test.tsx.snap b/src/__tests__/Date/__snapshots__/DatePickerInputWithoutModal.test.tsx.snap index e3990ba7..e4396842 100644 --- a/src/__tests__/Date/__snapshots__/DatePickerInputWithoutModal.test.tsx.snap +++ b/src/__tests__/Date/__snapshots__/DatePickerInputWithoutModal.test.tsx.snap @@ -169,6 +169,7 @@ exports[`renders DatePickerInput 1`] = ` maxFontSizeMultiplier={1.5} multiline={false} onBlur={[Function]} + onChange={[Function]} onChangeText={[Function]} onFocus={[Function]} placeholder=" "