daliry-mobile-date-picker 1.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/.editorconfig +10 -0
- package/.gitattributes +4 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/workspace.xml +813 -0
- package/.yarnrc.yml +1 -0
- package/README.md +26 -0
- package/build.js +15 -0
- package/dist/MobileDatePicker.d.ts +17 -0
- package/dist/index.css +54 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5282 -0
- package/package.json +30 -0
- package/src/MobileDatePicker.tsx +123 -0
- package/src/index.tsx +12 -0
- package/src/mobileDatePicker.css +59 -0
- package/tsconfig.json +18 -0
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "daliry-mobile-date-picker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"packageManager": "yarn@4.5.2",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/MobileDatePicker.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "node build.js && tsc"
|
|
10
|
+
},
|
|
11
|
+
"peerDependencies": {
|
|
12
|
+
"react": "^18.3.1",
|
|
13
|
+
"react-dom": "^18.3.1"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@alwatr/nano-build": "^5.5.0",
|
|
17
|
+
"moment-jalaali": "^0.10.4",
|
|
18
|
+
"react": "^18.3.1",
|
|
19
|
+
"react-dom": "^18.3.1"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/moment-jalaali": "^0.7.9",
|
|
23
|
+
"@types/react": "^19.0.10",
|
|
24
|
+
"@types/react-dom": "^19.0.4",
|
|
25
|
+
"esbuild": "^0.25.1"
|
|
26
|
+
},
|
|
27
|
+
"keywords": ["react", "datepicker", "jalali", "persian", "calendar"],
|
|
28
|
+
"author": "Mahdi Daliry",
|
|
29
|
+
"license": "MIT"
|
|
30
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { useState, useRef, useEffect } from "react";
|
|
2
|
+
import moment, { Moment } from "moment-jalaali";
|
|
3
|
+
import "./mobileDatePicker.css";
|
|
4
|
+
// export * from '.';
|
|
5
|
+
|
|
6
|
+
export interface IDate {
|
|
7
|
+
jYear: number;
|
|
8
|
+
jMonth: number;
|
|
9
|
+
jDay: number;
|
|
10
|
+
jDate: string;
|
|
11
|
+
date: string;
|
|
12
|
+
gDate: string;
|
|
13
|
+
moment: Moment;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface IMobileDatePicker {
|
|
17
|
+
onDateChange: (date: IDate) => void;
|
|
18
|
+
isBirthdate?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const jalaliMonths = [
|
|
22
|
+
"", "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور",
|
|
23
|
+
"مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", ""
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const years = Array.from({ length: 1308 }, (_, i) => 1308 + i);
|
|
27
|
+
const days = Array.from({ length: 33 }, (_, i) => i);
|
|
28
|
+
|
|
29
|
+
const MobileDatePicker = ({ onDateChange, isBirthdate = false }: IMobileDatePicker) => {
|
|
30
|
+
const today = moment();
|
|
31
|
+
const [selectedYear, setSelectedYear] = useState(isBirthdate ? 1388 : today.jYear() - 1);
|
|
32
|
+
const [selectedMonth, setSelectedMonth] = useState(isBirthdate ? 6 : today.jMonth());
|
|
33
|
+
const [selectedDay, setSelectedDay] = useState(isBirthdate ? 2 : today.jDate() - 1);
|
|
34
|
+
|
|
35
|
+
const listRef = useRef<HTMLDivElement>(null);
|
|
36
|
+
const listRefMonths = useRef<HTMLDivElement>(null);
|
|
37
|
+
const listRefDays = useRef<HTMLDivElement>(null);
|
|
38
|
+
|
|
39
|
+
const selectDateFunction = () => {
|
|
40
|
+
const gDate = moment(`${selectedYear}-${selectedMonth}-${selectedDay}`, "jYYYY-jMM-jDD").format("YYYY-MM-DD");
|
|
41
|
+
onDateChange({
|
|
42
|
+
jYear: selectedYear,
|
|
43
|
+
jMonth: selectedMonth,
|
|
44
|
+
jDay: selectedDay,
|
|
45
|
+
jDate: `${selectedYear}-${selectedMonth}-${selectedDay}`,
|
|
46
|
+
date: gDate,
|
|
47
|
+
gDate,
|
|
48
|
+
moment: moment(`${selectedYear}-${selectedMonth}-${selectedDay}`, "jYYYY-jMM-jDD"),
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (isBirthdate) selectDateFunction();
|
|
54
|
+
}, [selectedYear, selectedMonth, selectedDay]);
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
listRef.current?.scrollTo({ top: years.indexOf(selectedYear) * 45, behavior: "smooth" });
|
|
58
|
+
listRefMonths.current?.scrollTo({ top: selectedMonth * 45, behavior: "smooth" });
|
|
59
|
+
listRefDays.current?.scrollTo({ top: selectedDay * 45, behavior: "smooth" });
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
const handleScroll = () => {
|
|
63
|
+
const index = Math.round((listRef.current?.scrollTop || 0) / 45);
|
|
64
|
+
setSelectedYear(years[index + 1]);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const handleScrollMonths = () => {
|
|
68
|
+
const index = Math.round((listRefMonths.current?.scrollTop || 0) / 45);
|
|
69
|
+
setSelectedMonth(index + 1);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const handleScrollDays = () => {
|
|
73
|
+
const index = Math.round((listRefDays.current?.scrollTop || 0) / 45);
|
|
74
|
+
setSelectedDay(index + 1);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div className="datepicker-container">
|
|
79
|
+
<div className="scroll-lists">
|
|
80
|
+
<div className="scroll-list" onScroll={handleScrollDays} ref={listRefDays}>
|
|
81
|
+
{days.map((day, i) => (
|
|
82
|
+
<div
|
|
83
|
+
key={i}
|
|
84
|
+
className={`scroll-item ${day === selectedDay ? "selected" : ""}`}
|
|
85
|
+
>
|
|
86
|
+
{day}
|
|
87
|
+
</div>
|
|
88
|
+
))}
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div className="scroll-list" onScroll={handleScrollMonths} ref={listRefMonths}>
|
|
92
|
+
{jalaliMonths.map((month, i) => (
|
|
93
|
+
<div
|
|
94
|
+
key={i}
|
|
95
|
+
className={`scroll-item ${i === selectedMonth ? "selected" : ""}`}
|
|
96
|
+
>
|
|
97
|
+
{month}
|
|
98
|
+
</div>
|
|
99
|
+
))}
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div className="scroll-list" onScroll={handleScroll} ref={listRef}>
|
|
103
|
+
{years.map((year) => (
|
|
104
|
+
<div
|
|
105
|
+
key={year}
|
|
106
|
+
className={`scroll-item ${year === selectedYear ? "selected" : ""}`}
|
|
107
|
+
>
|
|
108
|
+
{year}
|
|
109
|
+
</div>
|
|
110
|
+
))}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
{!isBirthdate && (
|
|
115
|
+
<button className="apply-button" onClick={selectDateFunction}>
|
|
116
|
+
اعمال تاریخ
|
|
117
|
+
</button>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export default MobileDatePicker;
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
.datepicker-container {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: 16px;
|
|
6
|
+
width: 100%;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.scroll-lists {
|
|
10
|
+
display: flex;
|
|
11
|
+
justify-content: space-between;
|
|
12
|
+
background-color: #f5f5f5;
|
|
13
|
+
border-radius: 12px;
|
|
14
|
+
height: 152px;
|
|
15
|
+
width: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.scroll-list {
|
|
19
|
+
width: 110px;
|
|
20
|
+
height: 152px;
|
|
21
|
+
overflow-y: auto;
|
|
22
|
+
scroll-snap-type: y mandatory;
|
|
23
|
+
scrollbar-width: none;
|
|
24
|
+
-ms-overflow-style: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.scroll-list::-webkit-scrollbar {
|
|
28
|
+
display: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.scroll-item {
|
|
32
|
+
height: 45px;
|
|
33
|
+
line-height: 45px;
|
|
34
|
+
text-align: center;
|
|
35
|
+
scroll-snap-align: center;
|
|
36
|
+
color: #bbb;
|
|
37
|
+
font-size: 16px;
|
|
38
|
+
opacity: 0.5;
|
|
39
|
+
filter: blur(4px);
|
|
40
|
+
font-weight: normal;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.scroll-item.selected {
|
|
44
|
+
color: #333;
|
|
45
|
+
font-size: 20px;
|
|
46
|
+
font-weight: bold;
|
|
47
|
+
opacity: 1;
|
|
48
|
+
filter: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.apply-button {
|
|
52
|
+
padding: 10px 20px;
|
|
53
|
+
background-color: #1976d2;
|
|
54
|
+
color: white;
|
|
55
|
+
border: none;
|
|
56
|
+
border-radius: 8px;
|
|
57
|
+
font-size: 16px;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"declaration": true,
|
|
4
|
+
"emitDeclarationOnly": true,
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"jsx": "react-jsx",
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"module": "ESNext",
|
|
10
|
+
"target": "ESNext",
|
|
11
|
+
"moduleResolution": "Node",
|
|
12
|
+
"strict": true,
|
|
13
|
+
"baseUrl": "./src",
|
|
14
|
+
"allowSyntheticDefaultImports": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src"],
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|