Skip to content

Commit e567e20

Browse files
Merge pull request #229 from web-ridge/date-input-props
Date input props
2 parents 283a3a4 + d4025bd commit e567e20

File tree

10 files changed

+121
-22
lines changed

10 files changed

+121
-22
lines changed

docusaurus/docs/date-picker/input-date-picker.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ The value used to populate the component.
5353

5454
**onChange**
5555
`Type: Function`
56-
Event handler when the component changes.
56+
Callback event when the component date mask length matches the text input length.
57+
58+
**onChangeText**
59+
`Type: Function`
60+
Callback event when the component text input changes.
5761

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

70+
**withDateFormatInLabel**
71+
`Type: boolean | undefined`
72+
Flag indicating if the date format should be inside the components label.
73+
74+
**hasError**
75+
`Type: boolean | undefined`
76+
Flag indicating if the the component should display error styles.
77+
78+
**hideValidationErrors**
79+
`Type: boolean | undefined`
80+
Flag indicating if the the component should hide error styles along with the `helperText` component displaying the error message.
81+
82+
**onValidationError**
83+
`Type: Function | undefined`
84+
Callback used to return any error messages from the components validation.
85+
86+
**saveLabelDisabled**
87+
`Type: boolean | undefined`
88+
Flag indicating if the save label should be disabled and unable to receive events. Defaults to `false`.
89+
90+
**uppercase**
91+
`Type: boolean | undefined`
92+
Flag indicating if the text in the component should be uppercase. Defaults to `true`.
93+
94+
**startYear**
95+
`Type: number | undefined`
96+
The start year when the component is rendered. Defaults to `1800`.
97+
98+
**endYear**
99+
`Type: number | undefined`
100+
The end year when the component is rendered. Defaults to `2200`.
101+
66102
* Other [react-native TextInput props](https://reactnative.dev/docs/textinput#props).*

src/Date/DatePickerInput.shared.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ export type DatePickerInputProps = {
1010
validRange?: ValidRangeType | undefined
1111
withModal?: boolean
1212
withDateFormatInLabel?: boolean
13+
hideValidationErrors?: boolean
14+
hasError?: boolean
15+
onValidationError?: ((error: string | null) => void) | undefined
1316
calendarIcon?: string
1417
saveLabel?: string
18+
saveLabelDisabled?: boolean
19+
uppercase?: boolean
20+
startYear?: number
21+
endYear?: number
22+
onChangeText?: (text: string | undefined) => void
1523
} & Omit<
1624
React.ComponentProps<typeof TextInput>,
1725
'value' | 'onChange' | 'onChangeText'

src/Date/DatePickerInput.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,18 @@ function DatePickerInput(
4242
/>
4343
) : null
4444
}
45-
modal={({ value, locale, inputMode, validRange, saveLabel }) =>
45+
// eslint-disable-next-line react/no-unstable-nested-components
46+
modal={({
47+
value,
48+
locale,
49+
inputMode,
50+
validRange,
51+
saveLabel,
52+
saveLabelDisabled,
53+
uppercase,
54+
startYear,
55+
endYear,
56+
}) =>
4657
withModal ? (
4758
<DatePickerModal
4859
date={value}
@@ -54,6 +65,10 @@ function DatePickerInput(
5465
dateMode={inputMode}
5566
validRange={validRange}
5667
saveLabel={saveLabel}
68+
saveLabelDisabled={saveLabelDisabled ?? false}
69+
uppercase={uppercase ?? true}
70+
startYear={startYear ?? 1800}
71+
endYear={endYear ?? 2200}
5772
/>
5873
) : null
5974
}

src/Date/DatePickerInputWithoutModal.tsx

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,17 @@ function DatePickerInputWithoutModal(
1616
validRange,
1717
inputMode,
1818
withDateFormatInLabel = true,
19+
hasError,
20+
hideValidationErrors,
21+
onValidationError,
1922
modal,
2023
inputButtons,
2124
saveLabel,
25+
saveLabelDisabled,
26+
uppercase,
27+
startYear,
28+
endYear,
29+
onChangeText,
2230
...rest
2331
}: DatePickerInputProps & {
2432
modal?: (params: {
@@ -27,18 +35,28 @@ function DatePickerInputWithoutModal(
2735
inputMode: DatePickerInputProps['inputMode']
2836
validRange: DatePickerInputProps['validRange']
2937
saveLabel: DatePickerInputProps['saveLabel']
38+
saveLabelDisabled: DatePickerInputProps['saveLabelDisabled']
39+
uppercase: DatePickerInputProps['uppercase']
40+
startYear: DatePickerInputProps['startYear']
41+
endYear: DatePickerInputProps['endYear']
3042
}) => any
3143
inputButtons?: any
3244
},
3345
ref: any
3446
) {
3547
const theme = useTheme()
36-
const { formattedValue, inputFormat, onChangeText, error } = useDateInput({
48+
const {
49+
formattedValue,
50+
inputFormat,
51+
onChangeText: onDateInputChangeText,
52+
error,
53+
} = useDateInput({
3754
locale,
3855
value,
3956
validRange,
4057
inputMode,
4158
onChange,
59+
onValidationError,
4260
})
4361

4462
return (
@@ -55,23 +73,33 @@ function DatePickerInputWithoutModal(
5573
withDateFormatInLabel,
5674
})}
5775
value={formattedValue}
58-
keyboardType={'number-pad'}
59-
placeholder={inputFormat}
76+
keyboardType={rest.keyboardType ?? 'number-pad'}
6077
mask={inputFormat}
61-
onChangeText={onChangeText}
78+
onChangeText={onDateInputChangeText}
79+
onChange={(e) => onChangeText && onChangeText(e.nativeEvent.text)}
6280
keyboardAppearance={theme.dark ? 'dark' : 'default'}
63-
error={!!error}
81+
error={(!!error && !hideValidationErrors) || !!hasError}
6482
style={[styles.input, style]}
6583
/>
6684
{inputButtons}
6785
</View>
68-
{error ? (
69-
<HelperText style={styles.helperText} type="error" visible={!!error}>
86+
{error && !hideValidationErrors ? (
87+
<HelperText type="error" visible={!!error}>
7088
{error}
7189
</HelperText>
7290
) : null}
7391
</View>
74-
{modal?.({ value, locale, inputMode, validRange, saveLabel })}
92+
{modal?.({
93+
value,
94+
locale,
95+
inputMode,
96+
validRange,
97+
saveLabel,
98+
saveLabelDisabled,
99+
uppercase,
100+
startYear,
101+
endYear,
102+
})}
75103
</>
76104
)
77105
}
@@ -104,8 +132,5 @@ const styles = StyleSheet.create({
104132
input: {
105133
flexGrow: 1,
106134
},
107-
helperText: {
108-
// flex: 1,
109-
},
110135
})
111136
export default React.forwardRef(DatePickerInputWithoutModal)

src/Date/inputUtils.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@ export default function useDateInput({
99
validRange,
1010
inputMode,
1111
onChange,
12+
onValidationError,
1213
}: {
1314
onChange: (d: Date) => void
1415
locale: undefined | string
1516
value: Date | undefined
1617
validRange: ValidRangeType | undefined
1718
inputMode: 'start' | 'end'
19+
onValidationError?: ((error: string | null) => void) | undefined
1820
}) {
1921
const { isDisabled, isWithinValidRange, validStart, validEnd } =
2022
useRangeChecker(validRange)
2123
const [error, setError] = React.useState<null | string>(null)
2224
const formatter = useInputFormatter({ locale })
2325
const inputFormat = useInputFormat({ formatter, locale })
24-
const formattedValue = value !== null ? formatter.format(value) : ''
26+
const formattedValue = value ? formatter.format(value) : ''
2527
const onChangeText = (date: string) => {
2628
const dayIndex = inputFormat.indexOf('DD')
2729
const monthIndex = inputFormat.indexOf('MM')
@@ -35,13 +37,13 @@ export default function useDateInput({
3537
const month = Number(date.slice(monthIndex, monthIndex + 2))
3638

3739
if (Number.isNaN(day) || Number.isNaN(year) || Number.isNaN(month)) {
38-
setError(
39-
getTranslation(
40-
locale,
41-
'notAccordingToDateFormat',
42-
() => 'notAccordingToDateFormat'
43-
)(inputFormat)
44-
)
40+
const inputError = getTranslation(
41+
locale,
42+
'notAccordingToDateFormat',
43+
() => 'notAccordingToDateFormat'
44+
)(inputFormat)
45+
setError(inputError)
46+
onValidationError && onValidationError(inputError)
4547
return
4648
}
4749

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

5355
if (isDisabled(finalDate)) {
54-
setError(getTranslation(locale, 'dateIsDisabled'))
56+
const inputError = getTranslation(locale, 'dateIsDisabled')
57+
setError(inputError)
58+
onValidationError && onValidationError(inputError)
5559
return
5660
}
5761
if (!isWithinValidRange(finalDate)) {
@@ -80,11 +84,14 @@ export default function useDateInput({
8084
)(formatter.format(validEnd))
8185
: '',
8286
]
87+
const inputError = errors.filter((n) => n).join(' ')
8388
setError(errors.filter((n) => n).join(' '))
89+
onValidationError && onValidationError(inputError)
8490
return
8591
}
8692

8793
setError(null)
94+
onValidationError && onValidationError(null)
8895
if (inputMode === 'end') {
8996
onChange(finalDate)
9097
} else {

src/TextInputMask.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ function enhanceTextWithMask(
6969
function TextInputWithMask(
7070
{
7171
onChangeText,
72+
onChange,
7273
value,
7374
mask,
7475
...rest
@@ -101,6 +102,9 @@ function TextInputWithMask(
101102
{...rest}
102103
value={controlledValue}
103104
onChangeText={onInnerChange}
105+
onChange={(e) => {
106+
onChange && onChange(e)
107+
}}
104108
onBlur={onInnerBlur}
105109
/>
106110
)

src/__tests__/Date/__snapshots__/AnimatedCrossView.test.tsx.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3593,6 +3593,7 @@ exports[`renders collapsed AnimatedCrossView 1`] = `
35933593
maxFontSizeMultiplier={1.5}
35943594
multiline={false}
35953595
onBlur={[Function]}
3596+
onChange={[Function]}
35963597
onChangeText={[Function]}
35973598
onFocus={[Function]}
35983599
onSubmitEditing={[Function]}

src/__tests__/Date/__snapshots__/CalendarEdit.test.tsx.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ exports[`renders CalendarEdit 1`] = `
176176
maxFontSizeMultiplier={1.5}
177177
multiline={false}
178178
onBlur={[Function]}
179+
onChange={[Function]}
179180
onChangeText={[Function]}
180181
onFocus={[Function]}
181182
onSubmitEditing={[Function]}

src/__tests__/Date/__snapshots__/DatePickerInput.test.tsx.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ exports[`renders DatePickerInput 1`] = `
170170
maxFontSizeMultiplier={1.5}
171171
multiline={false}
172172
onBlur={[Function]}
173+
onChange={[Function]}
173174
onChangeText={[Function]}
174175
onFocus={[Function]}
175176
placeholder=" "

src/__tests__/Date/__snapshots__/DatePickerInputWithoutModal.test.tsx.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ exports[`renders DatePickerInput 1`] = `
169169
maxFontSizeMultiplier={1.5}
170170
multiline={false}
171171
onBlur={[Function]}
172+
onChange={[Function]}
172173
onChangeText={[Function]}
173174
onFocus={[Function]}
174175
placeholder=" "

0 commit comments

Comments
 (0)