@momo-kits/calendar 0.168.1-beta.20 → 0.168.1-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/CalendarPro.tsx +15 -20
- package/ContainerContext.ts +3 -0
- package/Day.tsx +2 -4
- package/HeaderControl.tsx +1 -2
- package/Month.tsx +1 -1
- package/MonthList.tsx +36 -23
- package/TabHeader.tsx +59 -74
- package/Util.ts +2 -101
- package/index.tsx +18 -37
- package/package.json +1 -1
- package/styles.ts +4 -16
- package/types.ts +5 -38
- package/LunarService.ts +0 -206
package/CalendarPro.tsx
CHANGED
|
@@ -7,18 +7,16 @@ import React, {
|
|
|
7
7
|
forwardRef,
|
|
8
8
|
useImperativeHandle,
|
|
9
9
|
} from 'react';
|
|
10
|
-
import {
|
|
10
|
+
import { ScrollView, View } from 'react-native';
|
|
11
11
|
import moment, { Moment } from 'moment';
|
|
12
12
|
import {
|
|
13
13
|
ApplicationContext,
|
|
14
14
|
CheckBox,
|
|
15
|
-
Colors,
|
|
16
15
|
Spacing,
|
|
17
16
|
Text,
|
|
18
17
|
} from '@momo-kits/foundation';
|
|
19
18
|
import MonthList from './MonthList';
|
|
20
19
|
import HeaderControl from './HeaderControl';
|
|
21
|
-
import LunarDateConverter from './LunarDateConverter';
|
|
22
20
|
import Util from './Util';
|
|
23
21
|
import {
|
|
24
22
|
CalendarProProps,
|
|
@@ -27,7 +25,7 @@ import {
|
|
|
27
25
|
MonthListRef,
|
|
28
26
|
Holidays,
|
|
29
27
|
} from './types';
|
|
30
|
-
import { ContainerContext } from './
|
|
28
|
+
import { ContainerContext } from './ContainerContext';
|
|
31
29
|
import styles from './styles';
|
|
32
30
|
|
|
33
31
|
const CalendarPro = forwardRef<CalendarProRef, CalendarProProps>(
|
|
@@ -53,8 +51,7 @@ const CalendarPro = forwardRef<CalendarProRef, CalendarProProps>(
|
|
|
53
51
|
const { theme, translate } = useContext(ApplicationContext);
|
|
54
52
|
const size = useContext(ContainerContext);
|
|
55
53
|
|
|
56
|
-
const
|
|
57
|
-
const headerRef = useRef<Moment>(today.clone());
|
|
54
|
+
const headerRef = useRef<Moment>(moment());
|
|
58
55
|
const headerControlRef = useRef<HeaderControlRef>(null);
|
|
59
56
|
const monthListRef = useRef<MonthListRef>(null);
|
|
60
57
|
|
|
@@ -84,10 +81,6 @@ const CalendarPro = forwardRef<CalendarProRef, CalendarProProps>(
|
|
|
84
81
|
const [temp, setTemp] = useState<any[]>([]);
|
|
85
82
|
const [headerKey, setHeaderKey] = useState<string>('');
|
|
86
83
|
const [ownUpdate, setOwnUpdate] = useState<boolean>(false);
|
|
87
|
-
const converter: any = useMemo(
|
|
88
|
-
() => (new LunarDateConverter()),
|
|
89
|
-
[],
|
|
90
|
-
);
|
|
91
84
|
|
|
92
85
|
useImperativeHandle(ref, () => ({
|
|
93
86
|
setDoubleDateAndTabIndex: (
|
|
@@ -99,11 +92,6 @@ const CalendarPro = forwardRef<CalendarProRef, CalendarProProps>(
|
|
|
99
92
|
if (firstDate) setStartDate(firstDate);
|
|
100
93
|
if (secondDate !== undefined) setEndDate(secondDate);
|
|
101
94
|
},
|
|
102
|
-
setDateRange: (dateRange: { startDate: any; endDate: any }) => {
|
|
103
|
-
if (monthListRef.current && dateRange.startDate) {
|
|
104
|
-
monthListRef.current.scrollToMonth(moment(dateRange.startDate));
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
95
|
}));
|
|
108
96
|
|
|
109
97
|
// Sync showLunar prop
|
|
@@ -205,7 +193,12 @@ const CalendarPro = forwardRef<CalendarProRef, CalendarProProps>(
|
|
|
205
193
|
}
|
|
206
194
|
|
|
207
195
|
return (
|
|
208
|
-
<View
|
|
196
|
+
<View
|
|
197
|
+
style={[
|
|
198
|
+
styles.container,
|
|
199
|
+
{ backgroundColor: theme.colors.background.surface },
|
|
200
|
+
]}
|
|
201
|
+
>
|
|
209
202
|
<HeaderControl
|
|
210
203
|
ref={headerControlRef}
|
|
211
204
|
selectedDate={propSelectedDate}
|
|
@@ -218,11 +211,15 @@ const CalendarPro = forwardRef<CalendarProRef, CalendarProProps>(
|
|
|
218
211
|
{[1, 2, 3, 4, 5, 6, 7].map(dayIdx => (
|
|
219
212
|
<Text
|
|
220
213
|
key={dayIdx}
|
|
221
|
-
color={
|
|
214
|
+
color={
|
|
215
|
+
dayIdx >= 6
|
|
216
|
+
? theme.colors.error.primary
|
|
217
|
+
: theme.colors.text.default
|
|
218
|
+
}
|
|
222
219
|
typography="label_s_medium"
|
|
223
220
|
style={[
|
|
224
221
|
styles.textDay,
|
|
225
|
-
{ width: (size.width - Spacing.
|
|
222
|
+
{ width: (size.width - Spacing.S * 2) / 7 },
|
|
226
223
|
]}
|
|
227
224
|
>
|
|
228
225
|
{translate?.(Util.mapWeeKDate(dayIdx))}
|
|
@@ -231,7 +228,6 @@ const CalendarPro = forwardRef<CalendarProRef, CalendarProProps>(
|
|
|
231
228
|
</View>
|
|
232
229
|
<MonthList
|
|
233
230
|
ref={monthListRef}
|
|
234
|
-
today={today}
|
|
235
231
|
minDate={minDate}
|
|
236
232
|
maxDate={maxDate}
|
|
237
233
|
startDate={startDate!}
|
|
@@ -241,7 +237,6 @@ const CalendarPro = forwardRef<CalendarProRef, CalendarProProps>(
|
|
|
241
237
|
isShowLunar={!isOffLunar && showLunar}
|
|
242
238
|
isDoubleDateMode={isDoubleDateMode}
|
|
243
239
|
tabSelected={tabSelected}
|
|
244
|
-
lunarConverter={converter}
|
|
245
240
|
holidays={holidays}
|
|
246
241
|
selectedDate={propSelectedDate}
|
|
247
242
|
priceList={priceListFormat}
|
package/Day.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
exportFontFamily,
|
|
10
10
|
} from '@momo-kits/foundation';
|
|
11
11
|
import { DayProps } from './types';
|
|
12
|
-
import { ContainerContext } from './
|
|
12
|
+
import { ContainerContext } from './ContainerContext';
|
|
13
13
|
import styles from './styles';
|
|
14
14
|
|
|
15
15
|
const Day: React.FC<DayProps> = props => {
|
|
@@ -36,13 +36,12 @@ const Day: React.FC<DayProps> = props => {
|
|
|
36
36
|
|
|
37
37
|
const { theme } = useContext(ApplicationContext);
|
|
38
38
|
const size = useContext(ContainerContext);
|
|
39
|
-
const scaledHeight = useScaleSize(48);
|
|
40
39
|
const scaledSpacing = useScaleSize(Spacing.XS);
|
|
41
40
|
const scaledFontSize = useScaleSize(8);
|
|
42
41
|
const scaledLineHeight = useScaleSize(12);
|
|
43
42
|
const lunarFontFamily = exportFontFamily('regular');
|
|
44
43
|
|
|
45
|
-
const itemWidth = (size.width - Spacing.
|
|
44
|
+
const itemWidth = (size.width - Spacing.S * 2) / 7;
|
|
46
45
|
if (isEmpty || !date) {
|
|
47
46
|
return <View style={[styles.dayContainer, { width: itemWidth }]} />;
|
|
48
47
|
}
|
|
@@ -114,7 +113,6 @@ const Day: React.FC<DayProps> = props => {
|
|
|
114
113
|
paddingVertical: !!price ? Spacing.XS : Spacing.S,
|
|
115
114
|
},
|
|
116
115
|
(isStart || isEnd) && { backgroundColor: theme.colors.primary },
|
|
117
|
-
!!price && { height: scaledHeight },
|
|
118
116
|
{ height: size.height },
|
|
119
117
|
]}
|
|
120
118
|
disabled={!(isValid && isInScope)}
|
package/HeaderControl.tsx
CHANGED
|
@@ -7,7 +7,6 @@ import React, {
|
|
|
7
7
|
} from 'react';
|
|
8
8
|
import {TouchableOpacity, View} from 'react-native';
|
|
9
9
|
import moment from 'moment';
|
|
10
|
-
import Moment from 'moment';
|
|
11
10
|
import {ApplicationContext, Icon, Text} from '@momo-kits/foundation';
|
|
12
11
|
|
|
13
12
|
import Util from './Util';
|
|
@@ -19,7 +18,7 @@ const HeaderControl: ForwardRefRenderFunction<
|
|
|
19
18
|
HeaderControlProps
|
|
20
19
|
> = ({onPressBackArrow, onPressNextArrow, selectedDate}, ref) => {
|
|
21
20
|
const {translate} = useContext(ApplicationContext);
|
|
22
|
-
const [info, setInfo] = useState<{date:
|
|
21
|
+
const [info, setInfo] = useState<{date: moment.Moment}>({
|
|
23
22
|
date: moment(selectedDate || new Date()),
|
|
24
23
|
});
|
|
25
24
|
|
package/Month.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import moment, {Moment} from 'moment';
|
|
|
4
4
|
import Day from './Day';
|
|
5
5
|
import {useScaleSize, Spacing} from '@momo-kits/foundation';
|
|
6
6
|
import {MonthProps} from './types';
|
|
7
|
-
import {ContainerContext} from './
|
|
7
|
+
import {ContainerContext} from './ContainerContext';
|
|
8
8
|
|
|
9
9
|
const Month: React.FC<MonthProps> = ({
|
|
10
10
|
dateList,
|
package/MonthList.tsx
CHANGED
|
@@ -5,7 +5,6 @@ import React, {
|
|
|
5
5
|
useImperativeHandle,
|
|
6
6
|
useCallback,
|
|
7
7
|
useContext,
|
|
8
|
-
useEffect,
|
|
9
8
|
useLayoutEffect,
|
|
10
9
|
useMemo,
|
|
11
10
|
useRef,
|
|
@@ -17,7 +16,7 @@ import {
|
|
|
17
16
|
NativeSyntheticEvent,
|
|
18
17
|
Platform,
|
|
19
18
|
} from 'react-native';
|
|
20
|
-
import { ContainerContext } from './
|
|
19
|
+
import { ContainerContext } from './ContainerContext';
|
|
21
20
|
import LunarDateConverter from './LunarDateConverter';
|
|
22
21
|
import Month from './Month';
|
|
23
22
|
import { MonthListProps, MonthListRef } from './types';
|
|
@@ -39,15 +38,22 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
39
38
|
isShowLunar,
|
|
40
39
|
isDoubleDateMode,
|
|
41
40
|
disabledDays,
|
|
41
|
+
tabSelected,
|
|
42
|
+
onChoose,
|
|
43
|
+
bestPriceColor,
|
|
42
44
|
onScrollCalendar,
|
|
43
|
-
...restProps
|
|
44
45
|
} = props;
|
|
45
46
|
|
|
46
47
|
const size = useContext(ContainerContext);
|
|
47
48
|
const scaledHeight48 = useScaleSize(48);
|
|
48
49
|
const listRef = useRef<FlatList>(null);
|
|
49
50
|
const currentKey = useRef<string | null>(null);
|
|
51
|
+
const targetIndex = useRef<number | null>(null);
|
|
50
52
|
const [heightStyle, setHeightStyle] = useState({});
|
|
53
|
+
const onScrollCalendarRef = useRef(onScrollCalendar);
|
|
54
|
+
onScrollCalendarRef.current = onScrollCalendar;
|
|
55
|
+
const scaledHeight48Ref = useRef(scaledHeight48);
|
|
56
|
+
scaledHeight48Ref.current = scaledHeight48;
|
|
51
57
|
|
|
52
58
|
const data = useMemo(() => {
|
|
53
59
|
const months: { date: Moment; dateList: any[] }[] = [];
|
|
@@ -69,9 +75,6 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
69
75
|
}
|
|
70
76
|
while (cursor.month() === monthIdx) {
|
|
71
77
|
const cloned = cursor.clone();
|
|
72
|
-
const hol = holidays.find(
|
|
73
|
-
h => h.day === cloned.date() && h.month === cloned.month() + 1,
|
|
74
|
-
);
|
|
75
78
|
dayList.push({
|
|
76
79
|
isEmpty: false,
|
|
77
80
|
date: cloned,
|
|
@@ -80,8 +83,6 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
80
83
|
solarMonth: cloned.month() + 1,
|
|
81
84
|
solarYear: cloned.year(),
|
|
82
85
|
}),
|
|
83
|
-
isSolarHoliday: !!(hol && !hol.lunar),
|
|
84
|
-
isLunarHoliday: !!(hol && hol.lunar),
|
|
85
86
|
});
|
|
86
87
|
cursor.add(1, 'days');
|
|
87
88
|
}
|
|
@@ -96,7 +97,7 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
96
97
|
mMin.add(1, 'month');
|
|
97
98
|
}
|
|
98
99
|
return months;
|
|
99
|
-
}, [minDate, maxDate
|
|
100
|
+
}, [minDate, maxDate]);
|
|
100
101
|
|
|
101
102
|
const getIndexOfMonth = useCallback(
|
|
102
103
|
(date: Moment) => data.findIndex(item => item.date.isSame(date, 'month')),
|
|
@@ -138,6 +139,9 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
138
139
|
(month: Moment) => {
|
|
139
140
|
const idx = getIndexOfMonth(month);
|
|
140
141
|
if (listRef.current && idx !== -1) {
|
|
142
|
+
const offset = idx * pageWidth.current;
|
|
143
|
+
targetIndex.current =
|
|
144
|
+
Math.abs(offset - scrollOffset.current) < 1 ? null : idx;
|
|
141
145
|
listRef.current.scrollToIndex({ index: idx, animated: true });
|
|
142
146
|
}
|
|
143
147
|
},
|
|
@@ -146,29 +150,31 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
146
150
|
|
|
147
151
|
useImperativeHandle(ref, () => ({ scrollToMonth }));
|
|
148
152
|
|
|
149
|
-
useEffect(() => {
|
|
150
|
-
const timer = setTimeout(() => {
|
|
151
|
-
scrollToMonth(selectedDate);
|
|
152
|
-
}, 500);
|
|
153
|
-
return () => clearTimeout(timer);
|
|
154
|
-
}, []);
|
|
155
|
-
|
|
156
153
|
const onViewableItemsChanged = useRef(({ changed }: { changed: any[] }) => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
154
|
+
const visible = changed.find(token => token.isViewable);
|
|
155
|
+
if (targetIndex.current !== null && visible?.index !== targetIndex.current) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
targetIndex.current = null;
|
|
159
|
+
if (visible) {
|
|
160
|
+
const { item, key, index } = visible;
|
|
161
|
+
if (onScrollCalendarRef.current && item && currentKey.current !== key) {
|
|
160
162
|
currentKey.current = key;
|
|
161
163
|
try {
|
|
162
164
|
setHeightStyle({
|
|
163
165
|
height:
|
|
164
|
-
(
|
|
166
|
+
(scaledHeight48Ref.current * item.dateList.length) / 7 +
|
|
165
167
|
Spacing.L * 2 +
|
|
166
168
|
Spacing.XS,
|
|
167
169
|
});
|
|
168
170
|
} catch {
|
|
169
171
|
setHeightStyle({});
|
|
170
172
|
}
|
|
171
|
-
|
|
173
|
+
onScrollCalendarRef.current({
|
|
174
|
+
date: item.date,
|
|
175
|
+
key,
|
|
176
|
+
currentIndex: index,
|
|
177
|
+
});
|
|
172
178
|
}
|
|
173
179
|
}
|
|
174
180
|
}).current;
|
|
@@ -201,7 +207,6 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
201
207
|
const priceListDate = priceList?.[keyMonth]?.day;
|
|
202
208
|
return (
|
|
203
209
|
<Month
|
|
204
|
-
{...restProps}
|
|
205
210
|
key={index}
|
|
206
211
|
month={item.date}
|
|
207
212
|
dateList={item.dateList}
|
|
@@ -214,11 +219,13 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
214
219
|
isShowLunar={isShowLunar}
|
|
215
220
|
isDoubleDateMode={isDoubleDateMode}
|
|
216
221
|
disabledDays={disabledDays}
|
|
222
|
+
tabSelected={tabSelected}
|
|
223
|
+
onChoose={onChoose}
|
|
224
|
+
bestPriceColor={bestPriceColor}
|
|
217
225
|
/>
|
|
218
226
|
);
|
|
219
227
|
},
|
|
220
228
|
[
|
|
221
|
-
restProps,
|
|
222
229
|
priceList,
|
|
223
230
|
holidays,
|
|
224
231
|
minDate,
|
|
@@ -228,6 +235,9 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
228
235
|
isShowLunar,
|
|
229
236
|
isDoubleDateMode,
|
|
230
237
|
disabledDays,
|
|
238
|
+
tabSelected,
|
|
239
|
+
onChoose,
|
|
240
|
+
bestPriceColor,
|
|
231
241
|
],
|
|
232
242
|
);
|
|
233
243
|
|
|
@@ -244,6 +254,9 @@ const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
|
|
|
244
254
|
keyExtractor={keyExtractor}
|
|
245
255
|
onScrollToIndexFailed={() => {}}
|
|
246
256
|
onScroll={onScroll}
|
|
257
|
+
onScrollBeginDrag={() => {
|
|
258
|
+
targetIndex.current = null;
|
|
259
|
+
}}
|
|
247
260
|
scrollEnabled
|
|
248
261
|
initialNumToRender={3}
|
|
249
262
|
maxToRenderPerBatch={MAX_RENDER_PER_BATCH}
|
package/TabHeader.tsx
CHANGED
|
@@ -1,88 +1,73 @@
|
|
|
1
|
-
import React
|
|
2
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useContext,
|
|
4
|
+
useImperativeHandle,
|
|
5
|
+
useState,
|
|
6
|
+
} from 'react';
|
|
7
|
+
import { TouchableWithoutFeedback, View } from 'react-native';
|
|
3
8
|
import Moment from 'moment';
|
|
4
9
|
import Util from './Util';
|
|
5
10
|
import {
|
|
6
11
|
ApplicationContext,
|
|
7
|
-
Colors,
|
|
8
12
|
Radius,
|
|
9
13
|
Spacing,
|
|
10
14
|
Text,
|
|
11
15
|
} from '@momo-kits/foundation';
|
|
12
|
-
import {TabHeaderProps,
|
|
16
|
+
import { TabHeaderProps, TabHeaderRef } from './types';
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
defaultDate: Moment.Moment | null;
|
|
18
|
+
const TabHeader = forwardRef<TabHeaderRef, TabHeaderProps>((props, ref) => {
|
|
19
|
+
const { label, disabled, id, onChangeTab } = props;
|
|
20
|
+
const { theme, translate } = useContext(ApplicationContext);
|
|
21
|
+
const [active, setActive] = useState<boolean | undefined>(props.activeTab);
|
|
22
|
+
const [date, setDate] = useState<Moment.Moment | undefined>(
|
|
23
|
+
props.date ? Moment(props.date) : undefined,
|
|
24
|
+
);
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
26
|
+
useImperativeHandle(ref, () => ({
|
|
27
|
+
updateView: (nextDate, activeTab) => {
|
|
28
|
+
setDate(nextDate ? Moment(nextDate) : undefined);
|
|
29
|
+
setActive(activeTab);
|
|
30
|
+
},
|
|
31
|
+
setActiveTab: setActive,
|
|
32
|
+
}));
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
};
|
|
34
|
+
const weekday = (day: Moment.Moment) =>
|
|
35
|
+
translate?.(Util.WEEKDAYSFROMMOMENT[day.day()]);
|
|
36
|
+
const isHighlighted = active && !disabled;
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
date: date ? Moment(date) : undefined,
|
|
40
|
-
active: activeTab,
|
|
41
|
-
});
|
|
42
|
-
};
|
|
38
|
+
const formattedDate = date ? date.format('DD/MM/YYYY') : '';
|
|
39
|
+
const dayOfWeek = date ? `${weekday(date)}, ` : '';
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
return (
|
|
42
|
+
<TouchableWithoutFeedback
|
|
43
|
+
disabled={disabled}
|
|
44
|
+
onPress={() => onChangeTab?.(id)}
|
|
45
|
+
>
|
|
46
|
+
<View
|
|
47
|
+
style={[
|
|
48
|
+
{
|
|
49
|
+
flex: 1,
|
|
50
|
+
padding: Spacing.S,
|
|
51
|
+
borderRadius: Radius.S,
|
|
52
|
+
},
|
|
53
|
+
isHighlighted && {
|
|
54
|
+
backgroundColor: theme.colors.background.surface,
|
|
55
|
+
},
|
|
56
|
+
]}
|
|
57
|
+
>
|
|
58
|
+
<Text
|
|
59
|
+
typography={'description_default_regular'}
|
|
60
|
+
color={theme.colors.text.hint}
|
|
61
|
+
>
|
|
62
|
+
{translate?.(label)}
|
|
63
|
+
</Text>
|
|
64
|
+
<Text typography={'header_s_semibold'}>
|
|
65
|
+
{`${dayOfWeek || '--'} `}
|
|
66
|
+
{formattedDate || '--/--/----'}
|
|
67
|
+
</Text>
|
|
68
|
+
</View>
|
|
69
|
+
</TouchableWithoutFeedback>
|
|
70
|
+
);
|
|
71
|
+
});
|
|
47
72
|
|
|
48
|
-
|
|
49
|
-
const {label, disabled} = this.props;
|
|
50
|
-
const {date, active} = this.state;
|
|
51
|
-
const {theme, translate} = this.context;
|
|
52
|
-
const defaultDate = this.defaultDate;
|
|
53
|
-
const weekday = (day: Moment.Moment) =>
|
|
54
|
-
translate?.(Util.WEEKDAYSFROMMOMENT[day.day()]);
|
|
55
|
-
const isHighlighted = active && !disabled;
|
|
56
|
-
|
|
57
|
-
const formattedDateFromState = date ? date.format('DD/MM/YYYY') : '';
|
|
58
|
-
const formattedDateFromDefault = defaultDate?.format('DD/MM/YYYY') ?? '';
|
|
59
|
-
const dayOfWeekFromState = date ? `${weekday(date)}, ` : '';
|
|
60
|
-
const dayOfWeekFromDefault = defaultDate ? `${weekday(defaultDate)},` : '';
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
<TouchableWithoutFeedback disabled={disabled} onPress={this.onChangeTab}>
|
|
64
|
-
<View
|
|
65
|
-
style={[
|
|
66
|
-
{
|
|
67
|
-
flex: 1,
|
|
68
|
-
padding: Spacing.S,
|
|
69
|
-
borderRadius: Radius.S,
|
|
70
|
-
},
|
|
71
|
-
isHighlighted && {
|
|
72
|
-
backgroundColor: theme.colors.background.surface,
|
|
73
|
-
},
|
|
74
|
-
]}>
|
|
75
|
-
<Text
|
|
76
|
-
typography={'description_default_regular'}
|
|
77
|
-
color={Colors.black_12}>
|
|
78
|
-
{translate?.(label)}
|
|
79
|
-
</Text>
|
|
80
|
-
<Text typography={'header_s_semibold'}>
|
|
81
|
-
{`${dayOfWeekFromState || dayOfWeekFromDefault || '--'} `}
|
|
82
|
-
{formattedDateFromState || formattedDateFromDefault || '--/--/----'}
|
|
83
|
-
</Text>
|
|
84
|
-
</View>
|
|
85
|
-
</TouchableWithoutFeedback>
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
73
|
+
export default TabHeader;
|
package/Util.ts
CHANGED
|
@@ -3,50 +3,8 @@ import LunarDateConverter from './LunarDateConverter';
|
|
|
3
3
|
import holiday from './holidayData';
|
|
4
4
|
import {Holidays} from './types';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
w: ['', 'Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'],
|
|
9
|
-
weekday: [
|
|
10
|
-
'',
|
|
11
|
-
'Monday',
|
|
12
|
-
'Tuesday',
|
|
13
|
-
'Wednesday',
|
|
14
|
-
'Thursday',
|
|
15
|
-
'Friday',
|
|
16
|
-
'Saturday',
|
|
17
|
-
'Sunday',
|
|
18
|
-
],
|
|
19
|
-
text: {
|
|
20
|
-
start: 'Start',
|
|
21
|
-
end: 'End',
|
|
22
|
-
date: 'Date',
|
|
23
|
-
save: 'Save',
|
|
24
|
-
clear: 'Reset',
|
|
25
|
-
},
|
|
26
|
-
date: 'DD / MM',
|
|
27
|
-
},
|
|
28
|
-
vi: {
|
|
29
|
-
w: ['', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'CN'],
|
|
30
|
-
weekday: [
|
|
31
|
-
'',
|
|
32
|
-
'Thứ hai',
|
|
33
|
-
'Thứ ba',
|
|
34
|
-
'Thứ tư',
|
|
35
|
-
'Thứ năm',
|
|
36
|
-
'Thứ sáu',
|
|
37
|
-
'Thứ bảy',
|
|
38
|
-
'Chủ nhật',
|
|
39
|
-
],
|
|
40
|
-
text: {
|
|
41
|
-
start: 'Start',
|
|
42
|
-
end: 'End',
|
|
43
|
-
date: 'Date',
|
|
44
|
-
save: 'Save',
|
|
45
|
-
clear: 'Reset',
|
|
46
|
-
},
|
|
47
|
-
date: 'DD / MM',
|
|
48
|
-
},
|
|
49
|
-
};
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
const converter = new LunarDateConverter();
|
|
50
8
|
|
|
51
9
|
const Solar = (momentDate: moment.Moment) => ({
|
|
52
10
|
solarDay: momentDate.date(),
|
|
@@ -106,39 +64,8 @@ const sortByDate = (arr: Holidays[]): Holidays[] => {
|
|
|
106
64
|
};
|
|
107
65
|
|
|
108
66
|
const Utils = {
|
|
109
|
-
WEEKDAYS: ['T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'CN'],
|
|
110
|
-
|
|
111
67
|
WEEKDAYSFROMMOMENT: ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
|
|
112
68
|
|
|
113
|
-
WEEKDAYSNAME: [
|
|
114
|
-
'Thứ 2',
|
|
115
|
-
'Thứ 3',
|
|
116
|
-
'Thứ 4',
|
|
117
|
-
'Thứ 5',
|
|
118
|
-
'Thứ 6',
|
|
119
|
-
'Thứ 7',
|
|
120
|
-
'Chủ nhật',
|
|
121
|
-
],
|
|
122
|
-
|
|
123
|
-
MONTHS: [
|
|
124
|
-
'Tháng 1',
|
|
125
|
-
'Tháng 2',
|
|
126
|
-
'Tháng 3',
|
|
127
|
-
'Tháng 4',
|
|
128
|
-
'Tháng 5',
|
|
129
|
-
'Tháng 6',
|
|
130
|
-
'Tháng 7',
|
|
131
|
-
'Tháng 8',
|
|
132
|
-
'Tháng 9',
|
|
133
|
-
'Tháng 10',
|
|
134
|
-
'Tháng 11',
|
|
135
|
-
'Tháng 12',
|
|
136
|
-
],
|
|
137
|
-
|
|
138
|
-
MAX_ROWS: 7,
|
|
139
|
-
|
|
140
|
-
MAX_COLUMNS: 7,
|
|
141
|
-
|
|
142
69
|
mapWeeKDate(i: number) {
|
|
143
70
|
const date = ['', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];
|
|
144
71
|
return date[i];
|
|
@@ -162,36 +89,11 @@ const Utils = {
|
|
|
162
89
|
return month.get(i);
|
|
163
90
|
},
|
|
164
91
|
|
|
165
|
-
mapMonthShorten(i: number) {
|
|
166
|
-
const month = new Map([
|
|
167
|
-
[1, 'Jan'],
|
|
168
|
-
[2, 'Feb'],
|
|
169
|
-
[3, 'Mar'],
|
|
170
|
-
[4, 'Apr'],
|
|
171
|
-
[5, 'May'],
|
|
172
|
-
[6, 'Jun'],
|
|
173
|
-
[7, 'Jul'],
|
|
174
|
-
[8, 'Aug'],
|
|
175
|
-
[9, 'Sep'],
|
|
176
|
-
[10, 'Oct'],
|
|
177
|
-
[11, 'Nov'],
|
|
178
|
-
[12, 'Dec'],
|
|
179
|
-
]);
|
|
180
|
-
return month.get(i);
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
getDaysInMonth(month: number, year: number) {
|
|
184
|
-
const lastDayOfMonth = new Date(year, month + 1, 0);
|
|
185
|
-
return lastDayOfMonth.getDate();
|
|
186
|
-
},
|
|
187
|
-
|
|
188
92
|
/**
|
|
189
93
|
* Get sorted list of holidays within the given month.
|
|
190
94
|
*/
|
|
191
95
|
getHolidaysInMonth(headerInfo: moment.Moment): Holidays[] {
|
|
192
96
|
if (headerInfo) {
|
|
193
|
-
// @ts-ignore
|
|
194
|
-
const converter = new LunarDateConverter();
|
|
195
97
|
const startDate = moment(headerInfo).startOf('month');
|
|
196
98
|
const endDate = moment(headerInfo).endOf('month');
|
|
197
99
|
const minLunarDate = converter.SolarToLunar(Solar(startDate));
|
|
@@ -279,7 +181,6 @@ const Utils = {
|
|
|
279
181
|
}
|
|
280
182
|
return [];
|
|
281
183
|
},
|
|
282
|
-
I18N_MAP,
|
|
283
184
|
};
|
|
284
185
|
|
|
285
186
|
export default Utils;
|
package/index.tsx
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
2
|
-
import React, {
|
|
3
|
-
useState,
|
|
4
|
-
useRef,
|
|
5
|
-
useEffect,
|
|
6
|
-
useContext,
|
|
7
|
-
createContext,
|
|
8
|
-
} from 'react';
|
|
2
|
+
import React, { useState, useRef, useEffect, useContext } from 'react';
|
|
9
3
|
import { Dimensions, LayoutChangeEvent, View } from 'react-native';
|
|
10
4
|
import moment from 'moment';
|
|
11
5
|
import {
|
|
@@ -18,13 +12,12 @@ import {
|
|
|
18
12
|
} from '@momo-kits/foundation';
|
|
19
13
|
import CalendarPro from './CalendarPro';
|
|
20
14
|
import TabHeader from './TabHeader';
|
|
21
|
-
import { CalendarProps, CalendarProRef } from './types';
|
|
15
|
+
import { CalendarProps, CalendarProRef, TabHeaderRef } from './types';
|
|
16
|
+
import { ContainerContext } from './ContainerContext';
|
|
22
17
|
import styles from './styles';
|
|
23
18
|
|
|
24
19
|
const DOUBLE = 'doubleDate';
|
|
25
20
|
|
|
26
|
-
export const ContainerContext = createContext({ width: 0, height: 0 });
|
|
27
|
-
|
|
28
21
|
const Calendar: React.FC<CalendarProps> = props => {
|
|
29
22
|
const { translate, theme } = useContext(ApplicationContext);
|
|
30
23
|
const scaledHeight48 = useScaleSize(48);
|
|
@@ -49,9 +42,6 @@ const Calendar: React.FC<CalendarProps> = props => {
|
|
|
49
42
|
isHideHoliday,
|
|
50
43
|
isShowLunar,
|
|
51
44
|
priceList,
|
|
52
|
-
labelFrom,
|
|
53
|
-
labelTo,
|
|
54
|
-
isHideLabel,
|
|
55
45
|
minDate = minDateDefault,
|
|
56
46
|
maxDate = maxDateDefault,
|
|
57
47
|
style,
|
|
@@ -85,9 +75,9 @@ const Calendar: React.FC<CalendarProps> = props => {
|
|
|
85
75
|
|
|
86
76
|
const calendarPicker = useRef<CalendarProRef>(null);
|
|
87
77
|
// hold refs to TabHeader instances
|
|
88
|
-
const cellHeader1 = useRef<
|
|
89
|
-
const cellHeader2 = useRef<
|
|
90
|
-
const cellHeaderSingle = useRef<
|
|
78
|
+
const cellHeader1 = useRef<TabHeaderRef>(null);
|
|
79
|
+
const cellHeader2 = useRef<TabHeaderRef>(null);
|
|
80
|
+
const cellHeaderSingle = useRef<TabHeaderRef>(null);
|
|
91
81
|
|
|
92
82
|
// Initialize view on mount
|
|
93
83
|
useEffect(() => {
|
|
@@ -217,18 +207,11 @@ const Calendar: React.FC<CalendarProps> = props => {
|
|
|
217
207
|
const updateHeaderView = () => {
|
|
218
208
|
const { onDateChange, onCTAStateChange } = props;
|
|
219
209
|
if (isDoubleDateMode) {
|
|
220
|
-
cellHeader1.current?.updateView(selectedDate, true);
|
|
221
|
-
cellHeader2.current?.updateView(null, false);
|
|
222
|
-
calendarPicker.current?.setDoubleDateAndTabIndex(
|
|
223
|
-
selectedDate,
|
|
224
|
-
null,
|
|
225
|
-
tabSelected.current,
|
|
226
|
-
);
|
|
227
210
|
doubleDate.current.first = moment(selectedDate);
|
|
228
211
|
doubleDate.current.second = null;
|
|
229
212
|
tabSelected.current = 1;
|
|
230
|
-
|
|
231
|
-
|
|
213
|
+
cellHeader1.current?.updateView(selectedDate, false);
|
|
214
|
+
cellHeader2.current?.updateView(null, true);
|
|
232
215
|
calendarPicker.current?.setDoubleDateAndTabIndex(
|
|
233
216
|
doubleDate.current.first,
|
|
234
217
|
doubleDate.current.second,
|
|
@@ -237,16 +220,17 @@ const Calendar: React.FC<CalendarProps> = props => {
|
|
|
237
220
|
onCTAStateChange?.(false);
|
|
238
221
|
onDateChange?.({ first: doubleDate.current.first!, second: null });
|
|
239
222
|
} else {
|
|
240
|
-
|
|
223
|
+
const date = doubleDate.current.first ?? selectedDate;
|
|
241
224
|
doubleDate.current.second = null;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
225
|
+
tabSelected.current = 0;
|
|
226
|
+
calendarPicker.current?.setDoubleDateAndTabIndex(date, null, 0);
|
|
227
|
+
onCTAStateChange?.(true);
|
|
228
|
+
if (date.isSame(selectedDate, 'day')) {
|
|
229
|
+
cellHeaderSingle.current?.updateView(date, true);
|
|
230
|
+
onDateChange?.(date.toDate());
|
|
246
231
|
} else {
|
|
247
|
-
|
|
232
|
+
setSelectedDate(date);
|
|
248
233
|
}
|
|
249
|
-
props.onDateChange?.(selectedDate.toDate());
|
|
250
234
|
}
|
|
251
235
|
};
|
|
252
236
|
|
|
@@ -302,7 +286,7 @@ const Calendar: React.FC<CalendarProps> = props => {
|
|
|
302
286
|
activeTab
|
|
303
287
|
date={doubleDate.current.first}
|
|
304
288
|
/>
|
|
305
|
-
<View style={
|
|
289
|
+
<View style={styles.tabGap} />
|
|
306
290
|
<TabHeader
|
|
307
291
|
id={1}
|
|
308
292
|
ref={cellHeader2}
|
|
@@ -361,9 +345,6 @@ const Calendar: React.FC<CalendarProps> = props => {
|
|
|
361
345
|
selectedDate={selectedDate}
|
|
362
346
|
isShowLunar={isShowLunar}
|
|
363
347
|
onCallbackCalendar={onCallbackCalendar}
|
|
364
|
-
labelFrom={labelFrom}
|
|
365
|
-
labelTo={labelTo}
|
|
366
|
-
isHideLabel={isHideLabel}
|
|
367
348
|
minDate={minDate}
|
|
368
349
|
maxDate={maxDate}
|
|
369
350
|
isHideHoliday={isHideHoliday}
|
|
@@ -376,4 +357,4 @@ const Calendar: React.FC<CalendarProps> = props => {
|
|
|
376
357
|
);
|
|
377
358
|
};
|
|
378
359
|
|
|
379
|
-
export { Calendar };
|
|
360
|
+
export { Calendar, ContainerContext };
|
package/package.json
CHANGED
package/styles.ts
CHANGED
|
@@ -16,6 +16,10 @@ export default StyleSheet.create({
|
|
|
16
16
|
alignItems: 'center',
|
|
17
17
|
marginBottom: Spacing.XS,
|
|
18
18
|
},
|
|
19
|
+
tabGap: {
|
|
20
|
+
width: Spacing.XS,
|
|
21
|
+
height: '100%',
|
|
22
|
+
},
|
|
19
23
|
headerContainer: {
|
|
20
24
|
paddingHorizontal: Spacing.M,
|
|
21
25
|
marginTop: Spacing.S,
|
|
@@ -57,7 +61,6 @@ export default StyleSheet.create({
|
|
|
57
61
|
marginTop: Spacing.S,
|
|
58
62
|
},
|
|
59
63
|
container: {
|
|
60
|
-
backgroundColor: 'white',
|
|
61
64
|
borderRadius: Radius.XS,
|
|
62
65
|
},
|
|
63
66
|
blueSeperator: {
|
|
@@ -70,18 +73,6 @@ export default StyleSheet.create({
|
|
|
70
73
|
txtHeader: {
|
|
71
74
|
textAlign: 'center',
|
|
72
75
|
},
|
|
73
|
-
btnRight: {
|
|
74
|
-
width: 36,
|
|
75
|
-
height: 36,
|
|
76
|
-
justifyContent: 'center',
|
|
77
|
-
alignItems: 'center',
|
|
78
|
-
},
|
|
79
|
-
btnLeft: {
|
|
80
|
-
width: 36,
|
|
81
|
-
height: 36,
|
|
82
|
-
justifyContent: 'center',
|
|
83
|
-
alignItems: 'center',
|
|
84
|
-
},
|
|
85
76
|
headerControlContainer: {
|
|
86
77
|
flexDirection: 'row',
|
|
87
78
|
justifyContent: 'space-between',
|
|
@@ -101,9 +92,6 @@ export default StyleSheet.create({
|
|
|
101
92
|
alignItems: 'center',
|
|
102
93
|
borderRadius: Radius.XS,
|
|
103
94
|
},
|
|
104
|
-
dayText: {
|
|
105
|
-
textAlign: 'center',
|
|
106
|
-
},
|
|
107
95
|
dayStartContainer: {
|
|
108
96
|
borderTopLeftRadius: Radius.XS,
|
|
109
97
|
borderBottomLeftRadius: Radius.XS,
|
package/types.ts
CHANGED
|
@@ -42,9 +42,6 @@ export type CalendarProProps = {
|
|
|
42
42
|
isDoubleDateMode: boolean;
|
|
43
43
|
onDateChange: (day: Moment.Moment) => void;
|
|
44
44
|
priceList?: PriceListData;
|
|
45
|
-
labelFrom?: string;
|
|
46
|
-
labelTo?: string;
|
|
47
|
-
isHideLabel?: boolean;
|
|
48
45
|
isHideHoliday?: boolean;
|
|
49
46
|
isOffLunar?: boolean;
|
|
50
47
|
onCallbackCalendar?: (lunar: string, nextStateShowLunar: boolean) => void;
|
|
@@ -52,17 +49,6 @@ export type CalendarProProps = {
|
|
|
52
49
|
bestPriceColor?: string;
|
|
53
50
|
};
|
|
54
51
|
|
|
55
|
-
export type CalendarProState = {
|
|
56
|
-
startDate: Moment.Moment;
|
|
57
|
-
endDate: Moment.Moment;
|
|
58
|
-
showLunar?: boolean;
|
|
59
|
-
tabSelected?: number;
|
|
60
|
-
holidays: Holidays[];
|
|
61
|
-
ownUpdate?: boolean;
|
|
62
|
-
temp?: any;
|
|
63
|
-
headerKey?: string;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
52
|
export type DoubleDate = {
|
|
67
53
|
first: Moment.Moment;
|
|
68
54
|
second: Moment.Moment | null;
|
|
@@ -102,15 +88,6 @@ export type CalendarProRef = {
|
|
|
102
88
|
secondDate?: Moment.Moment | null,
|
|
103
89
|
tabSelected?: number,
|
|
104
90
|
) => void;
|
|
105
|
-
setDateRange: (
|
|
106
|
-
dateRange: { startDate: any; endDate: any },
|
|
107
|
-
isScrollToStartDate: any,
|
|
108
|
-
) => void;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
export type CalendarState = {
|
|
112
|
-
isDoubleDateMode: boolean;
|
|
113
|
-
containerWidth: number;
|
|
114
91
|
};
|
|
115
92
|
|
|
116
93
|
export type HeaderControlRef = {
|
|
@@ -134,23 +111,16 @@ export type MonthListProps = {
|
|
|
134
111
|
endDate: Moment.Moment;
|
|
135
112
|
isShowLunar: boolean;
|
|
136
113
|
tabSelected?: number;
|
|
137
|
-
today: Moment.Moment;
|
|
138
114
|
onChoose: (day: Moment.Moment) => void;
|
|
139
115
|
onScrollCalendar?: (info: {
|
|
140
116
|
date: Moment.Moment;
|
|
141
117
|
key: string;
|
|
142
118
|
currentIndex: number;
|
|
143
119
|
}) => void;
|
|
144
|
-
lunarConverter: any;
|
|
145
120
|
disabledDays?: Date[];
|
|
146
121
|
bestPriceColor?: string;
|
|
147
122
|
};
|
|
148
123
|
|
|
149
|
-
export type MonthListState = {
|
|
150
|
-
data?: any;
|
|
151
|
-
isDoubleDateMode?: boolean;
|
|
152
|
-
};
|
|
153
|
-
|
|
154
124
|
export type MonthListRef = {
|
|
155
125
|
scrollToMonth: (date: Moment.Moment) => void;
|
|
156
126
|
};
|
|
@@ -168,6 +138,8 @@ export type MonthProps = {
|
|
|
168
138
|
isDoubleDateMode: boolean;
|
|
169
139
|
disabledDays?: Date[];
|
|
170
140
|
bestPriceColor?: string;
|
|
141
|
+
tabSelected?: number;
|
|
142
|
+
onChoose?: (date: Moment.Moment) => void;
|
|
171
143
|
};
|
|
172
144
|
|
|
173
145
|
export type DayProps = {
|
|
@@ -192,9 +164,9 @@ export type DayProps = {
|
|
|
192
164
|
bestPriceColor?: string;
|
|
193
165
|
};
|
|
194
166
|
|
|
195
|
-
export type
|
|
196
|
-
|
|
197
|
-
|
|
167
|
+
export type TabHeaderRef = {
|
|
168
|
+
updateView: (date?: Moment.Moment | Date | null, activeTab?: boolean) => void;
|
|
169
|
+
setActiveTab: (active: boolean) => void;
|
|
198
170
|
};
|
|
199
171
|
|
|
200
172
|
export type TabHeaderProps = {
|
|
@@ -205,8 +177,3 @@ export type TabHeaderProps = {
|
|
|
205
177
|
id: number;
|
|
206
178
|
disabled?: boolean;
|
|
207
179
|
};
|
|
208
|
-
|
|
209
|
-
export type TabHeaderRef = {
|
|
210
|
-
updateView: (date?: Moment.Moment | null, activeTab?: boolean) => void;
|
|
211
|
-
setActiveTab: (active: boolean) => void;
|
|
212
|
-
};
|
package/LunarService.ts
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
const removeFractionalPart = (number: string | number) =>
|
|
2
|
-
parseInt(String(number));
|
|
3
|
-
|
|
4
|
-
/* Compute the (integral) Julian day number of day dd/mm/yyyy, i.e., the number
|
|
5
|
-
* of days between 1/1/4713 BC (Julian calendar) and dd/mm/yyyy.
|
|
6
|
-
* Formula from http://www.tondering.dk/claus/calendar.html
|
|
7
|
-
*/
|
|
8
|
-
const jdFromDate = (dd: number, mm: number, yy: number) => {
|
|
9
|
-
let a, y, m, jd;
|
|
10
|
-
a = removeFractionalPart((14 - mm) / 12);
|
|
11
|
-
y = yy + 4800 - a;
|
|
12
|
-
m = mm + 12 * a - 3;
|
|
13
|
-
jd =
|
|
14
|
-
dd +
|
|
15
|
-
removeFractionalPart((153 * m + 2) / 5) +
|
|
16
|
-
365 * y +
|
|
17
|
-
removeFractionalPart(y / 4) -
|
|
18
|
-
removeFractionalPart(y / 100) +
|
|
19
|
-
removeFractionalPart(y / 400) -
|
|
20
|
-
32045;
|
|
21
|
-
if (jd < 2299161) {
|
|
22
|
-
jd =
|
|
23
|
-
dd +
|
|
24
|
-
removeFractionalPart((153 * m + 2) / 5) +
|
|
25
|
-
365 * y +
|
|
26
|
-
removeFractionalPart(y / 4) -
|
|
27
|
-
32083;
|
|
28
|
-
}
|
|
29
|
-
return jd;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/* Compute the time of the k-th new moon after the new moon of 1/1/1900 13:52 UCT
|
|
33
|
-
* (measured as the number of days since 1/1/4713 BC noon UCT, e.g., 2451545.125 is 1/1/2000 15:00 UTC).
|
|
34
|
-
* Returns a floating number, e.g., 2415079.9758617813 for k=2 or 2414961.935157746 for k=-2
|
|
35
|
-
* Algorithm from: "Astronomical Algorithms" by Jean Meeus, 1998
|
|
36
|
-
*/
|
|
37
|
-
const NewMoon = (k: number) => {
|
|
38
|
-
let T, T2, T3, dr, Jd1, M, Mpr, F, C1, deltat, JdNew;
|
|
39
|
-
T = k / 1236.85; // Time in Julian centuries from 1900 January 0.5
|
|
40
|
-
T2 = T * T;
|
|
41
|
-
T3 = T2 * T;
|
|
42
|
-
dr = Math.PI / 180;
|
|
43
|
-
Jd1 = 2415020.75933 + 29.53058868 * k + 0.0001178 * T2 - 0.000000155 * T3;
|
|
44
|
-
Jd1 = Jd1 + 0.00033 * Math.sin((166.56 + 132.87 * T - 0.009173 * T2) * dr); // Mean new moon
|
|
45
|
-
M = 359.2242 + 29.10535608 * k - 0.0000333 * T2 - 0.00000347 * T3; // Sun's mean anomaly
|
|
46
|
-
Mpr = 306.0253 + 385.81691806 * k + 0.0107306 * T2 + 0.00001236 * T3; // Moon's mean anomaly
|
|
47
|
-
F = 21.2964 + 390.67050646 * k - 0.0016528 * T2 - 0.00000239 * T3; // Moon's argument of latitude
|
|
48
|
-
C1 =
|
|
49
|
-
(0.1734 - 0.000393 * T) * Math.sin(M * dr) + 0.0021 * Math.sin(2 * dr * M);
|
|
50
|
-
C1 = C1 - 0.4068 * Math.sin(Mpr * dr) + 0.0161 * Math.sin(dr * 2 * Mpr);
|
|
51
|
-
C1 = C1 - 0.0004 * Math.sin(dr * 3 * Mpr);
|
|
52
|
-
C1 = C1 + 0.0104 * Math.sin(dr * 2 * F) - 0.0051 * Math.sin(dr * (M + Mpr));
|
|
53
|
-
C1 =
|
|
54
|
-
C1 -
|
|
55
|
-
0.0074 * Math.sin(dr * (M - Mpr)) +
|
|
56
|
-
0.0004 * Math.sin(dr * (2 * F + M));
|
|
57
|
-
C1 =
|
|
58
|
-
C1 -
|
|
59
|
-
0.0004 * Math.sin(dr * (2 * F - M)) -
|
|
60
|
-
0.0006 * Math.sin(dr * (2 * F + Mpr));
|
|
61
|
-
C1 =
|
|
62
|
-
C1 +
|
|
63
|
-
0.001 * Math.sin(dr * (2 * F - Mpr)) +
|
|
64
|
-
0.0005 * Math.sin(dr * (2 * Mpr + M));
|
|
65
|
-
if (T < -11) {
|
|
66
|
-
deltat =
|
|
67
|
-
0.001 +
|
|
68
|
-
0.000839 * T +
|
|
69
|
-
0.0002261 * T2 -
|
|
70
|
-
0.00000845 * T3 -
|
|
71
|
-
0.000000081 * T * T3;
|
|
72
|
-
} else {
|
|
73
|
-
deltat = -0.000278 + 0.000265 * T + 0.000262 * T2;
|
|
74
|
-
}
|
|
75
|
-
JdNew = Jd1 + C1 - deltat;
|
|
76
|
-
return JdNew;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/* Compute the longitude of the sun at any time.
|
|
80
|
-
* Parameter: floating number jdn, the number of days since 1/1/4713 BC noon
|
|
81
|
-
* Algorithm from: "Astronomical Algorithms" by Jean Meeus, 1998
|
|
82
|
-
*/
|
|
83
|
-
const SunLongitude = (jdn: number) => {
|
|
84
|
-
let T, T2, dr, M, L0, DL, L;
|
|
85
|
-
T = (jdn - 2451545.0) / 36525; // Time in Julian centuries from 2000-01-01 12:00:00 GMT
|
|
86
|
-
T2 = T * T;
|
|
87
|
-
dr = Math.PI / 180; // degree to radian
|
|
88
|
-
M = 357.5291 + 35999.0503 * T - 0.0001559 * T2 - 0.00000048 * T * T2; // mean anomaly, degree
|
|
89
|
-
L0 = 280.46645 + 36000.76983 * T + 0.0003032 * T2; // mean longitude, degree
|
|
90
|
-
DL = (1.9146 - 0.004817 * T - 0.000014 * T2) * Math.sin(dr * M);
|
|
91
|
-
DL =
|
|
92
|
-
DL +
|
|
93
|
-
(0.019993 - 0.000101 * T) * Math.sin(dr * 2 * M) +
|
|
94
|
-
0.00029 * Math.sin(dr * 3 * M);
|
|
95
|
-
L = L0 + DL; // true longitude, degree
|
|
96
|
-
L = L * dr;
|
|
97
|
-
L = L - Math.PI * 2 * Math.sin(L / (Math.PI * 2)); // Normalize to (0, 2*PI)
|
|
98
|
-
return L;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
/* Compute sun position at midnight of the day with the given Julian day number.
|
|
102
|
-
* The time zone if the time difference between local time and UTC: 7.0 for UTC+7:00.
|
|
103
|
-
* The returns a number between 0 and 11.
|
|
104
|
-
* From the day after March equinox and the 1st major term after March equinox, 0 is returned.
|
|
105
|
-
* After that, return 1, 2, 3 ...
|
|
106
|
-
*/
|
|
107
|
-
const getSunLongitude = (dayNumber: number, timeZone: number) => {
|
|
108
|
-
return removeFractionalPart(
|
|
109
|
-
(SunLongitude(dayNumber - 0.5 - timeZone / 24) / Math.PI) * 6
|
|
110
|
-
);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
/* Compute the day of the k-th new moon in the given time zone.
|
|
114
|
-
* The time zone if the time difference between local time and UTC: 7.0 for UTC+7:00
|
|
115
|
-
*/
|
|
116
|
-
const getNewMoonDay = (k: number, timeZone: number) => {
|
|
117
|
-
return removeFractionalPart(NewMoon(k) + 0.5 + timeZone / 24);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
/* Find the day that starts the luner month 11 of the given year for the given time zone */
|
|
121
|
-
const getLunarMonth11 = (yy: number, timeZone: number) => {
|
|
122
|
-
let k, off, nm, sunLong;
|
|
123
|
-
//off = jdFromDate(31, 12, yy) - 2415021.076998695;
|
|
124
|
-
off = jdFromDate(31, 12, yy) - 2415021;
|
|
125
|
-
k = removeFractionalPart(off / 29.530588853);
|
|
126
|
-
nm = getNewMoonDay(k, timeZone);
|
|
127
|
-
sunLong = getSunLongitude(nm, timeZone); // sun longitude at local midnight
|
|
128
|
-
if (sunLong >= 9) {
|
|
129
|
-
nm = getNewMoonDay(k - 1, timeZone);
|
|
130
|
-
}
|
|
131
|
-
return nm;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
/* Find the index of the leap month after the month starting on the day a11. */
|
|
135
|
-
const getLeapMonthOffset = (a11: number, timeZone: number) => {
|
|
136
|
-
let k, last, arc, i;
|
|
137
|
-
k = removeFractionalPart((a11 - 2415021.076998695) / 29.530588853 + 0.5);
|
|
138
|
-
last = 0;
|
|
139
|
-
i = 1; // We start with the month following lunar month 11
|
|
140
|
-
arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);
|
|
141
|
-
do {
|
|
142
|
-
last = arc;
|
|
143
|
-
i++;
|
|
144
|
-
arc = getSunLongitude(getNewMoonDay(k + i, timeZone), timeZone);
|
|
145
|
-
} while (arc !== last && i < 14);
|
|
146
|
-
return i - 1;
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
/* Comvert solar date dd/mm/yyyy to the corresponding lunar date */
|
|
150
|
-
export const convertSolar2Lunar = (
|
|
151
|
-
dd: number,
|
|
152
|
-
mm: number,
|
|
153
|
-
yy: number,
|
|
154
|
-
timeZone: number
|
|
155
|
-
) => {
|
|
156
|
-
let k,
|
|
157
|
-
dayNumber,
|
|
158
|
-
monthStart,
|
|
159
|
-
a11,
|
|
160
|
-
b11,
|
|
161
|
-
lunarDay,
|
|
162
|
-
lunarMonth,
|
|
163
|
-
lunarYear,
|
|
164
|
-
lunarLeap;
|
|
165
|
-
dayNumber = jdFromDate(dd, mm, yy);
|
|
166
|
-
k = removeFractionalPart((dayNumber - 2415021.076998695) / 29.530588853);
|
|
167
|
-
monthStart = getNewMoonDay(k + 1, timeZone);
|
|
168
|
-
if (monthStart > dayNumber) {
|
|
169
|
-
monthStart = getNewMoonDay(k, timeZone);
|
|
170
|
-
}
|
|
171
|
-
//alert(dayNumber+" -> "+monthStart);
|
|
172
|
-
a11 = getLunarMonth11(yy, timeZone);
|
|
173
|
-
b11 = a11;
|
|
174
|
-
if (a11 >= monthStart) {
|
|
175
|
-
lunarYear = yy;
|
|
176
|
-
a11 = getLunarMonth11(yy - 1, timeZone);
|
|
177
|
-
} else {
|
|
178
|
-
lunarYear = yy + 1;
|
|
179
|
-
b11 = getLunarMonth11(yy + 1, timeZone);
|
|
180
|
-
}
|
|
181
|
-
lunarDay = dayNumber - monthStart + 1;
|
|
182
|
-
let diff = removeFractionalPart((monthStart - a11) / 29);
|
|
183
|
-
lunarLeap = 0;
|
|
184
|
-
lunarMonth = diff + 10;
|
|
185
|
-
if (b11 - a11 > 365) {
|
|
186
|
-
let leapMonthDiff = getLeapMonthOffset(a11, timeZone);
|
|
187
|
-
if (diff >= leapMonthDiff) {
|
|
188
|
-
lunarMonth = diff + 10;
|
|
189
|
-
if (diff === leapMonthDiff) {
|
|
190
|
-
lunarLeap = 1;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
if (lunarMonth > 12) {
|
|
195
|
-
lunarMonth = lunarMonth - 12;
|
|
196
|
-
}
|
|
197
|
-
if (lunarMonth >= 11 && diff < 4) {
|
|
198
|
-
lunarYear -= 1;
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
lunarDay,
|
|
202
|
-
lunarMonth: lunarMonth,
|
|
203
|
-
lunarYear,
|
|
204
|
-
isleap: lunarLeap,
|
|
205
|
-
};
|
|
206
|
-
};
|