@@ -6,6 +6,7 @@ export default class extends Controller {
66 "calendar" ,
77 "title" ,
88 "weekdaysTemplate" ,
9+ "disabledDateTemplate" ,
910 "selectedDateTemplate" ,
1011 "todayDateTemplate" ,
1112 "currentMonthDateTemplate" ,
@@ -16,6 +17,10 @@ export default class extends Controller {
1617 type : String ,
1718 default : null ,
1819 } ,
20+ minDate : {
21+ type : String ,
22+ default : null ,
23+ } ,
1924 viewDate : {
2025 type : String ,
2126 default : new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) ,
@@ -43,13 +48,21 @@ export default class extends Controller {
4348
4449 selectDay ( e ) {
4550 e . preventDefault ( ) ;
51+ if ( this . isDateDisabled ( e . currentTarget . dataset . day ) ) return ;
52+
4653 // Set the selected date value
4754 this . selectedDateValue = e . currentTarget . dataset . day ;
4855 }
4956
5057 selectedDateValueChanged ( value , prevValue ) {
58+ const selectedDate = this . selectedDate ( ) ;
59+ if ( ! selectedDate ) {
60+ this . updateCalendar ( ) ;
61+ return ;
62+ }
63+
5164 // update the viewDateValue to the first day of month of the selected date (This will trigger updateCalendar() function)
52- const newViewDate = new Date ( this . selectedDateValue ) ;
65+ const newViewDate = new Date ( selectedDate ) ;
5366 newViewDate . setDate ( 2 ) ; // set the day to the 2nd (to avoid issues with months with different number of days and timezones)
5467 this . viewDateValue = newViewDate . toISOString ( ) . slice ( 0 , 10 ) ;
5568
@@ -58,7 +71,7 @@ export default class extends Controller {
5871
5972 // update the input value
6073 this . rubyUiCalendarInputOutlets . forEach ( ( outlet ) => {
61- const formattedDate = this . formatDate ( this . selectedDate ( ) ) ;
74+ const formattedDate = this . formatDate ( selectedDate ) ;
6275 outlet . setValue ( formattedDate ) ;
6376 } ) ;
6477 }
@@ -101,10 +114,20 @@ export default class extends Controller {
101114
102115 renderDay ( day ) {
103116 const today = new Date ( ) ;
117+ const selectedDate = this . selectedDate ( ) ;
104118 let dateHTML = "" ;
105119 const data = { day : day , dayDate : day . getDate ( ) } ;
106120
107- if ( day . toDateString ( ) === this . selectedDate ( ) . toDateString ( ) ) {
121+ if ( this . isDateDisabled ( day ) ) {
122+ // disabledDate
123+ dateHTML = Mustache . render (
124+ this . disabledDateTemplateTarget . innerHTML ,
125+ data ,
126+ ) ;
127+ } else if (
128+ selectedDate &&
129+ day . toDateString ( ) === selectedDate . toDateString ( )
130+ ) {
108131 // selectedDate
109132 // Render the selected date template target innerHTML with Mustache
110133 dateHTML = Mustache . render (
@@ -137,13 +160,13 @@ export default class extends Controller {
137160 }
138161
139162 selectedDate ( ) {
140- return new Date ( this . selectedDateValue ) ;
163+ return this . parseDate ( this . selectedDateValue ) ;
141164 }
142165
143166 viewDate ( ) {
144- return this . viewDateValue
145- ? new Date ( this . viewDateValue )
146- : this . selectedDate ( ) ;
167+ return (
168+ this . parseDate ( this . viewDateValue ) || this . selectedDate ( ) || new Date ( )
169+ ) ;
147170 }
148171
149172 getFullWeeksStartAndEndInMonth ( ) {
@@ -246,4 +269,40 @@ export default class extends Controller {
246269 return "th" ;
247270 }
248271 }
272+
273+ minDate ( ) {
274+ return this . parseDate ( this . minDateValue ) ;
275+ }
276+
277+ isDateDisabled ( date ) {
278+ const minDate = this . minDate ( ) ;
279+ const candidate = this . parseDate ( date ) ;
280+
281+ if ( ! minDate || ! candidate ) return false ;
282+
283+ return this . startOfDay ( candidate ) < this . startOfDay ( minDate ) ;
284+ }
285+
286+ parseDate ( value ) {
287+ if ( ! value ) return null ;
288+ if ( value instanceof Date ) return new Date ( value ) ;
289+
290+ const isoDate = value . toString ( ) . match ( / ^ ( \d { 4 } ) - ( \d { 2 } ) - ( \d { 2 } ) / ) ;
291+ if ( isoDate ) {
292+ return new Date (
293+ Number ( isoDate [ 1 ] ) ,
294+ Number ( isoDate [ 2 ] ) - 1 ,
295+ Number ( isoDate [ 3 ] ) ,
296+ ) ;
297+ }
298+
299+ const date = new Date ( value ) ;
300+ return Number . isNaN ( date . getTime ( ) ) ? null : date ;
301+ }
302+
303+ startOfDay ( date ) {
304+ const normalizedDate = new Date ( date ) ;
305+ normalizedDate . setHours ( 0 , 0 , 0 , 0 ) ;
306+ return normalizedDate ;
307+ }
249308}
0 commit comments