@hero-design/rn 8.94.0 → 8.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -2
- package/CHANGELOG.md +18 -0
- package/es/index.js +1744 -1322
- package/lib/index.js +1747 -1324
- package/locales/en_AU.js +10 -0
- package/locales/en_AU.mjs +8 -0
- package/locales/en_CA.js +10 -0
- package/locales/en_CA.mjs +8 -0
- package/locales/index.js +11 -0
- package/locales/index.mjs +9 -0
- package/locales/types.js +2 -0
- package/locales/types.mjs +1 -0
- package/package.json +4 -3
- package/rollup.config.mjs +97 -58
- package/src/components/DatePicker/DatePickerAndroid.tsx +34 -40
- package/src/components/DatePicker/DatePickerCalendar.tsx +23 -4
- package/src/components/DatePicker/DatePickerIOS.tsx +36 -67
- package/src/components/DatePicker/Dialog/AndroidDialog.tsx +68 -0
- package/src/components/DatePicker/Dialog/IOSDialog.tsx +91 -0
- package/src/components/DatePicker/Dialog/__tests__/AndroidDialog.spec.tsx +70 -0
- package/src/components/DatePicker/Dialog/__tests__/IOSDialog.spec.tsx +114 -0
- package/src/components/DatePicker/Dialog/type.ts +50 -0
- package/src/components/DatePicker/__tests__/DatePicker.spec.tsx +30 -1
- package/src/components/DatePicker/__tests__/DatePickerAndroid.spec.tsx +27 -0
- package/src/components/DatePicker/__tests__/DatePickerCalendar.spec.tsx +27 -0
- package/src/components/DatePicker/__tests__/DatePickerIOS.spec.tsx +28 -1
- package/src/components/DatePicker/__tests__/__snapshots__/DatePickerAndroid.spec.tsx.snap +18 -9
- package/src/components/DatePicker/__tests__/__snapshots__/DatePickerIOS.spec.tsx.snap +1 -0
- package/src/components/DatePicker/hooks/__tests__/useFormatDate.spec.ts +61 -0
- package/src/components/DatePicker/{useCalculateDate.tsx → hooks/useCalculateDate.tsx} +1 -1
- package/src/components/DatePicker/hooks/useFormatDate.ts +25 -0
- package/src/components/DatePicker/hooks/utils.ts +30 -0
- package/src/components/DatePicker/index.tsx +12 -1
- package/src/components/DatePicker/types.ts +15 -1
- package/src/components/HeroDesignProvider/index.tsx +19 -6
- package/src/components/LocaleProvider/__tests__/utils.specs.ts +12 -0
- package/src/components/LocaleProvider/context.ts +7 -0
- package/src/components/LocaleProvider/hooks.ts +19 -0
- package/src/components/LocaleProvider/index.tsx +27 -0
- package/src/components/LocaleProvider/utils.ts +14 -0
- package/src/index.ts +2 -0
- package/src/locales/en_AU.ts +10 -0
- package/src/locales/en_CA.ts +10 -0
- package/src/locales/index.ts +7 -0
- package/src/locales/types.ts +12 -0
- package/src/testHelpers/renderWithTheme.tsx +7 -1
- package/src/types.ts +4 -0
- package/stats/8.95.0/rn-stats.html +4842 -0
- package/stats/8.96.0/rn-stats.html +4842 -0
- package/stats/8.97.0/rn-stats.html +4842 -0
- package/types/components/DatePicker/DatePickerAndroid.d.ts +1 -1
- package/types/components/DatePicker/DatePickerCalendar.d.ts +1 -1
- package/types/components/DatePicker/DatePickerIOS.d.ts +1 -1
- package/types/components/DatePicker/Dialog/AndroidDialog.d.ts +5 -0
- package/types/components/DatePicker/Dialog/IOSDialog.d.ts +4 -0
- package/types/components/DatePicker/Dialog/type.d.ts +50 -0
- package/types/components/DatePicker/{useCalculateDate.d.ts → hooks/useCalculateDate.d.ts} +1 -1
- package/types/components/DatePicker/hooks/useFormatDate.d.ts +10 -0
- package/types/components/DatePicker/hooks/utils.d.ts +6 -0
- package/types/components/DatePicker/index.d.ts +5 -2
- package/types/components/DatePicker/types.d.ts +8 -1
- package/types/components/HeroDesignProvider/index.d.ts +5 -1
- package/types/components/LocaleProvider/__tests__/utils.specs.d.ts +1 -0
- package/types/components/LocaleProvider/context.d.ts +3 -0
- package/types/components/LocaleProvider/hooks.d.ts +5 -0
- package/types/components/LocaleProvider/index.d.ts +7 -0
- package/types/components/LocaleProvider/utils.d.ts +3 -0
- package/types/index.d.ts +2 -1
- package/types/locales/en_AU.d.ts +3 -0
- package/types/locales/en_CA.d.ts +3 -0
- package/types/locales/index.d.ts +5 -0
- package/types/locales/types.d.ts +10 -0
- package/types/types.d.ts +2 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { MonthYearPickerViewIOS } from '@hero-design/react-native-month-year-picker';
|
|
2
|
+
import DateTimePicker, {
|
|
3
|
+
DateTimePickerEvent,
|
|
4
|
+
} from '@react-native-community/datetimepicker';
|
|
5
|
+
import React, { useState } from 'react';
|
|
6
|
+
import BottomSheet from '../../BottomSheet';
|
|
7
|
+
import Button from '../../Button';
|
|
8
|
+
import { useTheme } from '../../../theme';
|
|
9
|
+
import { StyledPickerWrapper } from '../StyledDatePicker';
|
|
10
|
+
import { DatePickerDialogProps } from './type';
|
|
11
|
+
import { getDateValue } from '../hooks/useCalculateDate';
|
|
12
|
+
|
|
13
|
+
const IOSDatePickerDialog = ({
|
|
14
|
+
label,
|
|
15
|
+
open,
|
|
16
|
+
onClose,
|
|
17
|
+
confirmLabel,
|
|
18
|
+
locale,
|
|
19
|
+
value,
|
|
20
|
+
minDate,
|
|
21
|
+
maxDate,
|
|
22
|
+
onChange,
|
|
23
|
+
testID,
|
|
24
|
+
variant = 'default',
|
|
25
|
+
supportedOrientations = ['portrait'],
|
|
26
|
+
}: DatePickerDialogProps) => {
|
|
27
|
+
const theme = useTheme();
|
|
28
|
+
const [selectingDate, setSelectingDate] = useState<Date>(
|
|
29
|
+
getDateValue(value || new Date(), minDate, maxDate)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<BottomSheet
|
|
34
|
+
testID={testID}
|
|
35
|
+
open={open}
|
|
36
|
+
onRequestClose={onClose}
|
|
37
|
+
header={label}
|
|
38
|
+
footer={
|
|
39
|
+
<Button
|
|
40
|
+
variant="text"
|
|
41
|
+
text={confirmLabel}
|
|
42
|
+
onPress={() => {
|
|
43
|
+
if (selectingDate) {
|
|
44
|
+
onChange(selectingDate);
|
|
45
|
+
}
|
|
46
|
+
onClose();
|
|
47
|
+
}}
|
|
48
|
+
/>
|
|
49
|
+
}
|
|
50
|
+
supportedOrientations={supportedOrientations}
|
|
51
|
+
>
|
|
52
|
+
<StyledPickerWrapper>
|
|
53
|
+
{variant === 'month-year' ? (
|
|
54
|
+
<MonthYearPickerViewIOS
|
|
55
|
+
value={selectingDate}
|
|
56
|
+
locale={locale}
|
|
57
|
+
minimumDate={minDate}
|
|
58
|
+
textColor={theme.colors.onDefaultGlobalSurface}
|
|
59
|
+
maximumDate={maxDate}
|
|
60
|
+
onChange={(date: Date | undefined) => {
|
|
61
|
+
if (date) {
|
|
62
|
+
setSelectingDate(date);
|
|
63
|
+
}
|
|
64
|
+
}}
|
|
65
|
+
style={{ flex: 1 }}
|
|
66
|
+
/>
|
|
67
|
+
) : null}
|
|
68
|
+
{variant === 'default' ? (
|
|
69
|
+
<DateTimePicker
|
|
70
|
+
locale={locale}
|
|
71
|
+
testID="datePickerIOS"
|
|
72
|
+
value={selectingDate}
|
|
73
|
+
minimumDate={minDate}
|
|
74
|
+
maximumDate={maxDate}
|
|
75
|
+
mode="date"
|
|
76
|
+
onChange={(_: DateTimePickerEvent, date: Date | undefined) => {
|
|
77
|
+
if (date) {
|
|
78
|
+
setSelectingDate(date);
|
|
79
|
+
}
|
|
80
|
+
}}
|
|
81
|
+
display="spinner"
|
|
82
|
+
style={{ flex: 1 }}
|
|
83
|
+
textColor={theme.colors.onDefaultGlobalSurface}
|
|
84
|
+
/>
|
|
85
|
+
) : null}
|
|
86
|
+
</StyledPickerWrapper>
|
|
87
|
+
</BottomSheet>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export default IOSDatePickerDialog;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { fireEvent } from '@testing-library/react-native';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import { Button } from '../../../..';
|
|
4
|
+
import renderWithTheme from '../../../../testHelpers/renderWithTheme';
|
|
5
|
+
import AndroidDialog, { AndroidDatePickerDialogProps } from '../AndroidDialog';
|
|
6
|
+
|
|
7
|
+
const AndroidDialogExample = (
|
|
8
|
+
props: Omit<AndroidDatePickerDialogProps, 'open' | 'onClose'>
|
|
9
|
+
) => {
|
|
10
|
+
const [open, setOpen] = useState(false);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
<Button onPress={() => setOpen(true)} text="Open" />
|
|
15
|
+
<AndroidDialog open={open} onClose={() => setOpen(false)} {...props} />
|
|
16
|
+
</>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
describe('AndroidDialog', () => {
|
|
21
|
+
it('renders correctly', () => {
|
|
22
|
+
const onChange = jest.fn();
|
|
23
|
+
|
|
24
|
+
const { getByText, queryByTestId } = renderWithTheme(
|
|
25
|
+
<AndroidDialogExample
|
|
26
|
+
value={new Date('December 21, 1995')}
|
|
27
|
+
minDate={new Date('December 17, 1994')}
|
|
28
|
+
maxDate={new Date('December 17, 1996')}
|
|
29
|
+
onChange={onChange}
|
|
30
|
+
testID="android-dialog"
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(queryByTestId('android-dialog')).toBeNull();
|
|
35
|
+
|
|
36
|
+
// Open date picker
|
|
37
|
+
fireEvent.press(getByText('Open'));
|
|
38
|
+
expect(queryByTestId('datePickerAndroid')).toBeVisible();
|
|
39
|
+
|
|
40
|
+
// Change date
|
|
41
|
+
fireEvent(
|
|
42
|
+
queryByTestId('datePickerAndroid'),
|
|
43
|
+
'onChange',
|
|
44
|
+
null,
|
|
45
|
+
new Date('December 17, 1995')
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(onChange).toBeCalledWith(new Date('December 17, 1995'));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('renders month-year picker', () => {
|
|
52
|
+
const onChangeSpy = jest.fn();
|
|
53
|
+
const { queryByText, getByText } = renderWithTheme(
|
|
54
|
+
<AndroidDialogExample
|
|
55
|
+
value={new Date('December 21, 1995')}
|
|
56
|
+
variant="month-year"
|
|
57
|
+
onChange={onChangeSpy}
|
|
58
|
+
testID="android-dialog"
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
fireEvent.press(getByText('Open'));
|
|
63
|
+
expect(queryByText('Android month year picker')).toBeDefined();
|
|
64
|
+
|
|
65
|
+
// mock change date
|
|
66
|
+
fireEvent.press(getByText('Android month year picker'));
|
|
67
|
+
expect(queryByText('Android month year picker')).toBeNull();
|
|
68
|
+
expect(onChangeSpy).toBeCalledWith(new Date('2019-09-01'));
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { fireEvent } from '@testing-library/react-native';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import type { ModalProps } from 'react-native';
|
|
4
|
+
import renderWithTheme from '../../../../testHelpers/renderWithTheme';
|
|
5
|
+
import IOSDialog from '../IOSDialog';
|
|
6
|
+
import { setOrientation } from '../../../../testHelpers/utils';
|
|
7
|
+
import { Button } from '../../../..';
|
|
8
|
+
import { DatePickerDialogProps } from '../type';
|
|
9
|
+
|
|
10
|
+
jest.mock('react-native/Libraries/Modal/Modal', () => {
|
|
11
|
+
const Modal = jest.requireActual('react-native/Libraries/Modal/Modal');
|
|
12
|
+
return (props: ModalProps) => <Modal {...props} />;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const IOSDialogExample = (
|
|
16
|
+
props: Omit<DatePickerDialogProps, 'open' | 'onClose'>
|
|
17
|
+
) => {
|
|
18
|
+
const [open, setOpen] = useState(false);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<Button onPress={() => setOpen(true)} text="Open" />
|
|
23
|
+
<IOSDialog open={open} onClose={() => setOpen(false)} {...props} />
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
describe('IOSDialog', () => {
|
|
29
|
+
it('renders correctly', () => {
|
|
30
|
+
const onChange = jest.fn();
|
|
31
|
+
const { getByText, queryByTestId } = renderWithTheme(
|
|
32
|
+
<IOSDialogExample
|
|
33
|
+
value={new Date('December 21, 1995')}
|
|
34
|
+
label="Start date"
|
|
35
|
+
confirmLabel="Confirm"
|
|
36
|
+
onChange={onChange}
|
|
37
|
+
testID="ios-dialog"
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
expect(queryByTestId('ios-dialog')).toBeNull();
|
|
42
|
+
|
|
43
|
+
// Open date picker
|
|
44
|
+
fireEvent.press(getByText('Open'));
|
|
45
|
+
expect(queryByTestId('datePickerIOS')).toBeTruthy();
|
|
46
|
+
|
|
47
|
+
// Change date
|
|
48
|
+
fireEvent(
|
|
49
|
+
queryByTestId('datePickerIOS'),
|
|
50
|
+
'onChange',
|
|
51
|
+
null,
|
|
52
|
+
new Date('December 17, 1995')
|
|
53
|
+
);
|
|
54
|
+
fireEvent.press(getByText('Confirm'));
|
|
55
|
+
|
|
56
|
+
expect(onChange).toBeCalledWith(new Date('December 17, 1995'));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('renders correctly in landscape mode', () => {
|
|
60
|
+
const onChange = jest.fn();
|
|
61
|
+
setOrientation('landscape');
|
|
62
|
+
const { getByText, queryByTestId } = renderWithTheme(
|
|
63
|
+
<IOSDialogExample
|
|
64
|
+
value={new Date('December 21, 1995')}
|
|
65
|
+
label="Start date"
|
|
66
|
+
confirmLabel="Confirm"
|
|
67
|
+
onChange={onChange}
|
|
68
|
+
supportedOrientations={['landscape']}
|
|
69
|
+
testID="ios-dialog"
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
expect(queryByTestId('ios-dialog')).toBeNull();
|
|
74
|
+
|
|
75
|
+
// Open date picker
|
|
76
|
+
fireEvent.press(getByText('Open'));
|
|
77
|
+
expect(queryByTestId('datePickerIOS')).toBeTruthy();
|
|
78
|
+
|
|
79
|
+
// Change date
|
|
80
|
+
fireEvent(
|
|
81
|
+
queryByTestId('datePickerIOS'),
|
|
82
|
+
'onChange',
|
|
83
|
+
null,
|
|
84
|
+
new Date('December 17, 1995')
|
|
85
|
+
);
|
|
86
|
+
fireEvent.press(getByText('Confirm'));
|
|
87
|
+
|
|
88
|
+
expect(onChange).toBeCalledWith(new Date('December 17, 1995'));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('renders month-year picker', () => {
|
|
92
|
+
const onChangeSpy = jest.fn();
|
|
93
|
+
const { queryByText, getByText } = renderWithTheme(
|
|
94
|
+
<IOSDialogExample
|
|
95
|
+
value={new Date('December 21, 1995')}
|
|
96
|
+
variant="month-year"
|
|
97
|
+
label="Start date"
|
|
98
|
+
confirmLabel="Confirm"
|
|
99
|
+
onChange={onChangeSpy}
|
|
100
|
+
testID="ios-dialog"
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
fireEvent.press(getByText('Open'));
|
|
105
|
+
expect(getByText('Confirm')).toBeDefined();
|
|
106
|
+
expect(getByText('IOS month year picker')).toBeDefined();
|
|
107
|
+
|
|
108
|
+
// mock change date
|
|
109
|
+
fireEvent.press(getByText('IOS month year picker'));
|
|
110
|
+
fireEvent.press(getByText('Confirm'));
|
|
111
|
+
expect(queryByText('iOS month year picker')).toBeNull();
|
|
112
|
+
expect(onChangeSpy).toBeCalledWith(new Date('2019-09-01'));
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface DatePickerDialogProps {
|
|
2
|
+
/**
|
|
3
|
+
* The value of the date picker.
|
|
4
|
+
*/
|
|
5
|
+
value?: Date;
|
|
6
|
+
/**
|
|
7
|
+
* The minimum date of the date picker.
|
|
8
|
+
*/
|
|
9
|
+
minDate?: Date;
|
|
10
|
+
/**
|
|
11
|
+
* The maximum date of the date picker.
|
|
12
|
+
*/
|
|
13
|
+
maxDate?: Date;
|
|
14
|
+
/**
|
|
15
|
+
* The function to call when the date is changed.
|
|
16
|
+
*/
|
|
17
|
+
onChange: (date: Date) => void;
|
|
18
|
+
/**
|
|
19
|
+
* The test ID of the date picker.
|
|
20
|
+
*/
|
|
21
|
+
testID?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the dialog is open
|
|
24
|
+
*/
|
|
25
|
+
open: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* The function to call when the dialog is closed.
|
|
28
|
+
*/
|
|
29
|
+
onClose: () => void;
|
|
30
|
+
/**
|
|
31
|
+
* The variant of the date picker.
|
|
32
|
+
*/
|
|
33
|
+
variant?: 'default' | 'month-year';
|
|
34
|
+
/**
|
|
35
|
+
* [iOS only] The label of the DatePicker bottom sheet.
|
|
36
|
+
*/
|
|
37
|
+
label: string;
|
|
38
|
+
/**
|
|
39
|
+
* [iOS only] The confirm label of the date picker bottom sheet.
|
|
40
|
+
*/
|
|
41
|
+
confirmLabel: string;
|
|
42
|
+
/**
|
|
43
|
+
* [iOS only] The supported orientations of the date picker.
|
|
44
|
+
*/
|
|
45
|
+
supportedOrientations?: ('portrait' | 'landscape')[];
|
|
46
|
+
/**
|
|
47
|
+
* [iOS only] The locale of the date picker.
|
|
48
|
+
*/
|
|
49
|
+
locale?: string;
|
|
50
|
+
}
|
|
@@ -3,7 +3,7 @@ import { Platform } from 'react-native';
|
|
|
3
3
|
import { fireEvent } from '@testing-library/react-native';
|
|
4
4
|
import DatePicker from '..';
|
|
5
5
|
import renderWithTheme from '../../../testHelpers/renderWithTheme';
|
|
6
|
-
import { Button } from '../../..';
|
|
6
|
+
import { Button, Typography } from '../../..';
|
|
7
7
|
|
|
8
8
|
describe('DatePicker', () => {
|
|
9
9
|
it('renders DatePickerIOS when OS is iOS', () => {
|
|
@@ -146,4 +146,33 @@ describe('DatePicker', () => {
|
|
|
146
146
|
fireEvent.press(getByText('Change max date'));
|
|
147
147
|
expect(queryByDisplayValue('21/12/1994')).toBeTruthy();
|
|
148
148
|
});
|
|
149
|
+
|
|
150
|
+
it.each`
|
|
151
|
+
OS | variant
|
|
152
|
+
${'ios'} | ${'default'}
|
|
153
|
+
${'android'} | ${'default'}
|
|
154
|
+
${'ios'} | ${'calendar'}
|
|
155
|
+
${'android'} | ${'calendar'}
|
|
156
|
+
`(
|
|
157
|
+
'renders correct with custom value with OS=$OS and variant=$variant',
|
|
158
|
+
({ OS, variant }) => {
|
|
159
|
+
Platform.OS = OS;
|
|
160
|
+
const { getByTestId } = renderWithTheme(
|
|
161
|
+
<DatePicker
|
|
162
|
+
value={new Date('1995-12-17')}
|
|
163
|
+
label="Start date"
|
|
164
|
+
confirmLabel="Confirm"
|
|
165
|
+
onChange={jest.fn()}
|
|
166
|
+
variant={variant}
|
|
167
|
+
renderSelectedValue={({ date }) => (
|
|
168
|
+
<Typography.Body testID="custom-value">
|
|
169
|
+
{date.toLocaleDateString()}
|
|
170
|
+
</Typography.Body>
|
|
171
|
+
)}
|
|
172
|
+
/>
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
expect(getByTestId('custom-value')).toBeVisible();
|
|
176
|
+
}
|
|
177
|
+
);
|
|
149
178
|
});
|
|
@@ -2,6 +2,11 @@ import { fireEvent } from '@testing-library/react-native';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import renderWithTheme from '../../../testHelpers/renderWithTheme';
|
|
4
4
|
import DatePickerAndroid from '../DatePickerAndroid';
|
|
5
|
+
import HeroDesignProvider from '../../HeroDesignProvider';
|
|
6
|
+
import { theme } from '../../..';
|
|
7
|
+
|
|
8
|
+
import enAU from '../../../locales/en_AU';
|
|
9
|
+
import enCA from '../../../locales/en_CA';
|
|
5
10
|
|
|
6
11
|
describe('DatePickerAndroid', () => {
|
|
7
12
|
it('renders correctly', () => {
|
|
@@ -79,4 +84,26 @@ describe('DatePickerAndroid', () => {
|
|
|
79
84
|
expect(queryByText('Android month year picker')).toBeNull();
|
|
80
85
|
expect(onChangeSpy).toBeCalledWith(new Date('2019-09-01'));
|
|
81
86
|
});
|
|
87
|
+
|
|
88
|
+
it.each`
|
|
89
|
+
locale | expected
|
|
90
|
+
${enAU} | ${'21/12/1995'}
|
|
91
|
+
${enCA} | ${'Dec 21, 1995'}
|
|
92
|
+
`(
|
|
93
|
+
'renders correct format for $locale.lang locale',
|
|
94
|
+
({ locale, expected }) => {
|
|
95
|
+
const { getByDisplayValue } = renderWithTheme(
|
|
96
|
+
<HeroDesignProvider theme={theme} locale={locale}>
|
|
97
|
+
<DatePickerAndroid
|
|
98
|
+
value={new Date('December 21, 1995')}
|
|
99
|
+
label="Start date"
|
|
100
|
+
confirmLabel="Confirm"
|
|
101
|
+
onChange={jest.fn()}
|
|
102
|
+
/>
|
|
103
|
+
</HeroDesignProvider>
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(getByDisplayValue(expected)).toBeVisible();
|
|
107
|
+
}
|
|
108
|
+
);
|
|
82
109
|
});
|
|
@@ -4,6 +4,11 @@ import type { ModalProps } from 'react-native';
|
|
|
4
4
|
import renderWithTheme from '../../../testHelpers/renderWithTheme';
|
|
5
5
|
import DatePickerCalendar from '../DatePickerCalendar';
|
|
6
6
|
import { setOrientation } from '../../../testHelpers/utils';
|
|
7
|
+
import HeroDesignProvider from '../../HeroDesignProvider';
|
|
8
|
+
import { theme } from '../../..';
|
|
9
|
+
|
|
10
|
+
import enAU from '../../../locales/en_AU';
|
|
11
|
+
import enCA from '../../../locales/en_CA';
|
|
7
12
|
|
|
8
13
|
jest.mock('react-native/Libraries/Modal/Modal', () => {
|
|
9
14
|
const Modal = jest.requireActual('react-native/Libraries/Modal/Modal');
|
|
@@ -137,4 +142,26 @@ describe('DatePickerCalendar', () => {
|
|
|
137
142
|
expect(queryByText('January 1993')).toBeDefined();
|
|
138
143
|
}
|
|
139
144
|
);
|
|
145
|
+
|
|
146
|
+
it.each`
|
|
147
|
+
locale | expected
|
|
148
|
+
${enAU} | ${'21/12/1995'}
|
|
149
|
+
${enCA} | ${'Dec 21, 1995'}
|
|
150
|
+
`(
|
|
151
|
+
'renders correct format for $locale.lang locale',
|
|
152
|
+
({ locale, expected }) => {
|
|
153
|
+
const { getByDisplayValue } = renderWithTheme(
|
|
154
|
+
<HeroDesignProvider theme={theme} locale={locale}>
|
|
155
|
+
<DatePickerCalendar
|
|
156
|
+
value={new Date('December 21, 1995')}
|
|
157
|
+
label="Start date"
|
|
158
|
+
confirmLabel="Confirm"
|
|
159
|
+
onChange={jest.fn()}
|
|
160
|
+
/>
|
|
161
|
+
</HeroDesignProvider>
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
expect(getByDisplayValue(expected)).toBeVisible();
|
|
165
|
+
}
|
|
166
|
+
);
|
|
140
167
|
});
|
|
@@ -3,8 +3,13 @@ import React from 'react';
|
|
|
3
3
|
import type { ModalProps } from 'react-native';
|
|
4
4
|
import renderWithTheme from '../../../testHelpers/renderWithTheme';
|
|
5
5
|
import DatePickerIOS from '../DatePickerIOS';
|
|
6
|
-
import { getDateValue } from '../useCalculateDate';
|
|
6
|
+
import { getDateValue } from '../hooks/useCalculateDate';
|
|
7
7
|
import { setOrientation } from '../../../testHelpers/utils';
|
|
8
|
+
import HeroDesignProvider from '../../HeroDesignProvider';
|
|
9
|
+
import { theme } from '../../..';
|
|
10
|
+
|
|
11
|
+
import enAU from '../../../locales/en_AU';
|
|
12
|
+
import enCA from '../../../locales/en_CA';
|
|
8
13
|
|
|
9
14
|
jest.mock('react-native/Libraries/Modal/Modal', () => {
|
|
10
15
|
const Modal = jest.requireActual('react-native/Libraries/Modal/Modal');
|
|
@@ -178,4 +183,26 @@ describe('DatePickerIOS', () => {
|
|
|
178
183
|
expect(queryByText('iOS month year picker')).toBeNull();
|
|
179
184
|
expect(onChangeSpy).toBeCalledWith(new Date('2019-09-01'));
|
|
180
185
|
});
|
|
186
|
+
|
|
187
|
+
it.each`
|
|
188
|
+
locale | expected
|
|
189
|
+
${enAU} | ${'21/12/1995'}
|
|
190
|
+
${enCA} | ${'Dec 21, 1995'}
|
|
191
|
+
`(
|
|
192
|
+
'renders correct format for $locale.lang locale',
|
|
193
|
+
({ locale, expected }) => {
|
|
194
|
+
const { getByDisplayValue } = renderWithTheme(
|
|
195
|
+
<HeroDesignProvider theme={theme} locale={locale}>
|
|
196
|
+
<DatePickerIOS
|
|
197
|
+
value={new Date('December 21, 1995')}
|
|
198
|
+
label="Start date"
|
|
199
|
+
confirmLabel="Confirm"
|
|
200
|
+
onChange={jest.fn()}
|
|
201
|
+
/>
|
|
202
|
+
</HeroDesignProvider>
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
expect(getByDisplayValue(expected)).toBeVisible();
|
|
206
|
+
}
|
|
207
|
+
);
|
|
181
208
|
});
|
|
@@ -278,15 +278,24 @@ exports[`DatePickerAndroid renders correctly 1`] = `
|
|
|
278
278
|
</View>
|
|
279
279
|
</View>
|
|
280
280
|
</View>
|
|
281
|
-
<
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
281
|
+
<View
|
|
282
|
+
style={
|
|
283
|
+
[
|
|
284
|
+
{},
|
|
285
|
+
undefined,
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
>
|
|
289
|
+
<Picker
|
|
290
|
+
display="default"
|
|
291
|
+
maximumDate={1996-12-17T00:00:00.000Z}
|
|
292
|
+
minimumDate={1994-12-17T00:00:00.000Z}
|
|
293
|
+
mode="date"
|
|
294
|
+
onChange={[Function]}
|
|
295
|
+
testID="datePickerAndroid"
|
|
296
|
+
value={1995-12-21T00:00:00.000Z}
|
|
297
|
+
/>
|
|
298
|
+
</View>
|
|
290
299
|
</View>
|
|
291
300
|
<View
|
|
292
301
|
pointerEvents="box-none"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react-hooks';
|
|
2
|
+
import formatDate from 'date-fns/fp/format';
|
|
3
|
+
import useFormatDate from '../useFormatDate';
|
|
4
|
+
import { useDateTimeFormat } from '../../../LocaleProvider/hooks';
|
|
5
|
+
|
|
6
|
+
// Mock dependencies
|
|
7
|
+
jest.mock('../../../LocaleProvider/hooks', () => ({
|
|
8
|
+
useDateTimeFormat: jest.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
jest.mock('date-fns/fp/format', () => {
|
|
12
|
+
return jest.fn((format, date) => {
|
|
13
|
+
return `Formatted: ${format}, Date: ${date.toISOString()}`;
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('useFormatDate', () => {
|
|
18
|
+
const testDate = new Date('2023-04-15');
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
(useDateTimeFormat as jest.Mock).mockReturnValue({
|
|
23
|
+
localizeDateTime: () => 'MM/dd/yyyy',
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should return empty string when no date is provided', () => {
|
|
28
|
+
const { result } = renderHook(() => useFormatDate({}));
|
|
29
|
+
expect(result.current.displayValue).toBe('');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should format date with provided format', () => {
|
|
33
|
+
const { result } = renderHook(() =>
|
|
34
|
+
useFormatDate({
|
|
35
|
+
value: testDate,
|
|
36
|
+
displayFormat: 'yyyy-MM-dd',
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
expect(formatDate).toHaveBeenCalledWith('yyyy-MM-dd', testDate);
|
|
41
|
+
expect(result.current.format).toBe('yyyy-MM-dd');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should use locale format when no displayFormat provided', () => {
|
|
45
|
+
const { result } = renderHook(() =>
|
|
46
|
+
useFormatDate({
|
|
47
|
+
value: testDate,
|
|
48
|
+
locale: 'en-US',
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
expect(formatDate).toHaveBeenCalledWith('MM/dd/yyyy', testDate);
|
|
53
|
+
expect(result.current.format).toBe('MM/dd/yyyy');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should use default format when no displayFormat or locale provided', () => {
|
|
57
|
+
const { result } = renderHook(() => useFormatDate({ value: testDate }));
|
|
58
|
+
expect(formatDate).toHaveBeenCalledWith('MM/dd/yyyy', testDate);
|
|
59
|
+
expect(result.current.format).toBe('MM/dd/yyyy');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import formatDate from 'date-fns/fp/format';
|
|
2
|
+
import { useDateTimeFormat } from '../../LocaleProvider/hooks';
|
|
3
|
+
import { getDateFormat } from './utils';
|
|
4
|
+
|
|
5
|
+
type UseFormatDateProps = {
|
|
6
|
+
displayFormat?: string;
|
|
7
|
+
locale?: string;
|
|
8
|
+
value?: Date;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const useFormatDate = ({
|
|
12
|
+
displayFormat,
|
|
13
|
+
locale,
|
|
14
|
+
value,
|
|
15
|
+
}: UseFormatDateProps) => {
|
|
16
|
+
const { localizeDateTime } = useDateTimeFormat();
|
|
17
|
+
|
|
18
|
+
const format = getDateFormat({ displayFormat, locale, localizeDateTime });
|
|
19
|
+
|
|
20
|
+
const displayValue = value ? formatDate(format, value) : '';
|
|
21
|
+
|
|
22
|
+
return { displayValue, format };
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default useFormatDate;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DateTimeFormats, LocaleCode } from '../../../types';
|
|
2
|
+
import locales from '../../../locales';
|
|
3
|
+
|
|
4
|
+
// Function to get the date format based on the displayFormat and locale,
|
|
5
|
+
// if no displayFormat or locale is provided, use the default fullDate format
|
|
6
|
+
export const getDateFormat = ({
|
|
7
|
+
displayFormat,
|
|
8
|
+
locale,
|
|
9
|
+
localizeDateTime,
|
|
10
|
+
}: {
|
|
11
|
+
displayFormat?: string;
|
|
12
|
+
locale?: string;
|
|
13
|
+
localizeDateTime: (key: keyof DateTimeFormats) => string;
|
|
14
|
+
}) => {
|
|
15
|
+
// Prioritise displayFormat
|
|
16
|
+
if (displayFormat) {
|
|
17
|
+
return displayFormat;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// If locale is provided, find the corresponding locale in the locales object
|
|
21
|
+
if (locale && locales[locale as LocaleCode]) {
|
|
22
|
+
const localeObject = locales[locale as LocaleCode];
|
|
23
|
+
if (localeObject) {
|
|
24
|
+
return localeObject.dateTimeFormats.fullDate;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// If no displayFormat or locale is provided, use the default fullDate format
|
|
29
|
+
return localizeDateTime('fullDate');
|
|
30
|
+
};
|
|
@@ -4,6 +4,9 @@ import DatePickerAndroid from './DatePickerAndroid';
|
|
|
4
4
|
import DatePickerCalendar from './DatePickerCalendar';
|
|
5
5
|
import DatePickerIOS from './DatePickerIOS';
|
|
6
6
|
import type { DatePickerProps } from './types';
|
|
7
|
+
import IOSDatePickerDialog from './Dialog/IOSDialog';
|
|
8
|
+
import AndroidDatePickerDialog from './Dialog/AndroidDialog';
|
|
9
|
+
import { DatePickerDialogProps } from './Dialog/type';
|
|
7
10
|
|
|
8
11
|
const DatePicker = ({ variant = 'default', ...props }: DatePickerProps) => {
|
|
9
12
|
if (variant === 'calendar') {
|
|
@@ -16,4 +19,12 @@ const DatePicker = ({ variant = 'default', ...props }: DatePickerProps) => {
|
|
|
16
19
|
return <DatePickerAndroid {...props} variant={variant} />;
|
|
17
20
|
};
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
const Dialog = ({ ...props }: DatePickerDialogProps) => {
|
|
23
|
+
if (Platform.OS === 'ios') {
|
|
24
|
+
return <IOSDatePickerDialog {...props} />;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return <AndroidDatePickerDialog {...props} />;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default Object.assign(DatePicker, { Dialog });
|