react-native-molecules 0.5.0-beta.20 → 0.5.0-beta.22
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/components/Card/Card.tsx +1 -1
- package/components/Checkbox/CheckboxBase.ios.tsx +9 -16
- package/components/Checkbox/CheckboxBase.tsx +11 -18
- package/components/DateField/DateField.tsx +4 -3
- package/components/DatePicker/DateCalendar.tsx +4 -4
- package/components/DatePicker/DatePickerModal.tsx +35 -23
- package/components/DatePicker/DatePickerProvider.tsx +8 -2
- package/components/DatePicker/context.tsx +2 -1
- package/components/DatePicker/index.tsx +1 -0
- package/components/DatePickerInline/DatePickerDockedHeader.tsx +11 -7
- package/components/DatePickerInline/DatePickerInline.tsx +1 -1
- package/components/DatePickerInline/DatePickerInlineBase.tsx +3 -3
- package/components/DatePickerInline/DatePickerInlineHeader.tsx +50 -20
- package/components/DatePickerInline/DayNames.tsx +13 -10
- package/components/DatePickerInline/HeaderItem.tsx +2 -2
- package/components/DatePickerInline/Month.tsx +4 -3
- package/components/DatePickerInline/MonthPicker.tsx +74 -54
- package/components/DatePickerInline/Swiper.native.tsx +2 -2
- package/components/DatePickerInline/Swiper.tsx +3 -3
- package/components/DatePickerInline/YearPicker.tsx +136 -112
- package/components/DatePickerInline/{DatePickerContext.tsx → store.tsx} +7 -3
- package/components/DatePickerInline/types.ts +4 -3
- package/components/Divider/Divider.tsx +192 -0
- package/components/Divider/index.tsx +11 -0
- package/components/Drawer/DrawerItemGroup.tsx +3 -7
- package/components/IconButton/IconButton.tsx +2 -12
- package/components/List/List.tsx +507 -0
- package/components/List/context.tsx +28 -0
- package/components/List/index.ts +9 -0
- package/components/List/types.ts +149 -0
- package/components/{ListItem → List}/utils.ts +47 -50
- package/components/Menu/Menu.tsx +156 -12
- package/components/Menu/index.tsx +11 -7
- package/components/Menu/utils.ts +21 -70
- package/components/RadioButton/RadioButtonAndroid.tsx +38 -54
- package/components/RadioButton/RadioButtonIOS.tsx +2 -16
- package/components/Select/Select.tsx +139 -497
- package/components/Select/context.tsx +14 -32
- package/components/Select/types.ts +44 -53
- package/components/Select/utils.ts +15 -47
- package/components/Text/textFactory.tsx +17 -5
- package/components/TimeField/TimeField.tsx +1 -1
- package/components/TimePicker/TimeInput.tsx +2 -7
- package/components/TimePicker/TimePickerModal.tsx +15 -15
- package/components/TimePicker/utils.ts +0 -4
- package/components/TouchableRipple/TouchableRipple.native.tsx +36 -5
- package/components/TouchableRipple/TouchableRipple.tsx +53 -19
- package/components/TouchableRipple/rippleFromForegroundColor.ts +21 -0
- package/package.json +4 -2
- package/components/HorizontalDivider/HorizontalDivider.tsx +0 -103
- package/components/HorizontalDivider/index.tsx +0 -9
- package/components/ListItem/ListItem.tsx +0 -138
- package/components/ListItem/ListItemDescription.tsx +0 -25
- package/components/ListItem/ListItemTitle.tsx +0 -25
- package/components/ListItem/index.tsx +0 -14
- package/components/Menu/MenuDivider.tsx +0 -13
- package/components/Menu/MenuItem.tsx +0 -128
- package/components/VerticalDivider/VerticalDivider.tsx +0 -100
- package/components/VerticalDivider/index.tsx +0 -9
package/components/Card/Card.tsx
CHANGED
|
@@ -51,7 +51,7 @@ const Card = (
|
|
|
51
51
|
container: [cardStyles.container, cardStyles.root, style],
|
|
52
52
|
innerContainer: [cardStyles.innerContainer, touchableContainerStyle],
|
|
53
53
|
};
|
|
54
|
-
// eslint-disable-next-line
|
|
54
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
55
55
|
}, [variant, state, style, touchableContainerStyle]);
|
|
56
56
|
|
|
57
57
|
const elevation = elevationProp === undefined ? elevationLevel ?? 0 : elevationProp;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import setColor from 'color';
|
|
2
1
|
import { forwardRef, memo, useCallback, useMemo } from 'react';
|
|
3
2
|
import { View } from 'react-native';
|
|
4
3
|
|
|
@@ -37,20 +36,15 @@ const CheckboxIOS = (
|
|
|
37
36
|
state: state as States,
|
|
38
37
|
size,
|
|
39
38
|
});
|
|
39
|
+
const checkedColor = colorProp;
|
|
40
40
|
|
|
41
|
-
const {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
rippleColor: setColor(_checkedColor).fade(0.32).rgb().string(),
|
|
49
|
-
rippleContainerStyles: [styles.root, style],
|
|
50
|
-
iconContainerStyles: { opacity: indeterminate || checked ? 1 : 0 },
|
|
51
|
-
};
|
|
52
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
53
|
-
}, [checked, colorProp, indeterminate, style, state, size]);
|
|
41
|
+
const { rippleContainerStyles, iconContainerStyles } = useMemo(() => {
|
|
42
|
+
return {
|
|
43
|
+
rippleContainerStyles: [styles.root, style],
|
|
44
|
+
iconContainerStyles: { opacity: indeterminate || checked ? 1 : 0 },
|
|
45
|
+
};
|
|
46
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
47
|
+
}, [checked, colorProp, indeterminate, style, state, size, checkedColor]);
|
|
54
48
|
|
|
55
49
|
const onChange = useCallback(() => {
|
|
56
50
|
onChangeProp?.(!checked);
|
|
@@ -62,7 +56,6 @@ const CheckboxIOS = (
|
|
|
62
56
|
<TouchableRipple
|
|
63
57
|
{...rest}
|
|
64
58
|
borderless
|
|
65
|
-
rippleColor={rippleColor}
|
|
66
59
|
onPress={onChange}
|
|
67
60
|
disabled={disabled}
|
|
68
61
|
accessibilityRole="checkbox"
|
|
@@ -76,7 +69,7 @@ const CheckboxIOS = (
|
|
|
76
69
|
allowFontScaling={false}
|
|
77
70
|
type="material-community"
|
|
78
71
|
name={icon}
|
|
79
|
-
size={
|
|
72
|
+
size={iconSizeMap[size]}
|
|
80
73
|
color={checkedColor}
|
|
81
74
|
/>
|
|
82
75
|
</View>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import setColor from 'color';
|
|
2
1
|
import { forwardRef, memo, type PropsWithoutRef, useCallback, useMemo } from 'react';
|
|
3
|
-
import {
|
|
2
|
+
import { type ViewProps } from 'react-native';
|
|
4
3
|
|
|
5
4
|
import { useActionState } from '../../hooks';
|
|
6
5
|
import { resolveStateVariant } from '../../utils';
|
|
@@ -51,20 +50,15 @@ const CheckboxAndroid = (
|
|
|
51
50
|
size,
|
|
52
51
|
});
|
|
53
52
|
|
|
54
|
-
const {
|
|
55
|
-
|
|
56
|
-
const _color = tokenStylesParser.getColor(checked ? colorProp : uncheckedColorProp);
|
|
53
|
+
const { rippleContainerStyles, iconStyle } = useMemo(() => {
|
|
54
|
+
const _color = tokenStylesParser.getColor(checked ? colorProp : uncheckedColorProp);
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
rippleContainerStyles: [styles.root, style],
|
|
65
|
-
stateLayerStyle: [styles.stateLayer, stateLayerProps?.style],
|
|
66
|
-
};
|
|
67
|
-
}, [checked, colorProp, uncheckedColorProp, size, style, stateLayerProps?.style]);
|
|
56
|
+
return {
|
|
57
|
+
iconStyle: [styles.icon, _color],
|
|
58
|
+
rippleContainerStyles: [styles.root, style],
|
|
59
|
+
};
|
|
60
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
61
|
+
}, [checked, colorProp, uncheckedColorProp, style, size, state]);
|
|
68
62
|
|
|
69
63
|
const onChange = useCallback(() => {
|
|
70
64
|
onChangeProp?.(!checked);
|
|
@@ -82,7 +76,6 @@ const CheckboxAndroid = (
|
|
|
82
76
|
<TouchableRipple
|
|
83
77
|
{...rest}
|
|
84
78
|
borderless
|
|
85
|
-
rippleColor={rippleColor}
|
|
86
79
|
onPress={onChange}
|
|
87
80
|
disabled={disabled}
|
|
88
81
|
accessibilityRole="checkbox"
|
|
@@ -96,13 +89,13 @@ const CheckboxAndroid = (
|
|
|
96
89
|
allowFontScaling={false}
|
|
97
90
|
type="material-community"
|
|
98
91
|
name={icon}
|
|
99
|
-
size={
|
|
92
|
+
size={iconSizeMap[size]}
|
|
100
93
|
style={iconStyle}
|
|
101
94
|
/>
|
|
102
95
|
<StateLayer
|
|
103
96
|
testID={testID ? `${testID}-stateLayer` : ''}
|
|
104
97
|
{...stateLayerProps}
|
|
105
|
-
style={
|
|
98
|
+
style={[styles.stateLayer, stateLayerProps?.style]}
|
|
106
99
|
/>
|
|
107
100
|
</>
|
|
108
101
|
</TouchableRipple>
|
|
@@ -14,6 +14,7 @@ export type DateFieldProps = Omit<
|
|
|
14
14
|
> & {
|
|
15
15
|
inputMode?: DateFieldInputMode;
|
|
16
16
|
dateFormat?: string;
|
|
17
|
+
mask?: string;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
const DEFAULT_DATE_FORMAT = 'dd/MM/yyyy';
|
|
@@ -93,13 +94,13 @@ function DateField({
|
|
|
93
94
|
|
|
94
95
|
return (
|
|
95
96
|
<TextInputWithMask
|
|
97
|
+
placeholder={dateFormat}
|
|
98
|
+
keyboardType="number-pad"
|
|
99
|
+
mask={dateFormat}
|
|
96
100
|
{...rest}
|
|
97
101
|
ref={ref}
|
|
98
102
|
disabled={disabled}
|
|
99
103
|
value={formattedValue}
|
|
100
|
-
placeholder={dateFormat}
|
|
101
|
-
keyboardType="number-pad"
|
|
102
|
-
mask={dateFormat}
|
|
103
104
|
onChangeText={onChangeText}
|
|
104
105
|
onBlur={onInnerBlur}
|
|
105
106
|
onFocus={onInnerFocus}
|
|
@@ -11,7 +11,7 @@ import { useOptionalDatePickerContext } from './context';
|
|
|
11
11
|
|
|
12
12
|
export type DateCalendarProps = DatePickerInlineProps;
|
|
13
13
|
|
|
14
|
-
const DateCalendarDefault = memo((props: DateCalendarProps) => {
|
|
14
|
+
const DateCalendarDefault = memo(({ headerLayout = 'default', ...props }: DateCalendarProps) => {
|
|
15
15
|
const ctx = useOptionalDatePickerContext();
|
|
16
16
|
|
|
17
17
|
const hasExplicitState =
|
|
@@ -22,7 +22,7 @@ const DateCalendarDefault = memo((props: DateCalendarProps) => {
|
|
|
22
22
|
props.onChange !== undefined;
|
|
23
23
|
|
|
24
24
|
const isRange = props.mode === 'range' || ctx?.mode === 'range';
|
|
25
|
-
const effectiveHeaderLayout =
|
|
25
|
+
const effectiveHeaderLayout = headerLayout ?? (ctx ? 'docked' : 'inline');
|
|
26
26
|
const showOutsideDays =
|
|
27
27
|
props.showOutsideDays ?? (effectiveHeaderLayout === 'docked' && !isRange);
|
|
28
28
|
|
|
@@ -50,7 +50,7 @@ const DateCalendarDefault = memo((props: DateCalendarProps) => {
|
|
|
50
50
|
onChange={onChange}
|
|
51
51
|
locale={locale}
|
|
52
52
|
validRange={validRange}
|
|
53
|
-
headerLayout={
|
|
53
|
+
headerLayout={headerLayout}
|
|
54
54
|
showOutsideDays={showOutsideDays}
|
|
55
55
|
/>
|
|
56
56
|
);
|
|
@@ -72,7 +72,7 @@ const DateCalendarDefault = memo((props: DateCalendarProps) => {
|
|
|
72
72
|
onChange={onChange}
|
|
73
73
|
locale={locale}
|
|
74
74
|
validRange={validRange}
|
|
75
|
-
headerLayout={
|
|
75
|
+
headerLayout={headerLayout}
|
|
76
76
|
showOutsideDays={showOutsideDays}
|
|
77
77
|
/>
|
|
78
78
|
);
|
|
@@ -10,14 +10,14 @@ import {
|
|
|
10
10
|
} from 'react-native';
|
|
11
11
|
|
|
12
12
|
import { getRegisteredComponentWithFallback } from '../../core';
|
|
13
|
-
import { format } from '../../utils/date-fns';
|
|
14
13
|
import { DateField } from '../DateField';
|
|
14
|
+
import type { DatePickerInlineProps } from '../DatePickerInline/DatePickerInline';
|
|
15
15
|
import { IconButton } from '../IconButton';
|
|
16
16
|
import { Modal, type ModalProps } from '../Modal';
|
|
17
17
|
import { Portal } from '../Portal';
|
|
18
18
|
import { Text } from '../Text';
|
|
19
19
|
import { TextInput } from '../TextInput';
|
|
20
|
-
import type { DatePickerContextType, DatePickerValue } from './context';
|
|
20
|
+
import type { DatePickerContextType, DatePickerLocale, DatePickerValue } from './context';
|
|
21
21
|
import {
|
|
22
22
|
DatePickerContext,
|
|
23
23
|
useDatePickerContext,
|
|
@@ -42,7 +42,13 @@ export type DatePickerModalProps = Omit<ModalProps, 'children' | 'isOpen' | 'onC
|
|
|
42
42
|
cancelLabel?: string;
|
|
43
43
|
editIcon?: string;
|
|
44
44
|
calendarIcon?: string;
|
|
45
|
-
|
|
45
|
+
emptySummaryLabel?: string;
|
|
46
|
+
editingSummaryLabel?: string;
|
|
47
|
+
dateInputLabel?: string;
|
|
48
|
+
showCalendarAccessibilityLabel?: string;
|
|
49
|
+
enterDateManuallyAccessibilityLabel?: string;
|
|
50
|
+
locale?: DatePickerLocale;
|
|
51
|
+
headerLayout?: DatePickerInlineProps['headerLayout'];
|
|
46
52
|
/** Override the surface default draft mode. Modal defaults to `true` (staged commit). */
|
|
47
53
|
draft?: boolean;
|
|
48
54
|
};
|
|
@@ -59,6 +65,11 @@ function DatePickerModalBody({
|
|
|
59
65
|
cancelLabel = 'Cancel',
|
|
60
66
|
editIcon = 'pencil',
|
|
61
67
|
calendarIcon = 'calendar',
|
|
68
|
+
emptySummaryLabel = 'Select date',
|
|
69
|
+
editingSummaryLabel = 'Enter dates',
|
|
70
|
+
dateInputLabel = 'Date',
|
|
71
|
+
showCalendarAccessibilityLabel = 'Show calendar',
|
|
72
|
+
enterDateManuallyAccessibilityLabel = 'Enter date manually',
|
|
62
73
|
headerLayout,
|
|
63
74
|
...rest
|
|
64
75
|
}: BodyProps) {
|
|
@@ -97,15 +108,19 @@ function DatePickerModalBody({
|
|
|
97
108
|
: ctx.draftValue;
|
|
98
109
|
|
|
99
110
|
const summaryLabel = useMemo(() => {
|
|
100
|
-
if (editing) return
|
|
101
|
-
if (!draft) return
|
|
102
|
-
return
|
|
103
|
-
|
|
111
|
+
if (editing) return editingSummaryLabel;
|
|
112
|
+
if (!draft) return emptySummaryLabel;
|
|
113
|
+
return new Intl.DateTimeFormat(ctx.locale, {
|
|
114
|
+
weekday: 'short',
|
|
115
|
+
month: 'short',
|
|
116
|
+
day: 'numeric',
|
|
117
|
+
}).format(draft);
|
|
118
|
+
}, [ctx.locale, draft, editing, editingSummaryLabel, emptySummaryLabel]);
|
|
104
119
|
|
|
105
120
|
const body = editing ? (
|
|
106
121
|
<View style={datePickerModalStyles.inputContainer}>
|
|
107
122
|
<DateField autoFocus>
|
|
108
|
-
<TextInput.Label>
|
|
123
|
+
<TextInput.Label>{dateInputLabel}</TextInput.Label>
|
|
109
124
|
</DateField>
|
|
110
125
|
</View>
|
|
111
126
|
) : (
|
|
@@ -139,7 +154,9 @@ function DatePickerModalBody({
|
|
|
139
154
|
<IconButton
|
|
140
155
|
name={editing ? calendarIcon : editIcon}
|
|
141
156
|
accessibilityLabel={
|
|
142
|
-
editing
|
|
157
|
+
editing
|
|
158
|
+
? showCalendarAccessibilityLabel
|
|
159
|
+
: enterDateManuallyAccessibilityLabel
|
|
143
160
|
}
|
|
144
161
|
onPress={() => setEditing(prev => !prev)}
|
|
145
162
|
style={datePickerModalStyles.modeToggle}
|
|
@@ -161,31 +178,24 @@ function DatePickerModalBody({
|
|
|
161
178
|
function DatePickerModalLayer({
|
|
162
179
|
base,
|
|
163
180
|
draft: draftProp,
|
|
164
|
-
|
|
165
|
-
}: {
|
|
181
|
+
...rest
|
|
182
|
+
}: BodyProps & {
|
|
166
183
|
base: DatePickerContextType;
|
|
167
184
|
draft: boolean | undefined;
|
|
168
|
-
bodyProps: BodyProps;
|
|
169
185
|
}) {
|
|
170
186
|
const effectiveDraft = draftProp ?? base.providerDraft ?? true;
|
|
171
187
|
const ctx = useMemo(() => withDraftLayer(base, effectiveDraft), [base, effectiveDraft]);
|
|
172
188
|
if (!base.open) return null;
|
|
173
189
|
return (
|
|
174
190
|
<DatePickerContext value={ctx}>
|
|
175
|
-
<DatePickerModalBody {...
|
|
191
|
+
<DatePickerModalBody {...rest} />
|
|
176
192
|
</DatePickerContext>
|
|
177
193
|
);
|
|
178
194
|
}
|
|
179
195
|
|
|
180
|
-
function DatePickerModalAdapter({
|
|
181
|
-
draft,
|
|
182
|
-
bodyProps,
|
|
183
|
-
}: {
|
|
184
|
-
draft: boolean | undefined;
|
|
185
|
-
bodyProps: BodyProps;
|
|
186
|
-
}) {
|
|
196
|
+
function DatePickerModalAdapter({ draft, ...rest }: BodyProps & { draft: boolean | undefined }) {
|
|
187
197
|
const base = useDatePickerContext();
|
|
188
|
-
return <DatePickerModalLayer base={base} draft={draft}
|
|
198
|
+
return <DatePickerModalLayer base={base} draft={draft} {...rest} />;
|
|
189
199
|
}
|
|
190
200
|
|
|
191
201
|
function DatePickerModalInner({
|
|
@@ -193,6 +203,7 @@ function DatePickerModalInner({
|
|
|
193
203
|
onClose: onCloseProp,
|
|
194
204
|
value: valueProp,
|
|
195
205
|
onChange: onChangeProp,
|
|
206
|
+
locale,
|
|
196
207
|
draft: draftProp,
|
|
197
208
|
...rest
|
|
198
209
|
}: DatePickerModalProps) {
|
|
@@ -206,7 +217,7 @@ function DatePickerModalInner({
|
|
|
206
217
|
);
|
|
207
218
|
|
|
208
219
|
if (outer) {
|
|
209
|
-
return <DatePickerModalLayer base={outer} draft={draftProp}
|
|
220
|
+
return <DatePickerModalLayer base={outer} draft={draftProp} {...rest} />;
|
|
210
221
|
}
|
|
211
222
|
|
|
212
223
|
return (
|
|
@@ -214,8 +225,9 @@ function DatePickerModalInner({
|
|
|
214
225
|
value={valueProp}
|
|
215
226
|
onChange={onChangeProp}
|
|
216
227
|
open={isOpenProp}
|
|
228
|
+
locale={locale}
|
|
217
229
|
onOpenChange={onOpenChange}>
|
|
218
|
-
<DatePickerModalAdapter draft={draftProp}
|
|
230
|
+
<DatePickerModalAdapter draft={draftProp} {...rest} />
|
|
219
231
|
</DatePickerProvider>
|
|
220
232
|
);
|
|
221
233
|
}
|
|
@@ -4,7 +4,13 @@ import { memo, useCallback, useMemo, useRef, useState } from 'react';
|
|
|
4
4
|
import { getRegisteredComponentWithFallback } from '../../core';
|
|
5
5
|
import { useControlledValue } from '../../hooks';
|
|
6
6
|
import type { ValidRangeType } from '../DatePickerInline';
|
|
7
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
DatePickerContextType,
|
|
9
|
+
DatePickerLocale,
|
|
10
|
+
DatePickerMode,
|
|
11
|
+
DatePickerValue,
|
|
12
|
+
RangeValue,
|
|
13
|
+
} from './context';
|
|
8
14
|
import { DatePickerContext, withDraftLayer } from './context';
|
|
9
15
|
|
|
10
16
|
const DATE_FORMAT_BY_MODE: Record<DatePickerMode, string> = {
|
|
@@ -30,7 +36,7 @@ export type DatePickerProviderProps = {
|
|
|
30
36
|
defaultOpen?: boolean;
|
|
31
37
|
onOpenChange?: (open: boolean) => void;
|
|
32
38
|
|
|
33
|
-
locale?:
|
|
39
|
+
locale?: DatePickerLocale;
|
|
34
40
|
validRange?: ValidRangeType;
|
|
35
41
|
is24Hour?: boolean;
|
|
36
42
|
dateFormat?: string;
|
|
@@ -5,6 +5,7 @@ import type { ValidRangeType } from '../DatePickerInline';
|
|
|
5
5
|
import { registerPortalContext } from '../Portal';
|
|
6
6
|
|
|
7
7
|
export type DatePickerMode = 'date' | 'time' | 'datetime' | 'range';
|
|
8
|
+
export type DatePickerLocale = Intl.LocalesArgument;
|
|
8
9
|
|
|
9
10
|
export type DateValue = Date | null;
|
|
10
11
|
export type RangeValue = { start: Date | null; end: Date | null };
|
|
@@ -35,7 +36,7 @@ export type DatePickerContextType = {
|
|
|
35
36
|
open: boolean;
|
|
36
37
|
setOpen: (open: boolean) => void;
|
|
37
38
|
triggerRef: RefObject<any>;
|
|
38
|
-
locale?:
|
|
39
|
+
locale?: DatePickerLocale;
|
|
39
40
|
validRange?: ValidRangeType;
|
|
40
41
|
is24Hour: boolean;
|
|
41
42
|
dateFormat: string;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { add,
|
|
1
|
+
import { add, setYear } from 'date-fns';
|
|
2
2
|
import { memo, useCallback, useMemo } from 'react';
|
|
3
3
|
import { View, type ViewStyle } from 'react-native';
|
|
4
4
|
import { StyleSheet } from 'react-native-unistyles';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import type { DatePickerLocale } from '../DatePicker/context';
|
|
7
7
|
import type { DisableWeekDaysType } from './dateUtils';
|
|
8
8
|
import DayNames from './DayNames';
|
|
9
9
|
import HeaderItem from './HeaderItem';
|
|
10
|
+
import { useDatePickerInlineStoreRef, useDatePickerInlineStoreValue } from './store';
|
|
10
11
|
import { datePickerHeaderStyles } from './utils';
|
|
11
12
|
|
|
12
13
|
export type DockedHeaderProps = {
|
|
13
|
-
locale?:
|
|
14
|
+
locale?: DatePickerLocale;
|
|
14
15
|
scrollMode: 'horizontal' | 'vertical';
|
|
15
16
|
disableWeekDays?: DisableWeekDaysType;
|
|
16
17
|
style?: ViewStyle;
|
|
@@ -22,16 +23,19 @@ function DatePickerDockedHeader({
|
|
|
22
23
|
disableWeekDays,
|
|
23
24
|
style: styleProp,
|
|
24
25
|
}: DockedHeaderProps) {
|
|
25
|
-
const setStore =
|
|
26
|
-
const { localDate, pickerType } =
|
|
26
|
+
const setStore = useDatePickerInlineStoreRef().set;
|
|
27
|
+
const { localDate, pickerType } = useDatePickerInlineStoreValue(state => ({
|
|
27
28
|
localDate: state.localDate,
|
|
28
29
|
pickerType: state.pickerType,
|
|
29
30
|
}));
|
|
30
31
|
const isHorizontal = scrollMode === 'horizontal';
|
|
31
32
|
|
|
32
33
|
const { monthName, year } = useMemo(
|
|
33
|
-
() => ({
|
|
34
|
-
|
|
34
|
+
() => ({
|
|
35
|
+
monthName: new Intl.DateTimeFormat(locale, { month: 'short' }).format(localDate),
|
|
36
|
+
year: localDate.getFullYear(),
|
|
37
|
+
}),
|
|
38
|
+
[localDate, locale],
|
|
35
39
|
);
|
|
36
40
|
|
|
37
41
|
const handleMonthDropdown = useCallback(() => {
|
|
@@ -2,10 +2,10 @@ import { memo, useCallback, useEffect, useMemo } from 'react';
|
|
|
2
2
|
import { StyleSheet, View } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { useLatest } from '../../hooks';
|
|
5
|
-
import { defaultValue, Provider, useDatePickerStore } from './DatePickerContext';
|
|
6
5
|
import { areDatesOnSameDay, dateToUnix, getEndOfDay, getInitialIndex } from './dateUtils';
|
|
7
6
|
import Month from './Month';
|
|
8
7
|
import MonthPicker from './MonthPicker';
|
|
8
|
+
import { defaultValue, Provider, useDatePickerInlineStore } from './store';
|
|
9
9
|
import Swiper from './Swiper';
|
|
10
10
|
import type {
|
|
11
11
|
CalendarDate,
|
|
@@ -46,7 +46,7 @@ function DatePickerInlineBaseChild(props: DatePickerInlineBaseProps) {
|
|
|
46
46
|
showOutsideDays,
|
|
47
47
|
headerLayout,
|
|
48
48
|
} = props;
|
|
49
|
-
const [pickerType, setStore] =
|
|
49
|
+
const [pickerType, setStore] = useDatePickerInlineStore(state => state.pickerType);
|
|
50
50
|
|
|
51
51
|
const scrollMode = mode === 'range' || mode === 'multiple' ? 'vertical' : 'horizontal';
|
|
52
52
|
const isHorizontal = scrollMode === 'horizontal';
|
|
@@ -173,7 +173,7 @@ function DatePickerInlineBaseChild(props: DatePickerInlineBaseProps) {
|
|
|
173
173
|
{isHorizontal && pickerType === 'year' && (
|
|
174
174
|
<YearPicker layout={headerLayout === 'docked' ? 'list' : 'grid'} />
|
|
175
175
|
)}
|
|
176
|
-
{isHorizontal && pickerType === 'month' && <MonthPicker />}
|
|
176
|
+
{isHorizontal && pickerType === 'month' && <MonthPicker locale={locale} />}
|
|
177
177
|
</View>
|
|
178
178
|
);
|
|
179
179
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { add,
|
|
1
|
+
import { add, setYear } from 'date-fns';
|
|
2
2
|
import { memo, useCallback, useMemo } from 'react';
|
|
3
3
|
import { type StyleProp, View, type ViewStyle } from 'react-native';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { DatePickerLocale } from '../DatePicker/context';
|
|
6
6
|
import type { DisableWeekDaysType } from './dateUtils';
|
|
7
7
|
import DayNames from './DayNames';
|
|
8
8
|
import HeaderItem from './HeaderItem';
|
|
9
|
+
import { useDatePickerInlineStore, useDatePickerInlineStoreValue } from './store';
|
|
9
10
|
import { datePickerHeaderStyles, dayNamesHeight } from './utils';
|
|
10
11
|
|
|
11
12
|
const buttonContainerHeight = 56;
|
|
@@ -13,7 +14,7 @@ const buttonContainerMarginTop = 4;
|
|
|
13
14
|
const buttonContainerMarginBottom = 8;
|
|
14
15
|
|
|
15
16
|
export type CalendarHeaderProps = {
|
|
16
|
-
locale?:
|
|
17
|
+
locale?: DatePickerLocale;
|
|
17
18
|
scrollMode: 'horizontal' | 'vertical';
|
|
18
19
|
disableWeekDays?: DisableWeekDaysType;
|
|
19
20
|
style?: ViewStyle;
|
|
@@ -25,18 +26,21 @@ function DatePickerInlineHeader({
|
|
|
25
26
|
disableWeekDays,
|
|
26
27
|
style: styleProp,
|
|
27
28
|
}: CalendarHeaderProps) {
|
|
28
|
-
const [_, setStore] =
|
|
29
|
-
const { localDate,
|
|
29
|
+
const [_, setStore] = useDatePickerInlineStore(state => state);
|
|
30
|
+
const { localDate, pickerType } = useDatePickerInlineStoreValue(state => ({
|
|
30
31
|
localDate: state.localDate,
|
|
31
|
-
|
|
32
|
+
pickerType: state.pickerType,
|
|
32
33
|
}));
|
|
33
34
|
const isHorizontal = scrollMode === 'horizontal';
|
|
34
35
|
|
|
35
36
|
const { monthName, year } = useMemo(() => {
|
|
36
37
|
const y = localDate.getFullYear();
|
|
37
38
|
|
|
38
|
-
return {
|
|
39
|
-
|
|
39
|
+
return {
|
|
40
|
+
monthName: new Intl.DateTimeFormat(locale, { month: 'long' }).format(localDate),
|
|
41
|
+
year: y,
|
|
42
|
+
};
|
|
43
|
+
}, [localDate, locale]);
|
|
40
44
|
|
|
41
45
|
const { containerStyle } = useMemo(() => {
|
|
42
46
|
// const { datePickerHeader, buttonContainer, buttonWrapper, spacer, ...rest } =
|
|
@@ -54,36 +58,62 @@ function DatePickerInlineHeader({
|
|
|
54
58
|
};
|
|
55
59
|
}, [styleProp]);
|
|
56
60
|
|
|
61
|
+
const handleOnMonthPress = useCallback(() => {
|
|
62
|
+
isHorizontal &&
|
|
63
|
+
setStore(prev => ({
|
|
64
|
+
pickerType: prev.pickerType === 'month' ? undefined : 'month',
|
|
65
|
+
}));
|
|
66
|
+
}, [isHorizontal, setStore]);
|
|
67
|
+
|
|
57
68
|
const handleOnYearPress = useCallback(() => {
|
|
58
|
-
isHorizontal &&
|
|
69
|
+
isHorizontal &&
|
|
70
|
+
setStore(prev => ({
|
|
71
|
+
pickerType: prev.pickerType === 'year' ? undefined : 'year',
|
|
72
|
+
}));
|
|
59
73
|
}, [isHorizontal, setStore]);
|
|
60
74
|
|
|
61
|
-
const
|
|
75
|
+
const handleMonthPrev = useCallback(() => {
|
|
62
76
|
setStore(prev => ({ localDate: add(prev.localDate, { months: -1 }) }));
|
|
63
77
|
}, [setStore]);
|
|
64
78
|
|
|
65
|
-
const
|
|
79
|
+
const handleMonthNext = useCallback(() => {
|
|
66
80
|
setStore(prev => ({ localDate: add(prev.localDate, { months: 1 }) }));
|
|
67
81
|
}, [setStore]);
|
|
68
82
|
|
|
83
|
+
const handleYearPrev = useCallback(() => {
|
|
84
|
+
setStore(prev => ({
|
|
85
|
+
localDate: setYear(prev.localDate, prev.localDate.getFullYear() - 1),
|
|
86
|
+
}));
|
|
87
|
+
}, [setStore]);
|
|
88
|
+
|
|
89
|
+
const handleYearNext = useCallback(() => {
|
|
90
|
+
setStore(prev => ({
|
|
91
|
+
localDate: setYear(prev.localDate, prev.localDate.getFullYear() + 1),
|
|
92
|
+
}));
|
|
93
|
+
}, [setStore]);
|
|
94
|
+
|
|
69
95
|
return (
|
|
70
96
|
<View pointerEvents={'box-none'}>
|
|
71
97
|
<>
|
|
72
98
|
{isHorizontal && (
|
|
73
99
|
<View style={containerStyle}>
|
|
74
100
|
<HeaderItem
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
101
|
+
onPrev={handleMonthPrev}
|
|
102
|
+
onNext={handleMonthNext}
|
|
103
|
+
onPressDropdown={handleOnMonthPress}
|
|
104
|
+
type="month"
|
|
105
|
+
value={monthName}
|
|
106
|
+
pickerType={pickerType}
|
|
107
|
+
selecting={pickerType === 'month'}
|
|
80
108
|
/>
|
|
81
109
|
<HeaderItem
|
|
82
|
-
onNext={
|
|
83
|
-
onPrev={
|
|
84
|
-
|
|
110
|
+
onNext={handleYearNext}
|
|
111
|
+
onPrev={handleYearPrev}
|
|
112
|
+
onPressDropdown={handleOnYearPress}
|
|
113
|
+
type="year"
|
|
114
|
+
selecting={pickerType === 'year'}
|
|
85
115
|
value={year}
|
|
86
|
-
pickerType=
|
|
116
|
+
pickerType={pickerType}
|
|
87
117
|
/>
|
|
88
118
|
</View>
|
|
89
119
|
)}
|
|
@@ -1,23 +1,26 @@
|
|
|
1
|
-
import { memo } from 'react';
|
|
1
|
+
import { memo, useMemo } from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import { addDays,
|
|
4
|
+
import { addDays, startOfWeek } from '../../utils/date-fns';
|
|
5
|
+
import type { DatePickerLocale } from '../DatePicker/context';
|
|
5
6
|
import { type DisableWeekDaysType, showWeekDay } from './dateUtils';
|
|
6
7
|
import DayName from './DayName';
|
|
7
8
|
import { dateDayNameStyles } from './utils';
|
|
8
9
|
|
|
9
|
-
const shortDayNames = (() => {
|
|
10
|
-
const firstDOW = startOfWeek(new Date());
|
|
11
|
-
return Array.from(Array(7)).map((_, i) => format(addDays(firstDOW, i), 'EEEEE'));
|
|
12
|
-
})();
|
|
13
|
-
|
|
14
10
|
function DayNames({
|
|
15
11
|
disableWeekDays,
|
|
16
|
-
|
|
17
|
-
{
|
|
12
|
+
locale,
|
|
13
|
+
}: {
|
|
18
14
|
disableWeekDays?: DisableWeekDaysType;
|
|
19
|
-
locale?:
|
|
15
|
+
locale?: DatePickerLocale;
|
|
20
16
|
}) {
|
|
17
|
+
const shortDayNames = useMemo(() => {
|
|
18
|
+
const firstDOW = startOfWeek(new Date());
|
|
19
|
+
return Array.from(Array(7)).map((_, i) =>
|
|
20
|
+
new Intl.DateTimeFormat(locale, { weekday: 'narrow' }).format(addDays(firstDOW, i)),
|
|
21
|
+
);
|
|
22
|
+
}, [locale]);
|
|
23
|
+
|
|
21
24
|
return (
|
|
22
25
|
<View style={dateDayNameStyles.container} pointerEvents={'none'}>
|
|
23
26
|
{shortDayNames
|
|
@@ -6,7 +6,7 @@ import { Icon } from '../Icon';
|
|
|
6
6
|
import { IconButton } from '../IconButton';
|
|
7
7
|
import { Text } from '../Text';
|
|
8
8
|
import { TouchableRipple } from '../TouchableRipple';
|
|
9
|
-
import {
|
|
9
|
+
import { useDatePickerInlineStoreValue } from './store';
|
|
10
10
|
|
|
11
11
|
function HeaderItem({
|
|
12
12
|
value,
|
|
@@ -25,7 +25,7 @@ function HeaderItem({
|
|
|
25
25
|
onNext?: (type: 'month' | 'year' | undefined) => void;
|
|
26
26
|
onPrev?: (type: 'month' | 'year' | undefined) => void;
|
|
27
27
|
}) {
|
|
28
|
-
const { startDateYear, endDateYear } =
|
|
28
|
+
const { startDateYear, endDateYear } = useDatePickerInlineStoreValue(state => ({
|
|
29
29
|
startDateYear: state.startDateYear,
|
|
30
30
|
endDateYear: state.endDateYear,
|
|
31
31
|
}));
|