1818 * #L%
1919 */
2020import { css , html , LitElement } from 'lit' ;
21-
21+
2222export class YearMonthField extends LitElement {
2323
2424 static get is ( ) { return 'fc-year-month-field' ; }
@@ -29,6 +29,8 @@ export class YearMonthField extends LitElement {
2929 date : { type : Date } ,
3030 year : { type : Number , readOnly : true , state : true } ,
3131 month : { type : Number , readOnly : true , state : true } ,
32+ min : { type : Object , readOnly : true } ,
33+ max : { type : Object , readOnly : true } ,
3234 i18n : { type : Object }
3335 }
3436 }
@@ -39,6 +41,10 @@ export class YearMonthField extends LitElement {
3941 this . _i18n = { } ;
4042 this . __setDefaultFormatTitle ( this . _i18n ) ;
4143 this . __setDefaultMonthNames ( this . _i18n ) ;
44+ this . _decMonthDisabled = false ;
45+ this . _incMonthDisabled = false ;
46+ this . _decYearDisabled = false ;
47+ this . _incYearDisabled = false ;
4248 }
4349
4450 set i18n ( value ) {
@@ -56,19 +62,42 @@ export class YearMonthField extends LitElement {
5662
5763 get i18n ( ) { return this . _i18n ; }
5864
65+ /**
66+ * Checks if value is between min and max (inclusive).
67+ */
68+ __checkRange ( value ) {
69+ return ( ! this . min || value >= this . _minAsNumber )
70+ && ( ! this . max || value <= this . _maxAsNumber ) ;
71+ }
72+
5973 willUpdate ( changedProperties ) {
6074 if ( changedProperties . has ( 'value' ) ) {
61- this . date = this . value ? new Date ( this . value . substring ( 0 , 7 ) + '-02' ) : new Date ( ) ;
62- }
63- if ( changedProperties . has ( 'date' ) ) {
64- this . value = this . date . toISOString ( ) . substring ( 0 , 7 ) ;
65- this . date . setDate ( 1 ) ;
66- this . _year = this . date . getFullYear ( ) ;
67- this . _month = this . date . getMonth ( ) + 1 ;
75+ this . date = this . value ? new Date ( this . value . substring ( 0 , 7 ) + '-02' ) : new Date ( ) ;
6876 }
6977 if ( changedProperties . has ( 'i18n' ) && ! this . i18n ) {
7078 this . i18n = changedProperties . get ( 'i18n' ) ;
7179 }
80+ if ( changedProperties . has ( 'date' ) || changedProperties . has ( 'min' ) || changedProperties . has ( 'max' ) ) {
81+ const strValue = this . date . toISOString ( ) . substring ( 0 , 7 ) ;
82+ this . __normalizeValue ( strValue ) ;
83+ this . date . setDate ( 1 ) ;
84+ this . _year = this . date . getFullYear ( ) ;
85+ this . _month = this . date . getMonth ( ) + 1 ;
86+ this . __toggleButtons ( this . min , this . max ) ;
87+ }
88+ }
89+
90+ __normalizeValue ( value ) {
91+ const intValue = parseInt ( this . __yearMonthAsNumber ( this . date . getFullYear ( ) , this . date . getMonth ( ) ) ) ;
92+ if ( this . min && intValue < this . _minAsNumber ) {
93+ this . value = this . min . year + '-' + String ( this . min . month + 1 ) . padStart ( 2 , '0' ) ;
94+ this . date = new Date ( this . min . year , this . min . month ) ;
95+ } if ( this . max && intValue > this . _maxAsNumber ) {
96+ this . value = this . max . year + '-' + String ( this . max . month + 1 ) . padStart ( 2 , '0' ) ;
97+ this . date = new Date ( this . max . year , this . max . month ) ;
98+ } else {
99+ this . value = value ;
100+ }
72101 }
73102
74103 updated ( changedProperties ) {
@@ -96,11 +125,11 @@ export class YearMonthField extends LitElement {
96125
97126 render ( ) {
98127 return html `
99- < vaadin-button theme ="small icon " @click ="${ this . __decYear } "> <<</ vaadin-button >
100- < vaadin-button theme ="small icon " @click ="${ this . __decMonth } "> <</ vaadin-button >
128+ < vaadin-button id =" dec-year-button " theme ="small icon " @click ="${ this . __decYear } " ?disabled =" ${ this . _decYearDisabled } "> <<</ vaadin-button >
129+ < vaadin-button id =" dec-month-button " theme ="small icon " @click ="${ this . __decMonth } " ?disabled =" ${ this . _decMonthDisabled } "> <</ vaadin-button >
101130 < div part ="header "> ${ this . formatTitle ( this . _month , this . _year ) } </ div >
102- < vaadin-button theme ="small icon " @click ="${ this . __incMonth } "> ></ vaadin-button >
103- < vaadin-button theme ="small icon " @click ="${ this . __incYear } "> >></ vaadin-button >
131+ < vaadin-button id =" inc-month-button " theme ="small icon " @click ="${ this . __incMonth } " ?disabled =" ${ this . _incMonthDisabled } "> ></ vaadin-button >
132+ < vaadin-button id =" inc-year-button " theme ="small icon " @click ="${ this . __incYear } " ?disabled =" ${ this . _incYearDisabled } "> >></ vaadin-button >
104133 ` ;
105134 }
106135
@@ -116,19 +145,27 @@ export class YearMonthField extends LitElement {
116145 }
117146
118147 __decYear ( ) {
119- this . __addMonths ( - 12 ) ;
148+ if ( ! this . _minAsNumber || this . _minAsNumber < this . __dateAsNumber ( ) ) {
149+ this . __addMonths ( - 12 ) ;
150+ }
120151 }
121152
122153 __decMonth ( ) {
123- this . __addMonths ( - 1 ) ;
154+ if ( ! this . _minAsNumber || this . _minAsNumber < this . __dateAsNumber ( ) ) {
155+ this . __addMonths ( - 1 ) ;
156+ }
124157 }
125158
126159 __incYear ( ) {
127- this . __addMonths ( 12 ) ;
160+ if ( ! this . _maxAsNumber || this . _maxAsNumber > this . __dateAsNumber ( ) ) {
161+ this . __addMonths ( 12 ) ;
162+ }
128163 }
129164
130165 __incMonth ( ) {
131- this . __addMonths ( 1 ) ;
166+ if ( ! this . _maxAsNumber || this . _maxAsNumber > this . __dateAsNumber ( ) ) {
167+ this . __addMonths ( 1 ) ;
168+ }
132169 }
133170
134171 __setDefaultFormatTitle ( obj ) {
@@ -138,6 +175,65 @@ export class YearMonthField extends LitElement {
138175 __setDefaultMonthNames ( obj ) {
139176 obj . monthNames = [ 'January' , 'February' , 'March' , 'April' , 'May' , 'June' , 'July' , 'August' , 'September' , 'October' , 'November' , 'December' ] ;
140177 }
178+
179+ /**
180+ * Returns a number joining year and month. Month is left padded with zero up to two chars length.
181+ */
182+ __yearMonthAsNumber ( year , month ) {
183+ return parseInt ( year + '' + String ( month ) . padStart ( 2 , '0' ) ) ;
184+ }
185+
186+ /**
187+ * Converts this.date to yearMonth number
188+ */
189+ __dateAsNumber ( ) {
190+ return this . date ? this . __yearMonthAsNumber ( this . date . getFullYear ( ) , this . date . getMonth ( ) ) : undefined ;
191+ }
192+
193+ /**
194+ * Converts min or max value to yearMonth number.
195+ */
196+ __minMaxAsNumber ( value ) {
197+ return value ? this . __yearMonthAsNumber ( value . year , value . month ) : undefined ;
198+ }
199+
200+ /**
201+ * Converts this.min to number
202+ * @private
203+ */
204+ get _minAsNumber ( ) {
205+ return this . __minMaxAsNumber ( this . min ) ;
206+ }
207+
208+ /**
209+ * Converts this.max to number
210+ * @private
211+ */
212+ get _maxAsNumber ( ) {
213+ return this . __minMaxAsNumber ( this . max ) ;
214+ }
215+
216+ /**
217+ * Returns true if delta between minOrMax and this.date is less than 1 year (12 months)
218+ */
219+ __dateDeltaLtYear ( minOrMax ) {
220+ const toMonths = ( year , month ) => year * 12 + month ;
221+ const dateToMonths = toMonths ( this . date . getFullYear ( ) , this . date . getMonth ( ) ) ;
222+ return Math . abs ( dateToMonths - toMonths ( minOrMax . year , minOrMax . month ) ) < 12 ;
223+ }
224+
225+ /**
226+ * Enable or disabled navigation buttons
227+ */
228+ __toggleButtons ( min , max ) {
229+ const minAsNumber = this . __minMaxAsNumber ( min ) ;
230+ const maxAsNumber = this . __minMaxAsNumber ( max ) ;
231+
232+ this . _decMonthDisabled = minAsNumber && minAsNumber >= this . __dateAsNumber ( ) ;
233+ this . _incMonthDisabled = maxAsNumber && maxAsNumber <= this . __dateAsNumber ( ) ;
234+ this . _decYearDisabled = minAsNumber && ( minAsNumber >= this . __dateAsNumber ( ) || this . __dateDeltaLtYear ( min ) ) ;
235+ this . _incYearDisabled = maxAsNumber && ( maxAsNumber <= this . __dateAsNumber ( ) || this . __dateDeltaLtYear ( max ) ) ;
236+ }
141237
142238}
143239
0 commit comments