react-native-nepali-picker 1.0.8 → 1.1.0-alpha.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.
Files changed (63) hide show
  1. package/lib/commonjs/CalendarPicker.js +89 -80
  2. package/lib/commonjs/CalendarPicker.js.map +1 -1
  3. package/lib/commonjs/DayCell.js +57 -0
  4. package/lib/commonjs/DayCell.js.map +1 -0
  5. package/lib/commonjs/calendar/config.js +1 -1
  6. package/lib/commonjs/calendar/functions.js +49 -17
  7. package/lib/commonjs/calendar/functions.js.map +1 -1
  8. package/lib/commonjs/calendar/settings.js +3 -1
  9. package/lib/commonjs/calendar/settings.js.map +1 -1
  10. package/lib/commonjs/calendar/validate.js +39 -0
  11. package/lib/commonjs/calendar/validate.js.map +1 -0
  12. package/lib/commonjs/index.js +13 -0
  13. package/lib/commonjs/index.js.map +1 -1
  14. package/lib/module/CalendarPicker.js +91 -82
  15. package/lib/module/CalendarPicker.js.map +1 -1
  16. package/lib/module/DayCell.js +52 -0
  17. package/lib/module/DayCell.js.map +1 -0
  18. package/lib/module/calendar/config.js +1 -1
  19. package/lib/module/calendar/functions.js +49 -17
  20. package/lib/module/calendar/functions.js.map +1 -1
  21. package/lib/module/calendar/settings.js +2 -0
  22. package/lib/module/calendar/settings.js.map +1 -1
  23. package/lib/module/calendar/validate.js +34 -0
  24. package/lib/module/calendar/validate.js.map +1 -0
  25. package/lib/module/index.js +1 -0
  26. package/lib/module/index.js.map +1 -1
  27. package/lib/typescript/commonjs/src/CalendarPicker.d.ts +1 -1
  28. package/lib/typescript/commonjs/src/CalendarPicker.d.ts.map +1 -1
  29. package/lib/typescript/commonjs/src/DayCell.d.ts +14 -0
  30. package/lib/typescript/commonjs/src/DayCell.d.ts.map +1 -0
  31. package/lib/typescript/commonjs/src/calendar/functions.d.ts +1 -1
  32. package/lib/typescript/commonjs/src/calendar/functions.d.ts.map +1 -1
  33. package/lib/typescript/commonjs/src/calendar/settings.d.ts +2 -0
  34. package/lib/typescript/commonjs/src/calendar/settings.d.ts.map +1 -1
  35. package/lib/typescript/commonjs/src/calendar/validate.d.ts +2 -0
  36. package/lib/typescript/commonjs/src/calendar/validate.d.ts.map +1 -0
  37. package/lib/typescript/commonjs/src/index.d.ts +1 -0
  38. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  39. package/lib/typescript/commonjs/src/types.d.ts +3 -1
  40. package/lib/typescript/commonjs/src/types.d.ts.map +1 -1
  41. package/lib/typescript/module/src/CalendarPicker.d.ts +1 -1
  42. package/lib/typescript/module/src/CalendarPicker.d.ts.map +1 -1
  43. package/lib/typescript/module/src/DayCell.d.ts +14 -0
  44. package/lib/typescript/module/src/DayCell.d.ts.map +1 -0
  45. package/lib/typescript/module/src/calendar/functions.d.ts +1 -1
  46. package/lib/typescript/module/src/calendar/functions.d.ts.map +1 -1
  47. package/lib/typescript/module/src/calendar/settings.d.ts +2 -0
  48. package/lib/typescript/module/src/calendar/settings.d.ts.map +1 -1
  49. package/lib/typescript/module/src/calendar/validate.d.ts +2 -0
  50. package/lib/typescript/module/src/calendar/validate.d.ts.map +1 -0
  51. package/lib/typescript/module/src/index.d.ts +1 -0
  52. package/lib/typescript/module/src/index.d.ts.map +1 -1
  53. package/lib/typescript/module/src/types.d.ts +3 -1
  54. package/lib/typescript/module/src/types.d.ts.map +1 -1
  55. package/package.json +1 -1
  56. package/src/CalendarPicker.tsx +111 -119
  57. package/src/DayCell.tsx +70 -0
  58. package/src/calendar/config.ts +1 -1
  59. package/src/calendar/functions.ts +59 -17
  60. package/src/calendar/settings.ts +2 -0
  61. package/src/calendar/validate.tsx +37 -0
  62. package/src/index.tsx +1 -0
  63. package/src/types.ts +3 -1
@@ -1,13 +1,16 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useCallback, useEffect, useMemo, useState, useRef } from 'react';
2
2
  import {
3
- View,
4
- Text,
5
3
  Modal,
6
4
  Pressable,
5
+ ScrollView,
7
6
  StyleSheet,
7
+ Text,
8
8
  TouchableOpacity,
9
- ScrollView,
9
+ View,
10
10
  } from 'react-native';
11
+ import DateSyncLogo from './assets/DateSync';
12
+ import { ChevronIcon } from './assets/Icons';
13
+ import Triangle from './assets/Triangle';
11
14
  import {
12
15
  bs,
13
16
  daysInEnglish,
@@ -16,12 +19,11 @@ import {
16
19
  monthsInEnglish,
17
20
  monthsInNepali,
18
21
  } from './calendar/config';
19
- import { calcFirstDay, isToday } from './calendar/settings';
20
- import { NepaliToday, validateDate } from './calendar/functions';
21
- import { ChevronIcon } from './assets/Icons';
22
- import DateSyncLogo from './assets/DateSync';
23
- import Triangle from './assets/Triangle';
22
+ import { NepaliToday } from './calendar/functions';
23
+ import { calcFirstDay, NEPALI_MAX_YEAR, NEPALI_MIN_YEAR } from './calendar/settings';
24
+ import DayCell from './DayCell'
24
25
  import type { CalendarPickerProps } from './types';
26
+ import { validateCalendarDates } from './calendar/validate';
25
27
 
26
28
  const CalendarPicker = ({
27
29
  visible,
@@ -29,7 +31,9 @@ const CalendarPicker = ({
29
31
  theme = 'light',
30
32
  onDateSelect,
31
33
  language = 'np',
32
- initialDate = NepaliToday(),
34
+ date = NepaliToday(),
35
+ minDate = '2000-01-01',
36
+ maxDate = '2099-12-30',
33
37
  brandColor = '#2081b9',
34
38
  titleTextStyle = {
35
39
  fontSize: 20,
@@ -44,17 +48,17 @@ const CalendarPicker = ({
44
48
  fontWeight: '600',
45
49
  },
46
50
  }: CalendarPickerProps) => {
47
- const value = validateDate(initialDate);
48
- console.log('the initial date is ', initialDate);
49
- const [TodayNepaliDate, setTodayNepaliDate] = useState(initialDate);
50
- const cYear = parseInt(TodayNepaliDate.split('-')[0], 10);
51
- const cMonth = parseInt(TodayNepaliDate.split('-')[1], 10);
52
- const cDay = parseInt(TodayNepaliDate.split('-')[2], 10);
53
-
54
- const [firstDayOfMonth, setFirstDayOfMonth] = useState<number>(0);
51
+ const yearModelScrollRef = useRef<ScrollView>(null)
52
+
53
+ const value = validateCalendarDates(date, minDate, maxDate);
54
+
55
+ const [userSelectedDate, setUserSelectedDate] = useState(date);
56
+ const cYear = parseInt(userSelectedDate.split('-')[0], 10);
57
+ const cMonth = parseInt(userSelectedDate.split('-')[1], 10);
58
+ const cDay = parseInt(userSelectedDate.split('-')[2], 10);
59
+
55
60
  const [month, setMonth] = useState<number>(cMonth);
56
61
  const [year, setYear] = useState<number>(cYear);
57
- const [calendarDate, setCalendarDate] = useState<(number | null)[]>([]);
58
62
 
59
63
  const [yearModal, setYearModal] = useState<boolean>(false);
60
64
 
@@ -63,21 +67,42 @@ const CalendarPicker = ({
63
67
  setYear(cYear);
64
68
  };
65
69
 
66
- const handleDateClick = (day: number) => {
70
+ const handleDateClick = useCallback((day: number) => {
67
71
  const date = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
68
- setTodayNepaliDate(date);
72
+ setUserSelectedDate(date);
69
73
  onDateSelect(date);
70
74
  onClose();
71
- };
75
+ }, [year, month, onDateSelect, onClose]);
72
76
 
77
+ //check weather the date is disabled or not?(with maximum and minimum date provided)
78
+ const isDateDisabled = useCallback((day: number) => {
79
+ const date = `${year}-${month
80
+ .toString()
81
+ .padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
82
+
83
+ if (minDate && date < minDate) return true;
84
+ if (maxDate && date > maxDate) return true;
85
+
86
+ return false;
87
+
88
+ }, [year, month, minDate, maxDate])
89
+
90
+ // Set the user selected date is as NepaliDate (initially it will be always
91
+ // current Nepali Date)
73
92
  useEffect(() => {
74
- setTodayNepaliDate(initialDate);
75
- }, [initialDate]);
93
+ setUserSelectedDate(date);
94
+ }, [date]);
95
+
96
+ // It will calculate the current date number
97
+ const selectedDay = useMemo(() => {
98
+ const [y, m, d] = userSelectedDate.split('-').map(Number);
99
+ return y === year && m === month ? d : null;
100
+ }, [userSelectedDate, year, month]);
76
101
 
77
- //Handle Next Month Click
102
+ //Handle Next Month button Click
78
103
  const handleNextClick = () => {
79
104
  if (month === 12) {
80
- if (year < 2099) {
105
+ if (year < NEPALI_MAX_YEAR) {
81
106
  setYear((prev) => prev + 1);
82
107
  setMonth(1);
83
108
  }
@@ -86,10 +111,10 @@ const CalendarPicker = ({
86
111
  }
87
112
  };
88
113
 
89
- //Handle Previous Month Click
114
+ //Handle Previous Month button Click
90
115
  const handlePreviousClick = () => {
91
116
  if (month === 1) {
92
- if (year > 2000) {
117
+ if (year > NEPALI_MIN_YEAR) {
93
118
  setYear((prev) => prev - 1);
94
119
  setMonth(12);
95
120
  }
@@ -98,39 +123,54 @@ const CalendarPicker = ({
98
123
  }
99
124
  };
100
125
 
101
- const openYearView = () => {
126
+ //open the model which shows the list of years(2000-2099)BS
127
+ const openYearView = async () => {
102
128
  setYearModal(true);
129
+
130
+ //wait for model to open completely before to scroll down
131
+ await new Promise((resolve) => setTimeout(resolve, 10))
132
+ // After model is opened, need ot scrolldown to that year
133
+ // Here we need to calculate (roughly) how much to scroll to keep the seelcted year in
134
+ // focus
135
+ // - For that we take the height of the year button and one row contain around 3-5(
136
+ // we will take 4) column of buttons so,
137
+ // approx Height = (year number(82 for 2082) * button height)/cloumn number
138
+ // NOTE: This is approx just to make the button visible when model is opened.
139
+ const vHeight = (year - NEPALI_MIN_YEAR) * 36 / 4
140
+ yearModelScrollRef.current?.scrollTo({
141
+ y: vHeight,
142
+ animated: true
143
+ })
144
+
103
145
  };
104
146
 
147
+ //close the year view model
105
148
  const closeYearView = () => {
106
149
  setYearModal(false);
107
150
  };
108
151
 
109
- useEffect(() => {
110
- // calculate First Day Of Month (FDOM) and Days In Month(DIM)
152
+
153
+ // Calculating the number of cells on that month and year(Max it can have 42 cells)
154
+ // If the cells don't have the date, it will be null otherwise it will contain the actual
155
+ // date number (1,2,3...upto 32)
156
+ const calendarDate = useMemo(() => {
111
157
  const FDOM = calcFirstDay(year, month);
112
158
  const DIM = bs[year][month];
113
- setFirstDayOfMonth(FDOM);
114
-
115
- // array which contain 42 cells and it only fill the date with number if the date is present otherwise it fill cells with null.
116
- const calendarCells = Array.from({ length: 42 }, (_, index) => {
117
- const dayNumber = index - FDOM + 1;
118
- if (dayNumber > 0 && dayNumber <= DIM) {
119
- return dayNumber;
120
- } else {
121
- return null;
122
- }
123
- });
124
- setCalendarDate(calendarCells);
125
- }, [year, month, initialDate]);
159
+ return Array.from({ length: 42 }, (_, index) => {
160
+ const dayNum = index - FDOM + 1
161
+ return dayNum > 0 && dayNum <= DIM ? dayNum : null
162
+ })
163
+ }, [year, month])
126
164
 
127
165
  const handleYearClick = (y: number) => {
128
166
  setYear(y);
129
167
  closeYearView();
130
168
  };
169
+
131
170
  const dark = theme === 'dark';
132
171
  const weekDays = language === 'en' ? daysInEnglish : daysInNepali;
133
172
 
173
+ // If the user prvided (initial value ) is not in correct format i.e (YYYY-MM-DD)
134
174
  if (value !== true) {
135
175
  return (
136
176
  <Modal visible={visible} onRequestClose={onClose} transparent={true}>
@@ -154,7 +194,7 @@ const CalendarPicker = ({
154
194
  paddingVertical: 10,
155
195
  }}
156
196
  >
157
- Unsupported date range on initialDate
197
+ Unsupported date range on Provided Date
158
198
  </Text>
159
199
  <Text
160
200
  style={{
@@ -187,7 +227,7 @@ const CalendarPicker = ({
187
227
  paddingHorizontal: 10,
188
228
  }}
189
229
  >
190
- {language === 'np' ? 'आजको मिति ' : "Today's Date"}
230
+ {language === 'np' ? 'तपाईंको मिति ' : "Selected Date"}
191
231
  </Text>
192
232
  {/* Today date in large fonts on click sync the calenar with today date */}
193
233
  <View
@@ -304,67 +344,30 @@ const CalendarPicker = ({
304
344
  </View>
305
345
 
306
346
  {/* for actual data fo calenadr which has the day in them */}
347
+
307
348
  <View style={styles.datesContainer}>
308
- {calendarDate.map((dayItem, index) => {
309
- return (
310
- <TouchableOpacity
311
- style={styles.dateItem}
312
- key={index}
313
- onPress={
314
- //execute on day item press, Only execute when dayItem is not null
315
- dayItem ? () => handleDateClick(dayItem) : () => { }
316
- }
317
- >
318
- {dayItem ? (
319
- <View
320
- style={{
321
- paddingHorizontal: 6,
322
- paddingVertical: 3,
323
- borderRadius: 999,
324
- //check if the date is today or not and apply conditional styling.
325
- backgroundColor: isToday(
326
- TodayNepaliDate,
327
- index,
328
- year,
329
- month,
330
- firstDayOfMonth
331
- )
332
- ? brandColor
333
- : dark
334
- ? '#383838'
335
- : '#fff',
336
- }}
337
- >
338
- <Text
339
- style={{
340
- ...dayTextStyle,
341
- color: isToday(
342
- TodayNepaliDate,
343
- index,
344
- year,
345
- month,
346
- firstDayOfMonth
347
- )
348
- ? '#fff'
349
- : dark
350
- ? 'white'
351
- : 'black',
352
- }}
353
- >
354
- {language === 'np'
355
- ? getNepaliNumber(dayItem)
356
- : dayItem}
357
- </Text>
358
- </View>
359
- ) : null}
360
- </TouchableOpacity>
361
- );
362
- })}
349
+ {calendarDate.map((day, index) => (
350
+ <DayCell
351
+ key={index}
352
+ day={day}
353
+ isSelectedDay={day !== null && day === selectedDay}
354
+ disabled={day !== null && isDateDisabled(day)}
355
+ onPress={handleDateClick}
356
+ dark={dark}
357
+ brandColor={brandColor}
358
+ language={language}
359
+ dayTextStyle={dayTextStyle}
360
+ />
361
+ ))}
363
362
  </View>
363
+
364
364
  </View>
365
365
  </View>
366
366
  </Pressable>
367
367
  </Pressable>
368
+
369
+ {/* the year modal which will show the list of year (in scrollview) */}
370
+ {/* NOTE: Need to change in flatlist for performance but need to fix the responsive */}
368
371
  <Modal
369
372
  visible={yearModal}
370
373
  onRequestClose={closeYearView}
@@ -383,6 +386,7 @@ const CalendarPicker = ({
383
386
  >
384
387
  <ScrollView
385
388
  showsVerticalScrollIndicator={false}
389
+ ref={yearModelScrollRef}
386
390
  contentContainerStyle={{
387
391
  display: 'flex',
388
392
  paddingVertical: 10,
@@ -397,7 +401,7 @@ const CalendarPicker = ({
397
401
  return (
398
402
  <TouchableOpacity
399
403
  key={index}
400
- onPress={() => handleYearClick(index + 2000)}
404
+ onPress={() => handleYearClick(index + NEPALI_MIN_YEAR)}
401
405
  style={{
402
406
  paddingHorizontal: 20,
403
407
  paddingVertical: 6,
@@ -407,7 +411,7 @@ const CalendarPicker = ({
407
411
  borderRadius: 20,
408
412
 
409
413
  backgroundColor:
410
- index + 2000 === year ? brandColor : '',
414
+ index + NEPALI_MIN_YEAR === year ? brandColor : '',
411
415
  borderWidth: 0.4,
412
416
  }}
413
417
  >
@@ -415,7 +419,7 @@ const CalendarPicker = ({
415
419
  style={{
416
420
  fontWeight: '500',
417
421
  color:
418
- index + 2000 === year
422
+ index + NEPALI_MIN_YEAR === year
419
423
  ? 'white'
420
424
  : dark
421
425
  ? 'white'
@@ -423,8 +427,8 @@ const CalendarPicker = ({
423
427
  }}
424
428
  >
425
429
  {language === 'np'
426
- ? getNepaliNumber(index + 2000)
427
- : index + 2000}
430
+ ? getNepaliNumber(index + NEPALI_MIN_YEAR)
431
+ : index + NEPALI_MIN_YEAR}
428
432
  </Text>
429
433
  </TouchableOpacity>
430
434
  );
@@ -466,11 +470,6 @@ const styles = StyleSheet.create({
466
470
  alignItems: 'center',
467
471
  paddingVertical: 18,
468
472
  },
469
- //WeekText: {
470
- // fontWeight: 'bold',
471
- // fontSize: 14,
472
- // color: 'black',
473
- //},
474
473
  datesContainer: {
475
474
  flexDirection: 'row',
476
475
  flexWrap: 'wrap',
@@ -482,10 +481,6 @@ const styles = StyleSheet.create({
482
481
  alignItems: 'center',
483
482
  paddingVertical: 10,
484
483
  },
485
- //DayText: {
486
- // fontSize: 14,
487
- // fontWeight: '600',
488
- //},
489
484
  CButton: {
490
485
  paddingHorizontal: 20,
491
486
  paddingVertical: 10,
@@ -499,10 +494,7 @@ const styles = StyleSheet.create({
499
494
  outerDateConainer: {
500
495
  paddingHorizontal: 3,
501
496
  },
502
- //TitleText: {
503
- // fontSize: 20,
504
- // fontWeight: 'bold',
505
- //},
497
+
506
498
  // for year view modal
507
499
  YearInnerPressable: {
508
500
  justifyContent: 'center',
@@ -0,0 +1,70 @@
1
+ import React from 'react';
2
+ import { Text, TouchableOpacity, View } from 'react-native';
3
+ import { getNepaliNumber } from './calendar/config';
4
+
5
+ type DayCellProps = {
6
+ day: number | null;
7
+ isSelectedDay: boolean;
8
+ onPress: (day: number) => void;
9
+ dark: boolean;
10
+ brandColor: string;
11
+ language: 'np' | 'en';
12
+ dayTextStyle?: any;
13
+ disabled: boolean;
14
+ };
15
+
16
+ const DayCell = React.memo(
17
+ ({
18
+ day,
19
+ isSelectedDay,
20
+ onPress,
21
+ dark,
22
+ brandColor,
23
+ language,
24
+ dayTextStyle,
25
+ disabled,
26
+ }: DayCellProps) => {
27
+ if (!day) {
28
+ return <View style={{ width: '14.28%', paddingVertical: 10 }} />;
29
+ }
30
+
31
+ return (
32
+ <TouchableOpacity
33
+ onPress={() => !disabled && onPress(day)}
34
+ style={[{
35
+ width: '14.28%',
36
+ justifyContent: 'center',
37
+ alignItems: 'center',
38
+ paddingVertical: 10,
39
+ },
40
+ disabled && { opacity: 0.35 }]}
41
+ >
42
+ <View
43
+ style={{
44
+ paddingHorizontal: 6,
45
+ paddingVertical: 3,
46
+ borderRadius: 999,
47
+ backgroundColor: isSelectedDay
48
+ ? brandColor
49
+ : dark
50
+ ? '#383838'
51
+ : '#fff',
52
+ }}
53
+ >
54
+ <Text
55
+ style={[
56
+ dayTextStyle,
57
+ {
58
+ color: isSelectedDay ? '#fff' : dark ? '#fff' : '#000',
59
+ },
60
+ ]}
61
+ >
62
+ {language === 'np' ? getNepaliNumber(day) : day}
63
+ </Text>
64
+ </View>
65
+ </TouchableOpacity>
66
+ );
67
+ }
68
+ );
69
+
70
+ export default DayCell;
@@ -163,7 +163,7 @@ bs[2080] = [2080, 31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30];
163
163
 
164
164
  bs[2081] = [2081, 31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31];
165
165
 
166
- bs[2082] = [2082, 31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30];
166
+ bs[2082] = [2082, 31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30];
167
167
 
168
168
  bs[2083] = [2083, 31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30];
169
169
 
@@ -1,5 +1,6 @@
1
1
  import { bs } from './config';
2
2
  import type { DateString } from '../types';
3
+ import { NEPALI_MAX_YEAR, NEPALI_MIN_YEAR } from './settings';
3
4
 
4
5
  const formatDate = (date: Date) => {
5
6
  const year = date.getFullYear();
@@ -8,18 +9,59 @@ const formatDate = (date: Date) => {
8
9
  return `${year}-${month}-${day}`;
9
10
  };
10
11
 
11
- export const validateDate = (date: string): string | boolean => {
12
- const dateArray = date.split('-');
13
- const [userYear, userMonth, _] = dateArray.map(Number);
14
- if (dateArray.length !== 3) {
15
- return 'Invalid date format';
16
- } else if (userYear < 2000 || userYear >= 2100) {
17
- return 'Year Range is 2000 to 2099';
18
- } else if (userMonth < 1 || userMonth > 12) {
19
- return 'Month Range is 1 to 12';
20
- } else {
21
- return true;
12
+
13
+ // Add padart 0 if the date is day or months are denoted by single number
14
+ const normalizeNepaliDate = (date: string): string | null => {
15
+ const parts = date.split('-');
16
+ if (parts.length !== 3) return null;
17
+
18
+ const [y, m, d] = parts;
19
+
20
+ if (!/^\d{4}$/.test(y)) return null;
21
+ if (!/^\d{1,2}$/.test(m)) return null;
22
+ if (!/^\d{1,2}$/.test(d)) return null;
23
+
24
+ return `${y}-${m.padStart(2, '0')}-${d.padStart(2, '0')}`;
25
+ };
26
+
27
+
28
+ export const validateDate = (uDate: string): true | string => {
29
+
30
+ const normalized = normalizeNepaliDate(uDate)
31
+
32
+ if (!normalized) {
33
+ return 'Date format must be YYYY-MM-DD';
22
34
  }
35
+
36
+ // format check
37
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(normalized)) {
38
+ return 'Date format must be YYYY-MM-DD';
39
+ }
40
+ const [yearStr, monthStr, dayStr] = normalized.split('-');
41
+ const year = Number(yearStr);
42
+ const month = Number(monthStr);
43
+ const day = Number(dayStr);
44
+
45
+ // Year range
46
+ if (year < NEPALI_MIN_YEAR || year > NEPALI_MAX_YEAR) {
47
+ return 'Year range must be between 2000 and 2099 (BS)';
48
+ }
49
+ // Month range
50
+ if (month < 1 || month > 12) {
51
+ return 'Month range must be between 01 and 12';
52
+ }
53
+ //Day range using BS data
54
+ const daysInMonth = bs?.[year]?.[month];
55
+
56
+ if (!daysInMonth) {
57
+ return 'Invalid Nepali calendar data';
58
+ }
59
+
60
+ if (day < 1 || day > daysInMonth) {
61
+ return `Day range for ${year}-${monthStr} is 01 to ${daysInMonth}`;
62
+ }
63
+
64
+ return true;
23
65
  };
24
66
 
25
67
  const FindDateDifference = (date1: number, date2: number) => {
@@ -41,14 +83,14 @@ const AdToBs = (UserDate: DateString): DateString => {
41
83
 
42
84
  // number of days from that reference date
43
85
  const DateDifference = FindDateDifference(ReferenceDate, UserTimeDate);
44
- let nepaliYear: number = 2000;
86
+ let nepaliYear: number = NEPALI_MIN_YEAR;
45
87
  let nepaliMonth: number = 1;
46
88
  let nepaliDay: number = 1;
47
89
  //difference can calculate upto previous day so add 1 to get current day(Today)
48
90
 
49
91
  let DD = DateDifference + 1;
50
92
 
51
- outerLoop: for (let year = 2000; year < 2100; year++) {
93
+ outerLoop: for (let year = NEPALI_MIN_YEAR; year <= NEPALI_MAX_YEAR; year++) {
52
94
  for (let month = 1; month <= 12; month++) {
53
95
  if (DD <= bs[year][month]) {
54
96
  nepaliYear = year;
@@ -76,12 +118,12 @@ const NepaliToday = (): DateString => {
76
118
  new Date(formatDate(date)).getTime()
77
119
  );
78
120
 
79
- let nepaliYear: number = 2000;
121
+ let nepaliYear: number = NEPALI_MIN_YEAR;
80
122
  let nepaliMonth: number = 1;
81
123
  let nepaliDay: number = 1;
82
124
  //difference can calculate upto previous day so add 1 to get current day(Today)
83
125
  let DD = DateDifference + 1;
84
- outerLoop: for (let year = 2000; year < 2100; year++) {
126
+ outerLoop: for (let year = NEPALI_MIN_YEAR; year <= NEPALI_MAX_YEAR; year++) {
85
127
  for (let month = 1; month <= 12; month++) {
86
128
  if (DD <= bs[year][month]) {
87
129
  nepaliYear = year;
@@ -108,7 +150,7 @@ const BsToAd = (userDate: DateString): DateString => {
108
150
  throw new Error('Invalid date format');
109
151
  }
110
152
  const [userYear, userMonth, userDay] = dateArray.map(Number);
111
- if (userYear < 2000 || userYear >= 2100) {
153
+ if (userYear < NEPALI_MIN_YEAR || userYear > NEPALI_MAX_YEAR) {
112
154
  throw new Error('Year Range is 2000 to 2099');
113
155
  }
114
156
  if (userMonth < 1 || userMonth > 12) {
@@ -119,7 +161,7 @@ const BsToAd = (userDate: DateString): DateString => {
119
161
  // throw new Error('Month out of supported range');
120
162
  // }
121
163
 
122
- for (let year = 2000; year < userYear; year++) {
164
+ for (let year = NEPALI_MIN_YEAR; year < userYear; year++) {
123
165
  for (let month = 1; month <= 12; month++) {
124
166
  dateDifference += bs[year][month];
125
167
  }
@@ -1,5 +1,7 @@
1
1
  import { bs, leapYears } from './config';
2
2
 
3
+ export const NEPALI_MIN_YEAR = 2000;
4
+ export const NEPALI_MAX_YEAR = 2099;
3
5
  const calcFirstDay = (currentYear: number, currentMonth: number) => {
4
6
  let month = currentMonth;
5
7
  let year = currentYear;
@@ -0,0 +1,37 @@
1
+ import { validateDate } from "./functions";
2
+
3
+ export const validateCalendarDates = (
4
+ date: string,
5
+ minDate: string,
6
+ maxDate: string
7
+ ): true | string => {
8
+ // 1. Validate minDate
9
+ const minCheck = validateDate(minDate);
10
+ if (minCheck !== true) {
11
+ return `Invalid minDate: ${minCheck}`;
12
+ }
13
+
14
+ // 2. Validate maxDate
15
+ const maxCheck = validateDate(maxDate);
16
+ if (maxCheck !== true) {
17
+ return `Invalid maxDate: ${maxCheck}`;
18
+ }
19
+
20
+ // 3. Validate user provided date
21
+ const initialCheck = validateDate(date);
22
+ if (initialCheck !== true) {
23
+ return `Invalid provided date: ${initialCheck}`;
24
+ }
25
+
26
+ // 4. Logical range validation
27
+ if (minDate > maxDate) {
28
+ return 'minDate must be less than or equal to maxDate';
29
+ }
30
+
31
+ // 5. Initial date within range
32
+ if (date < minDate || date > maxDate) {
33
+ return 'Provided date must be between minDate and maxDate';
34
+ }
35
+
36
+ return true;
37
+ };
package/src/index.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ export { NEPALI_MIN_YEAR, NEPALI_MAX_YEAR } from './calendar/settings'
1
2
  export { AdToBs, BsToAd, NepaliToday } from './calendar/functions';
2
3
  export { default as CalendarPicker } from './CalendarPicker';
3
4
  export type { CalendarPickerProps, DateString } from './types.ts';
package/src/types.ts CHANGED
@@ -12,6 +12,8 @@ export interface CalendarPickerProps {
12
12
  dayTextStyle?: TextStyle;
13
13
  weekTextStyle?: TextStyle;
14
14
  titleTextStyle?: TextStyle;
15
- initialDate?: DateString;
15
+ date?: DateString;
16
+ minDate?: DateString;
17
+ maxDate?: DateString;
16
18
  }
17
19
  export type DateString = string;