@cleartrip/ct-design-calendar 4.0.0 → 5.0.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/dist/Arrow/LeftArrow.d.ts +3 -0
- package/dist/Arrow/LeftArrow.d.ts.map +1 -0
- package/dist/Arrow/RightArrow.d.ts +3 -0
- package/dist/Arrow/RightArrow.d.ts.map +1 -0
- package/dist/BaseCalendar.d.ts +4 -0
- package/dist/BaseCalendar.d.ts.map +1 -0
- package/dist/Calendar.d.ts +4 -0
- package/dist/Calendar.d.ts.map +1 -0
- package/dist/Calendar.native.d.ts +4 -0
- package/dist/Calendar.native.d.ts.map +1 -0
- package/dist/CalendarBody/LazyMonthList.d.ts +4 -0
- package/dist/CalendarBody/LazyMonthList.d.ts.map +1 -0
- package/dist/CalendarBody/PlaceholderMonth.d.ts +5 -0
- package/dist/CalendarBody/PlaceholderMonth.d.ts.map +1 -0
- package/dist/CalendarBody/index.d.ts +4 -0
- package/dist/CalendarBody/index.d.ts.map +1 -0
- package/dist/CalendarDayElements/CalendarDate.d.ts +4 -0
- package/dist/CalendarDayElements/CalendarDate.d.ts.map +1 -0
- package/dist/CalendarDayElements/CalendarDot.d.ts +4 -0
- package/dist/CalendarDayElements/CalendarDot.d.ts.map +1 -0
- package/dist/CalendarDayElements/CalendarDotWrapper.d.ts +5 -0
- package/dist/CalendarDayElements/CalendarDotWrapper.d.ts.map +1 -0
- package/dist/CalendarDayElements/CalendarRange.d.ts +4 -0
- package/dist/CalendarDayElements/CalendarRange.d.ts.map +1 -0
- package/dist/CalendarDayElements/index.d.ts +4 -0
- package/dist/CalendarDayElements/index.d.ts.map +1 -0
- package/dist/CalendarDayElements/useForceRerender.d.ts +5 -0
- package/dist/CalendarDayElements/useForceRerender.d.ts.map +1 -0
- package/dist/CalendarMonth/CalendarMonthBody.d.ts +4 -0
- package/dist/CalendarMonth/CalendarMonthBody.d.ts.map +1 -0
- package/dist/CalendarMonth/CalendarMonthFooter.d.ts +5 -0
- package/dist/CalendarMonth/CalendarMonthFooter.d.ts.map +1 -0
- package/dist/CalendarMonth/CalendarMonthHeader.d.ts +4 -0
- package/dist/CalendarMonth/CalendarMonthHeader.d.ts.map +1 -0
- package/dist/CalendarMonth/index.d.ts +12 -0
- package/dist/CalendarMonth/index.d.ts.map +1 -0
- package/dist/Caption/index.d.ts +4 -0
- package/dist/Caption/index.d.ts.map +1 -0
- package/dist/DayPicker.d.ts +62 -0
- package/dist/DayPicker.d.ts.map +1 -0
- package/dist/Footer/CheckinCheckout.d.ts +11 -0
- package/dist/Footer/CheckinCheckout.d.ts.map +1 -0
- package/dist/Footer/LongWeekend.d.ts +5 -0
- package/dist/Footer/LongWeekend.d.ts.map +1 -0
- package/dist/Footer/constants.d.ts +7 -0
- package/dist/Footer/constants.d.ts.map +1 -0
- package/dist/Footer/index.d.ts +14 -0
- package/dist/Footer/index.d.ts.map +1 -0
- package/dist/WeekDays.d.ts +3 -0
- package/dist/WeekDays.d.ts.map +1 -0
- package/dist/constants.d.ts +13 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/ct-design-calendar.browser.cjs.js +2 -0
- package/dist/ct-design-calendar.browser.cjs.js.map +1 -0
- package/dist/ct-design-calendar.browser.esm.js +2 -0
- package/dist/ct-design-calendar.browser.esm.js.map +1 -0
- package/dist/ct-design-calendar.cjs.js +67 -0
- package/dist/ct-design-calendar.cjs.js.map +1 -0
- package/dist/ct-design-calendar.esm.js +61 -0
- package/dist/ct-design-calendar.esm.js.map +1 -0
- package/dist/ct-design-calendar.umd.js +70 -0
- package/dist/ct-design-calendar.umd.js.map +1 -0
- package/dist/event/EventEmitter/index.d.ts +10 -0
- package/dist/event/EventEmitter/index.d.ts.map +1 -0
- package/dist/event/EventEmitter/type.d.ts +10 -0
- package/dist/event/EventEmitter/type.d.ts.map +1 -0
- package/dist/event/constants.d.ts +6 -0
- package/dist/event/constants.d.ts.map +1 -0
- package/dist/event/index.d.ts +8 -0
- package/dist/event/index.d.ts.map +1 -0
- package/dist/globalStyle.d.ts +2 -0
- package/dist/globalStyle.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/style.d.ts +2 -0
- package/dist/style.d.ts.map +1 -0
- package/dist/styles.d.ts +570 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/type.d.ts +58 -0
- package/dist/type.d.ts.map +1 -0
- package/dist/util.d.ts +22 -0
- package/dist/util.d.ts.map +1 -0
- package/package.json +32 -5
- package/src/Arrow/LeftArrow.tsx +13 -0
- package/src/Arrow/RightArrow.tsx +13 -0
- package/src/BaseCalendar.tsx +189 -0
- package/src/Calendar.native.tsx +99 -0
- package/src/Calendar.tsx +13 -0
- package/src/CalendarBody/LazyMonthList.tsx +45 -0
- package/src/CalendarBody/PlaceholderMonth.tsx +20 -0
- package/src/CalendarBody/index.tsx +159 -0
- package/src/CalendarDayElements/CalendarDate.tsx +34 -0
- package/src/CalendarDayElements/CalendarDot.tsx +11 -0
- package/src/CalendarDayElements/CalendarDotWrapper.tsx +17 -0
- package/src/CalendarDayElements/CalendarRange.tsx +54 -0
- package/src/CalendarDayElements/index.tsx +77 -0
- package/src/CalendarDayElements/useForceRerender.ts +14 -0
- package/src/CalendarMonth/CalendarMonthBody.tsx +39 -0
- package/src/CalendarMonth/CalendarMonthFooter.tsx +70 -0
- package/src/CalendarMonth/CalendarMonthHeader.tsx +15 -0
- package/src/CalendarMonth/index.tsx +43 -0
- package/src/Caption/index.tsx +39 -0
- package/src/DayPicker.tsx +324 -0
- package/src/Footer/CheckinCheckout.tsx +196 -0
- package/src/Footer/LongWeekend.tsx +98 -0
- package/src/Footer/constants.ts +7 -0
- package/src/Footer/index.tsx +84 -0
- package/src/WeekDays.tsx +20 -0
- package/src/constants.ts +54 -0
- package/src/event/EventEmitter/index.ts +34 -0
- package/src/event/EventEmitter/type.ts +10 -0
- package/src/event/constants.ts +5 -0
- package/src/event/index.tsx +21 -0
- package/src/globalStyle.ts +351 -0
- package/src/index.ts +3 -0
- package/src/style.ts +333 -0
- package/src/styles.ts +167 -0
- package/src/type.ts +66 -0
- package/src/util.ts +114 -0
package/dist/util.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const PAST_DATE = "2000-01-01";
|
|
2
|
+
export declare const DAY_MILLISECONDS: number;
|
|
3
|
+
export declare const TODAY_DATE: string;
|
|
4
|
+
export declare const MONTHS: string[];
|
|
5
|
+
export declare const ELEMENTS_HEIGHT: {
|
|
6
|
+
HEADING: number;
|
|
7
|
+
DATE: number;
|
|
8
|
+
FOOTER: number;
|
|
9
|
+
HOLIDAY: number;
|
|
10
|
+
};
|
|
11
|
+
export declare const DAY_LIST: {
|
|
12
|
+
day: string;
|
|
13
|
+
isWeekend: boolean;
|
|
14
|
+
}[];
|
|
15
|
+
export declare const formattedDate: (year: string, month: string, day: string) => string;
|
|
16
|
+
export declare const getWeekRow: (year: number, month: number) => number[][];
|
|
17
|
+
export declare const getMonthArray: (startMonth: number, startYear: number) => {
|
|
18
|
+
month: string;
|
|
19
|
+
year: string;
|
|
20
|
+
}[];
|
|
21
|
+
export declare const getDateDifference: (date1: string, date2: string) => number;
|
|
22
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../packages/components/Calendar/src/util.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,eAAe,CAAC;AAEtC,eAAO,MAAM,gBAAgB,QAAsB,CAAC;AAEpD,eAAO,MAAM,UAAU,QAA4D,CAAC;AAEpF,eAAO,MAAM,MAAM,UAalB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;CAK3B,CAAC;AAEF,eAAO,MAAM,QAAQ;;;GA6BpB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE,KAAK,MAAM,WAKrE,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,eAwBrD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,YAAY,MAAM,EAAE,WAAW,MAAM;WAC1C,MAAM;UAAQ,MAAM;GAc5C,CAAC;AACF,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,EAAE,OAAO,MAAM,WAK7D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,21 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleartrip/ct-design-calendar",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Calendar Component",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
|
-
"main": "dist/ct-design-calendar.cjs.js",
|
|
6
|
+
"main": "./dist/ct-design-calendar.cjs.js",
|
|
7
7
|
"jsnext:main": "dist/ct-design-calendar.esm.js",
|
|
8
|
+
"react-native": "src/index.ts",
|
|
8
9
|
"module": "dist/ct-design-calendar.esm.js",
|
|
9
10
|
"sideEffects": false,
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/ct-design-calendar.esm.js",
|
|
15
|
+
"default": "./dist/ct-design-calendar.cjs.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
10
18
|
"browser": {
|
|
11
19
|
"./dist/ct-design-calendar.esm.js": "./dist/ct-design-calendar.browser.esm.js",
|
|
12
20
|
"./dist/ct-design-calendar.cjs.js": "./dist/ct-design-calendar.browser.cjs.js"
|
|
13
21
|
},
|
|
14
22
|
"files": [
|
|
15
|
-
"dist"
|
|
23
|
+
"dist",
|
|
24
|
+
"src"
|
|
16
25
|
],
|
|
17
26
|
"dependencies": {
|
|
18
|
-
"
|
|
27
|
+
"react-day-picker": "8.8.1",
|
|
28
|
+
"react-tiny-virtual-list": "2.2.0",
|
|
29
|
+
"@cleartrip/ct-design-container": "5.0.0",
|
|
30
|
+
"@cleartrip/ct-design-theme": "5.0.0",
|
|
31
|
+
"@cleartrip/ct-design-accordion": "5.0.0",
|
|
32
|
+
"@cleartrip/ct-design-button": "5.0.0",
|
|
33
|
+
"@cleartrip/ct-design-badge": "5.0.0",
|
|
34
|
+
"@cleartrip/ct-design-typography": "5.0.0",
|
|
35
|
+
"@cleartrip/ct-design-icons": "5.0.0",
|
|
36
|
+
"@cleartrip/ct-design-common-utils": "5.0.0",
|
|
37
|
+
"@cleartrip/ct-design-style-manager": "5.0.0",
|
|
38
|
+
"@cleartrip/ct-design-types": "5.0.0",
|
|
39
|
+
"@cleartrip/ct-design-use-isomorphic-effect": "5.0.0",
|
|
40
|
+
"@cleartrip/ct-design-common-constants": "5.0.0",
|
|
41
|
+
"@cleartrip/ct-design-spacer": "5.0.0"
|
|
19
42
|
},
|
|
20
43
|
"devDependencies": {},
|
|
21
44
|
"peerDependencies": {
|
|
@@ -30,6 +53,10 @@
|
|
|
30
53
|
"license": "ISC",
|
|
31
54
|
"scripts": {
|
|
32
55
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
33
|
-
"
|
|
56
|
+
"watch-package": "rollup -c -w",
|
|
57
|
+
"build-package": "rollup -c",
|
|
58
|
+
"build-package:clean": "rm -rf dist && rollup -c",
|
|
59
|
+
"publish-package:local": "yalc publish --no-scripts",
|
|
60
|
+
"publish-package:local:registry": "pnpm publish --registry http://localhost:4873 --no-git-checks --access public"
|
|
34
61
|
}
|
|
35
62
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SVGProps } from 'react';
|
|
2
|
+
|
|
3
|
+
export function LeftArrow(props: SVGProps<SVGSVGElement>) {
|
|
4
|
+
return (
|
|
5
|
+
<svg viewBox='0 0 20 20' {...props}>
|
|
6
|
+
<path
|
|
7
|
+
d='M9.131 2L2.215 9.446a.821.821 0 00-.077 1.01l.077.098L9.131 18l1.106-1.108-5.67-6.106 13.43.02L18 9.21 4.586 9.19l5.65-6.082L9.132 2z'
|
|
8
|
+
fill='currentColor'
|
|
9
|
+
fillRule='nonzero'
|
|
10
|
+
/>
|
|
11
|
+
</svg>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SVGProps } from 'react';
|
|
2
|
+
|
|
3
|
+
export function RightArrow(props: SVGProps<SVGSVGElement>) {
|
|
4
|
+
return (
|
|
5
|
+
<svg viewBox='0 0 20 20' {...props}>
|
|
6
|
+
<path
|
|
7
|
+
d='M10.869 2l6.916 7.446a.821.821 0 01.077 1.01l-.077.098L10.869 18l-1.106-1.108 5.67-6.106-13.43.02L2 9.21l13.414-.02-5.65-6.082L10.868 2z'
|
|
8
|
+
fill='currentColor'
|
|
9
|
+
fillRule='nonzero'
|
|
10
|
+
/>
|
|
11
|
+
</svg>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
import dayjs from 'dayjs';
|
|
3
|
+
import { WEEK_DAY_LABEL } from '@cleartrip/ct-design-common-constants';
|
|
4
|
+
import { Container } from '@cleartrip/ct-design-container';
|
|
5
|
+
import { makeStyles, useStyles } from '@cleartrip/ct-design-style-manager';
|
|
6
|
+
|
|
7
|
+
import MobileCalendar, { DateRangeProps } from './DayPicker';
|
|
8
|
+
|
|
9
|
+
import useIsomorphicEffect from '@cleartrip/ct-design-use-isomorphic-effect';
|
|
10
|
+
import { ViewStyle } from '@cleartrip/ct-design-types';
|
|
11
|
+
|
|
12
|
+
const staticStyles = makeStyles((theme) => ({
|
|
13
|
+
outerWrapper: {
|
|
14
|
+
display: 'flex',
|
|
15
|
+
flexWrap: 'wrap',
|
|
16
|
+
},
|
|
17
|
+
weekDayHeader: {
|
|
18
|
+
display: 'flex',
|
|
19
|
+
alignItems: 'center',
|
|
20
|
+
justifyContent: 'center',
|
|
21
|
+
top: -1,
|
|
22
|
+
zIndex: 999,
|
|
23
|
+
paddingTop: theme.spacing[4],
|
|
24
|
+
paddingBottom: theme.spacing[4],
|
|
25
|
+
position: 'sticky' as ViewStyle['position'],
|
|
26
|
+
backgroundColor: theme.color.background.neutral,
|
|
27
|
+
height: 26,
|
|
28
|
+
borderBottom: `1px dotted ${theme.color.border.default}`,
|
|
29
|
+
},
|
|
30
|
+
weekDayItem: {
|
|
31
|
+
display: 'flex',
|
|
32
|
+
justifyContent: 'center',
|
|
33
|
+
},
|
|
34
|
+
weekendColor: {
|
|
35
|
+
// Add weekend specific styling if needed
|
|
36
|
+
// This can be enhanced based on design requirements
|
|
37
|
+
},
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
const Calendar = ({
|
|
41
|
+
onDateSelect,
|
|
42
|
+
noOfMonths,
|
|
43
|
+
mode,
|
|
44
|
+
customHeader,
|
|
45
|
+
onDayClick,
|
|
46
|
+
selectedDays,
|
|
47
|
+
disabledDays: disabledDaysProp,
|
|
48
|
+
defaultMonth,
|
|
49
|
+
modifiers,
|
|
50
|
+
modifierStyles,
|
|
51
|
+
footer,
|
|
52
|
+
customDay,
|
|
53
|
+
customSelectedDayProps,
|
|
54
|
+
asyncInitialScroll = false,
|
|
55
|
+
}: DateRangeProps) => {
|
|
56
|
+
const today = new Date();
|
|
57
|
+
|
|
58
|
+
const disabledDays = disabledDaysProp ?? [{ before: today }];
|
|
59
|
+
|
|
60
|
+
const elementRef = useRef<HTMLDivElement>(null);
|
|
61
|
+
|
|
62
|
+
const [width, setWidth] = useState(0);
|
|
63
|
+
|
|
64
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
65
|
+
|
|
66
|
+
const isInitialViewScrolled = useRef(false);
|
|
67
|
+
|
|
68
|
+
const getInitialDefaultDate = () => {
|
|
69
|
+
if (selectedDays && 'from' in selectedDays) {
|
|
70
|
+
const { from, to } = selectedDays;
|
|
71
|
+
if (from !== to) {
|
|
72
|
+
return from;
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
return selectedDays;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const initialDate = getInitialDefaultDate();
|
|
80
|
+
|
|
81
|
+
useIsomorphicEffect(() => {
|
|
82
|
+
let scrollTimeout: NodeJS.Timeout;
|
|
83
|
+
const scrollToSelectedRange = () => {
|
|
84
|
+
if (initialDate && containerRef.current) {
|
|
85
|
+
const targetMonthNode = containerRef.current.querySelector(`#Calendar${initialDate.getMonth()}`);
|
|
86
|
+
// Scroll the target month into view
|
|
87
|
+
if (targetMonthNode) {
|
|
88
|
+
targetMonthNode.scrollIntoView({
|
|
89
|
+
block: 'center',
|
|
90
|
+
});
|
|
91
|
+
isInitialViewScrolled.current = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
// Scroll to view only once when component is loaded
|
|
96
|
+
if (!isInitialViewScrolled.current) {
|
|
97
|
+
if (asyncInitialScroll) {
|
|
98
|
+
scrollTimeout = setTimeout(scrollToSelectedRange);
|
|
99
|
+
} else {
|
|
100
|
+
scrollToSelectedRange();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return () => {
|
|
104
|
+
if (scrollTimeout) {
|
|
105
|
+
clearTimeout(scrollTimeout);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}, [selectedDays, containerRef.current]);
|
|
109
|
+
|
|
110
|
+
useLayoutEffect(() => {
|
|
111
|
+
if (elementRef?.current) {
|
|
112
|
+
setWidth(elementRef.current.clientWidth);
|
|
113
|
+
}
|
|
114
|
+
}, []);
|
|
115
|
+
|
|
116
|
+
const dayDimension = width / 7;
|
|
117
|
+
|
|
118
|
+
const dynamicStyles = useStyles(
|
|
119
|
+
() => ({
|
|
120
|
+
weekDayItem: {
|
|
121
|
+
maxWidth: dayDimension,
|
|
122
|
+
width: width / 7,
|
|
123
|
+
},
|
|
124
|
+
weekendItem: {
|
|
125
|
+
maxWidth: dayDimension,
|
|
126
|
+
width: width / 7,
|
|
127
|
+
// Add weekend specific styling here if needed
|
|
128
|
+
// color: theme.color.text.secondary, // example
|
|
129
|
+
},
|
|
130
|
+
}),
|
|
131
|
+
[dayDimension, width],
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @todo Om To get the MobileCalendar component render here itself
|
|
136
|
+
*
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div ref={elementRef}>
|
|
141
|
+
{width > 0 && (
|
|
142
|
+
<Container styleConfig={{ root: [staticStyles.outerWrapper] }}>
|
|
143
|
+
<Container styleConfig={{ root: [staticStyles.weekDayHeader] }}>
|
|
144
|
+
{Object.keys(WEEK_DAY_LABEL).map((itm, key) => {
|
|
145
|
+
const isWeekend = key > 4;
|
|
146
|
+
return (
|
|
147
|
+
<Container
|
|
148
|
+
key={key}
|
|
149
|
+
styleConfig={{
|
|
150
|
+
root: [
|
|
151
|
+
staticStyles.weekDayItem,
|
|
152
|
+
...(isWeekend ? [staticStyles.weekendColor] : []),
|
|
153
|
+
isWeekend ? dynamicStyles.weekendItem : dynamicStyles.weekDayItem,
|
|
154
|
+
],
|
|
155
|
+
}}
|
|
156
|
+
>
|
|
157
|
+
{WEEK_DAY_LABEL[(key + 1) % 7]}
|
|
158
|
+
</Container>
|
|
159
|
+
);
|
|
160
|
+
})}
|
|
161
|
+
</Container>
|
|
162
|
+
<div ref={containerRef}>
|
|
163
|
+
<MobileCalendar
|
|
164
|
+
mode={mode}
|
|
165
|
+
noOfMonths={noOfMonths}
|
|
166
|
+
onDateSelect={onDateSelect}
|
|
167
|
+
onDayClick={onDayClick}
|
|
168
|
+
selectedDays={selectedDays}
|
|
169
|
+
disabledDays={disabledDays}
|
|
170
|
+
cellWidth={dayDimension}
|
|
171
|
+
cellHeight={dayDimension}
|
|
172
|
+
daySize={dayDimension}
|
|
173
|
+
defaultMonth={dayjs(initialDate).toDate()}
|
|
174
|
+
fromMonth={defaultMonth}
|
|
175
|
+
customHeader={customHeader}
|
|
176
|
+
modifiers={modifiers}
|
|
177
|
+
modifierStyles={modifierStyles}
|
|
178
|
+
footer={footer}
|
|
179
|
+
customDay={customDay}
|
|
180
|
+
customSelectedDayProps={customSelectedDayProps}
|
|
181
|
+
/>
|
|
182
|
+
</div>
|
|
183
|
+
</Container>
|
|
184
|
+
)}
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export default Calendar;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { memo, useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { usePubEvent } from './event';
|
|
4
|
+
import { makeStyles } from '@cleartrip/ct-design-style-manager';
|
|
5
|
+
import { View } from 'react-native';
|
|
6
|
+
|
|
7
|
+
import { ICalendarProps } from './type';
|
|
8
|
+
import CalendarBody from './CalendarBody';
|
|
9
|
+
import WeekDays from './WeekDays';
|
|
10
|
+
|
|
11
|
+
const staticCalendarStyles = makeStyles((theme) => {
|
|
12
|
+
return {
|
|
13
|
+
calendarContainer: {
|
|
14
|
+
backgroundColor: theme?.color.background.neutral,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const Calendar: React.FC<ICalendarProps> = ({
|
|
20
|
+
selectedDates: selectedDatesList,
|
|
21
|
+
handleCalendarDateClicked,
|
|
22
|
+
calendarDotsList,
|
|
23
|
+
holidayList,
|
|
24
|
+
}) => {
|
|
25
|
+
const selectedDates = [selectedDatesList[0]?.toString() || '', selectedDatesList[1]?.toString() || ''];
|
|
26
|
+
const selectedDatesRef = useRef<string[]>(selectedDates);
|
|
27
|
+
|
|
28
|
+
const publishDatesSelection = usePubEvent('SELECTED_DATES');
|
|
29
|
+
|
|
30
|
+
const getSelectedDates = useCallback(() => {
|
|
31
|
+
return selectedDatesRef.current;
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
const setSelectedDate = useCallback((dates: string[]) => {
|
|
35
|
+
publishDatesSelection({
|
|
36
|
+
oldDates: selectedDatesRef.current,
|
|
37
|
+
newDates: dates,
|
|
38
|
+
});
|
|
39
|
+
selectedDatesRef.current = dates ?? [];
|
|
40
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
43
|
+
const handleDateClicked = useCallback((date: string) => {
|
|
44
|
+
let response: string[] = [];
|
|
45
|
+
const reformattedDate = date.replace(/\//g, '-');
|
|
46
|
+
const prev = getSelectedDates();
|
|
47
|
+
switch (prev.filter((x) => x).length) {
|
|
48
|
+
case 0:
|
|
49
|
+
response = [date];
|
|
50
|
+
handleCalendarDateClicked({
|
|
51
|
+
checkInDate: new Date(reformattedDate),
|
|
52
|
+
stateDateType: 'checkOut',
|
|
53
|
+
});
|
|
54
|
+
break;
|
|
55
|
+
case 1:
|
|
56
|
+
if (date <= prev[0]) return;
|
|
57
|
+
response = [prev[0], date];
|
|
58
|
+
handleCalendarDateClicked({
|
|
59
|
+
checkInDate: new Date(prev[0].replace(/\//g, '-')),
|
|
60
|
+
checkOutDate: new Date(reformattedDate),
|
|
61
|
+
stateDateType: 'checkIn',
|
|
62
|
+
});
|
|
63
|
+
break;
|
|
64
|
+
case 2:
|
|
65
|
+
response = [date];
|
|
66
|
+
handleCalendarDateClicked({
|
|
67
|
+
checkInDate: new Date(reformattedDate),
|
|
68
|
+
stateDateType: 'checkOut',
|
|
69
|
+
});
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
setSelectedDate(response);
|
|
73
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
74
|
+
}, []);
|
|
75
|
+
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const [startDate = '', endDate = ''] = selectedDatesList;
|
|
78
|
+
const [currStartDate = '', currEndDate = ''] = selectedDatesRef.current;
|
|
79
|
+
if (startDate === currStartDate && endDate === currEndDate) return;
|
|
80
|
+
if (!startDate) return setSelectedDate([]);
|
|
81
|
+
if (!endDate) return setSelectedDate([startDate]);
|
|
82
|
+
setSelectedDate([startDate, endDate]);
|
|
83
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
84
|
+
}, [selectedDatesList]);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<View style={staticCalendarStyles?.calendarContainer}>
|
|
88
|
+
<WeekDays />
|
|
89
|
+
<CalendarBody
|
|
90
|
+
calendarDotsList={calendarDotsList}
|
|
91
|
+
getSelectedDates={getSelectedDates}
|
|
92
|
+
handleDateClicked={handleDateClicked}
|
|
93
|
+
holidayList={holidayList}
|
|
94
|
+
/>
|
|
95
|
+
</View>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export default memo(Calendar);
|
package/src/Calendar.tsx
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Container } from '@cleartrip/ct-design-container';
|
|
2
|
+
import { ICalendarProps } from './type';
|
|
3
|
+
|
|
4
|
+
const CalendarComponent: React.FC<ICalendarProps> = () => {
|
|
5
|
+
return (
|
|
6
|
+
<Container>
|
|
7
|
+
{/* Well what you need is to to migrate src/components/home/hotelCalendarContainer/calendar.tsx
|
|
8
|
+
biggest challenge is mapping types from aldenui to ct-design-system*/}
|
|
9
|
+
</Container>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default CalendarComponent;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { memo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { InteractionManager } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import PlaceholderMonth from './PlaceholderMonth';
|
|
6
|
+
import CalendarMonth from '../CalendarMonth';
|
|
7
|
+
import { ILazyMonthListProps } from '../type';
|
|
8
|
+
|
|
9
|
+
const LazyMonthList: React.FC<ILazyMonthListProps> = ({
|
|
10
|
+
monthList,
|
|
11
|
+
handleDateClicked,
|
|
12
|
+
getSelectedDates,
|
|
13
|
+
calendarDotsList,
|
|
14
|
+
holidayList,
|
|
15
|
+
monthHeightRef,
|
|
16
|
+
}) => {
|
|
17
|
+
const [rendered, setRendered] = useState(0);
|
|
18
|
+
return monthList.map((item, index) => {
|
|
19
|
+
if (index > rendered)
|
|
20
|
+
return (
|
|
21
|
+
<PlaceholderMonth
|
|
22
|
+
key={`lazyPlaceholderMonth-${index}`}
|
|
23
|
+
height={monthHeightRef.current[`${item.year}/${item.month}`]}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
return (
|
|
27
|
+
<CalendarMonth
|
|
28
|
+
onLayout={() => {
|
|
29
|
+
InteractionManager.runAfterInteractions(() => {
|
|
30
|
+
if (rendered < monthList.length) setRendered((prev) => prev + 1);
|
|
31
|
+
});
|
|
32
|
+
}}
|
|
33
|
+
key={`preceedingMonths-${index}`}
|
|
34
|
+
handleDateClicked={handleDateClicked}
|
|
35
|
+
getSelectedDates={getSelectedDates}
|
|
36
|
+
month={item.month}
|
|
37
|
+
year={item.year}
|
|
38
|
+
calendarDotsList={calendarDotsList}
|
|
39
|
+
holidayList={holidayList}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default memo(LazyMonthList);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { memo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import { staticCalendarBodyStyle } from '../styles';
|
|
6
|
+
|
|
7
|
+
const PlaceholderMonth = ({ height }: { height: number }) => {
|
|
8
|
+
return (
|
|
9
|
+
<View
|
|
10
|
+
style={[
|
|
11
|
+
staticCalendarBodyStyle?.placeholderMonthContainer,
|
|
12
|
+
{
|
|
13
|
+
height: height,
|
|
14
|
+
},
|
|
15
|
+
]}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default memo(PlaceholderMonth);
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { memo, useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { InteractionManager, ScrollView, View } from 'react-native';
|
|
4
|
+
import { useSubEvent } from '../event';
|
|
5
|
+
|
|
6
|
+
import CalendarMonth from '../CalendarMonth';
|
|
7
|
+
import { ELEMENTS_HEIGHT, formattedDate, getMonthArray, getWeekRow } from '../util';
|
|
8
|
+
import { ICalendarBodyProps, IMonthListObj } from '../type';
|
|
9
|
+
import { staticCalendarBodyStyle } from '../styles';
|
|
10
|
+
import LazyMonthList from './LazyMonthList';
|
|
11
|
+
import PlaceholderMonth from './PlaceholderMonth';
|
|
12
|
+
|
|
13
|
+
const CalendarBody: React.FC<ICalendarBodyProps> = ({
|
|
14
|
+
getSelectedDates,
|
|
15
|
+
handleDateClicked,
|
|
16
|
+
calendarDotsList,
|
|
17
|
+
holidayList,
|
|
18
|
+
}) => {
|
|
19
|
+
const [show, setShow] = useState(false);
|
|
20
|
+
const [isScrollAnimated, setIsScrollAnimated] = useState<boolean>(false);
|
|
21
|
+
const monthHeightRef = useRef<Record<string, number>>({});
|
|
22
|
+
const scrollViewRef = useRef<ScrollView>(null);
|
|
23
|
+
const currentDate = new Date();
|
|
24
|
+
const currentDay = currentDate.getDate();
|
|
25
|
+
const currentMonth = currentDate.getMonth() + 1;
|
|
26
|
+
const currentYear = currentDate.getFullYear();
|
|
27
|
+
const allMonths: IMonthListObj[] = getMonthArray(currentMonth, currentYear);
|
|
28
|
+
|
|
29
|
+
const getCalendarParts = () => {
|
|
30
|
+
const startDate =
|
|
31
|
+
getSelectedDates() && getSelectedDates().length > 0
|
|
32
|
+
? getSelectedDates()[0]
|
|
33
|
+
: formattedDate(currentYear.toString(), currentMonth.toString(), currentDay.toString());
|
|
34
|
+
let preceedingMonths: IMonthListObj[] = [];
|
|
35
|
+
let activeMonths: IMonthListObj[] = [];
|
|
36
|
+
let followingMonths: IMonthListObj[] = [];
|
|
37
|
+
|
|
38
|
+
if (getSelectedDates() && getSelectedDates().length > 0) {
|
|
39
|
+
const startMonthIndex = (12 + parseInt(startDate.split('/')[1]) - currentMonth) % 12;
|
|
40
|
+
preceedingMonths = allMonths.slice(0, startMonthIndex);
|
|
41
|
+
activeMonths = allMonths.slice(startMonthIndex, startMonthIndex + 2);
|
|
42
|
+
followingMonths = allMonths.slice(startMonthIndex + 2);
|
|
43
|
+
} else {
|
|
44
|
+
activeMonths = allMonths.slice(0, 2);
|
|
45
|
+
followingMonths = allMonths.slice(2);
|
|
46
|
+
}
|
|
47
|
+
return { preceedingMonths, activeMonths, followingMonths };
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const { preceedingMonths, activeMonths, followingMonths } = getCalendarParts();
|
|
51
|
+
const [renderedMonths, setRenderedMonths] = useState(0);
|
|
52
|
+
|
|
53
|
+
const storeMonthHeights = () => {
|
|
54
|
+
allMonths.forEach((item) => {
|
|
55
|
+
const rowCount = getWeekRow(parseInt(item.year), parseInt(item.month)).length;
|
|
56
|
+
monthHeightRef.current[`${item.year}/${item.month}`] =
|
|
57
|
+
rowCount * ELEMENTS_HEIGHT.DATE + ELEMENTS_HEIGHT.HEADING + ELEMENTS_HEIGHT.FOOTER;
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function getWeekOfMonth(dateString: string) {
|
|
62
|
+
const [year, month, day] = dateString.split(/[-/]/).map(Number);
|
|
63
|
+
const date = new Date(year, month - 1, day);
|
|
64
|
+
const firstDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay();
|
|
65
|
+
const mondayBasedOffset = (firstDay + 6) % 7;
|
|
66
|
+
return Math.ceil((date.getDate() + mondayBasedOffset) / 7);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const getScrollDelta = (fullDate: string[]) => {
|
|
70
|
+
const startDate = fullDate[0];
|
|
71
|
+
const [startYear, startMonth, _] = startDate.split('/');
|
|
72
|
+
const refStartKey = `${startYear}/${startMonth}`;
|
|
73
|
+
const startDateWeek = getWeekOfMonth(startDate);
|
|
74
|
+
let startDelta = startDateWeek > 3 ? startDateWeek * ELEMENTS_HEIGHT.DATE : 0;
|
|
75
|
+
Object.entries(monthHeightRef.current).forEach(([key, value]) => {
|
|
76
|
+
if (refStartKey > key) {
|
|
77
|
+
startDelta += value;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return startDelta;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
storeMonthHeights();
|
|
84
|
+
|
|
85
|
+
const scrollToSelectedDates = (newDates: string[]) => {
|
|
86
|
+
if (scrollViewRef.current && newDates.length > 0) {
|
|
87
|
+
const scrollOffset = getScrollDelta(newDates);
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
if (scrollViewRef.current) scrollViewRef.current.scrollTo({ y: scrollOffset, animated: isScrollAnimated });
|
|
90
|
+
setIsScrollAnimated(true);
|
|
91
|
+
}, 0);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
scrollToSelectedDates(getSelectedDates());
|
|
97
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
98
|
+
}, [getSelectedDates]);
|
|
99
|
+
|
|
100
|
+
useSubEvent('SELECTED_DATES', ({ newDates }: { newDates: string[] }) => {
|
|
101
|
+
scrollToSelectedDates(newDates);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<ScrollView showsVerticalScrollIndicator={false} ref={scrollViewRef} nestedScrollEnabled>
|
|
106
|
+
<LazyMonthList
|
|
107
|
+
show={show}
|
|
108
|
+
monthList={preceedingMonths}
|
|
109
|
+
handleDateClicked={handleDateClicked}
|
|
110
|
+
getSelectedDates={getSelectedDates}
|
|
111
|
+
calendarDotsList={calendarDotsList}
|
|
112
|
+
holidayList={holidayList}
|
|
113
|
+
monthHeightRef={monthHeightRef}
|
|
114
|
+
/>
|
|
115
|
+
{activeMonths.map((item, index) => {
|
|
116
|
+
if (index > renderedMonths)
|
|
117
|
+
return (
|
|
118
|
+
<PlaceholderMonth
|
|
119
|
+
key={`placeholderMonth-${index}`}
|
|
120
|
+
height={monthHeightRef.current[`${item.year}/${item.month}`]}
|
|
121
|
+
/>
|
|
122
|
+
);
|
|
123
|
+
return (
|
|
124
|
+
<CalendarMonth
|
|
125
|
+
onLayout={() => {
|
|
126
|
+
InteractionManager.runAfterInteractions(() => {
|
|
127
|
+
if (renderedMonths < activeMonths.length) setRenderedMonths((prev) => prev + 1);
|
|
128
|
+
});
|
|
129
|
+
if (index === activeMonths.length - 1) {
|
|
130
|
+
InteractionManager.runAfterInteractions(() => {
|
|
131
|
+
setShow(true);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}}
|
|
135
|
+
key={`activeMonths-${index}`}
|
|
136
|
+
handleDateClicked={handleDateClicked}
|
|
137
|
+
getSelectedDates={getSelectedDates}
|
|
138
|
+
month={item.month}
|
|
139
|
+
year={item.year}
|
|
140
|
+
calendarDotsList={calendarDotsList}
|
|
141
|
+
holidayList={holidayList}
|
|
142
|
+
/>
|
|
143
|
+
);
|
|
144
|
+
})}
|
|
145
|
+
<LazyMonthList
|
|
146
|
+
show={show}
|
|
147
|
+
monthList={followingMonths}
|
|
148
|
+
handleDateClicked={handleDateClicked}
|
|
149
|
+
getSelectedDates={getSelectedDates}
|
|
150
|
+
calendarDotsList={calendarDotsList}
|
|
151
|
+
holidayList={holidayList}
|
|
152
|
+
monthHeightRef={monthHeightRef}
|
|
153
|
+
/>
|
|
154
|
+
<View style={staticCalendarBodyStyle?.spacer} />
|
|
155
|
+
</ScrollView>
|
|
156
|
+
);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export default memo(CalendarBody);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { memo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useStyles } from '@cleartrip/ct-design-style-manager';
|
|
4
|
+
import { View } from 'react-native';
|
|
5
|
+
|
|
6
|
+
import CalendarDotWrapper from './CalendarDotWrapper';
|
|
7
|
+
import { getSelectedDateRootStyles, staticCalendarDateStyle } from '../styles';
|
|
8
|
+
import { ICalendarDateProp } from '../type';
|
|
9
|
+
import { Typography, TypographyColor, TypographyVariant } from '@cleartrip/ct-design-typography';
|
|
10
|
+
|
|
11
|
+
const CalendarDate: React.FC<ICalendarDateProp> = ({ day, date, isSelected, calendarDotsList }) => {
|
|
12
|
+
const dynamicCalendarDateStyles = useStyles(
|
|
13
|
+
(theme) => {
|
|
14
|
+
return {
|
|
15
|
+
root: getSelectedDateRootStyles(theme, isSelected),
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
[isSelected],
|
|
19
|
+
);
|
|
20
|
+
if (!day) return null;
|
|
21
|
+
|
|
22
|
+
const showDot = calendarDotsList.includes(date);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<View style={[staticCalendarDateStyle.root, dynamicCalendarDateStyles?.root]}>
|
|
26
|
+
<CalendarDotWrapper showDot={showDot} />
|
|
27
|
+
<Typography variant={TypographyVariant.P1} color={isSelected ? TypographyColor.NEUTRAL : TypographyColor.PRIMARY}>
|
|
28
|
+
{day}
|
|
29
|
+
</Typography>
|
|
30
|
+
</View>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default memo(CalendarDate);
|