1919import  {  ElementMixin  }  from  '@vaadin/component-base/src/element-mixin.js' ; 
2020import  {  PolylitMixin  }  from  '@vaadin/component-base/src/polylit-mixin.js' ; 
2121import  {  TooltipController  }  from  '@vaadin/component-base/src/tooltip-controller.js' ; 
22+ import  {  SlotStylesMixin  }  from  '@vaadin/component-base/src/slot-styles-mixin.js' ; 
2223import  {  Overlay ,  OverlayCloseEvent  }  from  '@vaadin/overlay/vaadin-overlay' ; 
2324import  '@vaadin/text-field' ; 
2425import  {  TextField  }  from  '@vaadin/text-field/vaadin-text-field' ; 
@@ -54,8 +55,8 @@ const REF_CENTURY_DEFAULT = toRefCentury(new Date().getFullYear());
5455 * 
5556 * @element  vcf-month-picker 
5657 */ 
57- export  class  VcfMonthPicker  extends  ElementMixin ( 
58-   ThemableMixin ( PolylitMixin ( LitElement ) ) 
58+ export  class  VcfMonthPicker  extends  SlotStylesMixin ( 
59+   ElementMixin ( ThemableMixin ( PolylitMixin ( LitElement ) ) ) 
5960)  { 
6061  static  get  is ( )  { 
6162    return  'vcf-month-picker' ; 
@@ -236,26 +237,55 @@ export class VcfMonthPicker extends ElementMixin(
236237    ` ; 
237238  } 
238239
239-   update ( props : PropertyValues )  { 
240-     const  observer  =  new  MutationObserver ( ( )  =>  { 
241-       this . _updateSuffixStyles ( ) ; 
242-     } ) ; 
243-     observer . observe ( this . shadowRoot ! ,  {  childList : true ,  subtree : true  } ) ; 
240+   // @ts -expect-error overriding property from `SlotStylesMixinClass` 
241+   override  get  slotStyles ( ) : string [ ]  { 
242+     const  tag  =  this . localName ; 
243+ 
244+     /** 
245+      * These rules target a <vaadin-text-field> element with a child element 
246+      * having the 'toggle-button' part. It is used to style the calendar toggle 
247+      * button inside the month picker text field. 
248+      * 
249+      * The rules are scoped through the component selector and only applies to 
250+      * the toggle button in the month picker input field. 
251+      */ 
252+     return  [ 
253+       ` 
254+         ${ tag }  
255+           flex: none; 
256+           width: 1em; 
257+           height: 1em; 
258+           line-height: 1; 
259+           font-size: var(--vcf-month-picker-icon-size); 
260+           text-align: center; 
261+           color: var(--lumo-contrast-60pct); 
262+           transition: 0.2s color; 
263+           cursor: var(--lumo-clickable-cursor); 
264+           order: 2; 
265+         } 
266+ 
267+         ${ tag }  
268+           display: block; 
269+           font-family: var(--vcf-month-picker-icons-font-family); 
270+           content: var(--vcf-month-picker-toggle-calendar-icon); 
271+         } 
272+ 
273+         ${ tag }  
274+           color: var(--lumo-body-text-color); 
275+         } 
276+ 
277+         ${ tag }  
278+           color: var(--lumo-contrast-20pct); 
279+           cursor: default; 
280+         } 
281+       ` , 
282+     ] ; 
283+   } 
244284
285+   update ( props : PropertyValues )  { 
245286    super . update ( props ) ; 
246287
247-     if  ( this . textField )  { 
248-       this . textField . setAttribute ( 'value' ,  this . inputValue  ??  '' ) ; 
249-       this . textField . setAttribute ( 'label' ,  this . label ) ; 
250-       this . textField . setAttribute ( 'placeholder' ,  this . placeholder ) ; 
251-       this . textField . disabled  =  this . disabled ; 
252-       this . textField . readonly  =  this . readonly ; 
253-       this . textField . invalid  =  this . invalid ; 
254-       this . textField . required  =  this . required ; 
255-       this . textField . clearButtonVisible  =  this . clearButtonVisible ; 
256-       this . textField . setAttribute ( 'error-message' ,  this . errorMessage ) ; 
257-       this . textField . setAttribute ( 'helper-text' ,  this . helperText ) ; 
258-     } 
288+     this . __renderSlottedField ( ) ; 
259289
260290    this . overlay  =  this . overlay  ||  this . shadowRoot ! . querySelector ( '#overlay' ) ; 
261291
@@ -270,112 +300,54 @@ export class VcfMonthPicker extends ElementMixin(
270300  } 
271301
272302  protected  firstUpdated ( )  { 
273-     this . _createTextField ( ) ; 
303+     this . textField  =  this . querySelector ( 'vaadin-text-field' )  as  TextField ; 
304+     ( this . textField  as  any ) . _onKeyDown  =  this . _onKeyDown . bind ( this ) ; 
305+ 
274306    this . _tooltipController  =  new  TooltipController ( this ,  'tooltip' ) ; 
275307    this . _tooltipController . setPosition ( 'top' ) ; 
276308    this . addController ( this . _tooltipController ) ; 
277309    if  ( this . value )  { 
278310      this . __boundInputValueChanged ( ) ; 
279311    } 
312+   } 
280313
281-     // Inject a <style> element into the light DOM to style the toggle button inside the month picker text field 
282-     const  style  =  document . createElement ( 'style' ) ; 
283-     style . textContent  =  ` 
284-     /* 
285-       * These rules target a <vaadin-text-field> element with a child element 
286-       * having the 'toggle-button' part. It is used to style the calendar toggle 
287-       * button inside the month picker text field. 
288-       * 
289-       * The rules are scoped through the component selector and only applies to 
290-       * the toggle button in the month picker input field. 
291-       */ 
292-       vaadin-text-field > [part="toggle-button"] { 
293-         flex: none; 
294-         width: 1em; 
295-         height: 1em; 
296-         line-height: 1; 
297-         font-size: var(--vcf-month-picker-icon-size); 
298-         text-align: center; 
299-         color: var(--lumo-contrast-60pct); 
300-         transition: 0.2s color; 
301-         cursor: var(--lumo-clickable-cursor); 
302-       } 
303- 
304-       vaadin-text-field > [part="toggle-button"]::before { 
305-         display: block; 
306-         font-family: var(--vcf-month-picker-icons-font-family); 
307-         content: var(--vcf-month-picker-toggle-calendar-icon); 
308-       } 
309- 
310-       vaadin-text-field > [part="toggle-button"]:hover { 
311-         color: var(--lumo-body-text-color); 
312-       } 
313- 
314-       vaadin-text-field[readonly] > [part="toggle-button"] { 
315-         color: var(--lumo-contrast-20pct); 
316-         cursor: default; 
317-       } 
318-     ` ; 
319-     this . appendChild ( style ) ; 
320-   } 
321- 
322-   // Creates the text field element in the slot="text-field-slot" 
323-   _createTextField ( )  { 
324-     if  ( ! this . textField )  { 
325-       // Create toggle button 
326-       const  suffixDiv  =  document . createElement ( 'div' ) ; 
327-       suffixDiv . setAttribute ( 'part' ,  'toggle-button' ) ; 
328-       suffixDiv . setAttribute ( 'slot' ,  'suffix' ) ; 
329-       suffixDiv . setAttribute ( 'aria-hidden' ,  'true' ) ; 
330-       suffixDiv . addEventListener ( 'click' ,  e  =>  { 
331-         this . __toggle ( e ) ; 
332-       } ) ; 
333- 
334-       // Create text field 
335-       const  txtfield  =  document . createElement ( 'vaadin-text-field' ) ; 
336-       txtfield . setAttribute ( 'slot' ,  'text-field-slot' ) ; 
337-       txtfield . setAttribute ( 'id' ,  'textField' ) ; 
338-       txtfield . setAttribute ( 'value' ,  this . inputValue  ??  '' ) ; 
339-       txtfield . setAttribute ( 'label' ,  this . label ) ; 
340-       txtfield . setAttribute ( 'placeholder' ,  this . placeholder ) ; 
341-       txtfield . disabled  =  this . disabled ; 
342-       txtfield . readonly  =  this . readonly ; 
343-       txtfield . invalid  =  this . invalid ; 
344-       txtfield . required  =  this . required ; 
345-       txtfield . clearButtonVisible  =  this . clearButtonVisible ; 
346-       txtfield . setAttribute ( 'error-message' ,  this . errorMessage ) ; 
347-       txtfield . setAttribute ( 'helper-text' ,  this . helperText ) ; 
348-       txtfield . setAttribute ( 'autocomplete' ,  'off' ) ; 
349- 
350-       // Add event listeners to the text field 
351-       txtfield . addEventListener ( 'click' ,  e  =>  { 
352-         this . __boundInputClicked ( e ) ; 
353-       } ) ; 
354-       txtfield . addEventListener ( 'change' ,  ( )  =>  { 
355-         this . __boundInputValueChanged ( ) ; 
356-       } ) ; 
357-       txtfield . addEventListener ( 'blur' ,  ( )  =>  { 
358-         this . _onBlur ( ) ; 
359-       } ) ; 
360-       txtfield . addEventListener ( 'focus' ,  ( )  =>  { 
361-         this . _onFocus ( ) ; 
362-       } ) ; 
363- 
364-       // Accessibility attributes 
365-       txtfield . setAttribute ( 'role' ,  'combobox' ) ; 
366-       txtfield . setAttribute ( 'aria-haspopup' ,  'dialog' ) ; 
367-       txtfield . setAttribute ( 'aria-expanded' ,  this . opened  ? 'true'  : 'false' ) ; 
368-       ( txtfield  as  any ) . _onKeyDown  =  this . _onKeyDown . bind ( this ) ; 
369- 
370-       // Add toggle button to suffix slot 
371-       txtfield . appendChild ( suffixDiv ) ; 
372- 
373-       // Store a reference to the created vaadin-text-field 
374-       this . textField  =  txtfield  as  TextField ; 
375- 
376-       // Append text field to slot 
377-       this . appendChild ( txtfield ) ; 
378-     } 
314+   private  __renderSlottedField ( )  { 
315+     render ( 
316+       html ` 
317+         < vaadin-text-field  
318+           slot ="text-field-slot " 
319+           .label ="${ this . label }  
320+           .value ="${ this . inputValue  ??  '' }  
321+           .placeholder ="${ this . placeholder }  
322+           .disabled ="${ this . disabled }  
323+           .invalid ="${ this . invalid }  
324+           .required ="${ this . required }  
325+           .clearButtonVisible ="${ this . clearButtonVisible }  
326+           .helperText ="${ this . helperText }  
327+           .errorMessage ="${ this . errorMessage }  
328+           @click ="${ this . __boundInputClicked }  
329+           @change ="${ this . __boundInputValueChanged }  
330+           @blur ="${ this . _onBlur }  
331+           @focus ="${ this . _onFocus }  
332+         >  
333+           < input  
334+             slot ="input " 
335+             role ="combobox " 
336+             aria-haspopup ="dialog " 
337+             aria-controls ="overlay " 
338+             aria-expanded ="${ this . opened  ? 'true'  : 'false' }  
339+           />  
340+           < div  
341+             part ="toggle-button " 
342+             slot ="suffix " 
343+             aria-hidden ="true " 
344+             @click ="${ this . __toggle }  
345+           > </ div >  
346+         </ vaadin-text-field >  
347+       ` , 
348+       this , 
349+       {  host : this  } 
350+     ) ; 
379351  } 
380352
381353  render ( )  { 
@@ -402,18 +374,6 @@ export class VcfMonthPicker extends ElementMixin(
402374    ` ; 
403375  } 
404376
405-   // This method is necessary to ensure the toggle button appears 
406-   // before the clear button 
407-   _updateSuffixStyles ( )  { 
408-     const  suffixElement  =  this . textField ?. shadowRoot 
409-       ?. querySelector ( 'vaadin-input-container' ) 
410-       ?. shadowRoot ?. querySelector ( '[name="suffix"]' )  as  HTMLElement ; 
411-     if  ( suffixElement )  { 
412-       suffixElement . style . display  =  'flex' ; 
413-       suffixElement . style . flexDirection  =  'row-reverse' ; 
414-     } 
415-   } 
416- 
417377  _onVaadinOverlayClose ( e : OverlayCloseEvent )  { 
418378    if  ( 
419379      e . detail . sourceEvent  && 
@@ -730,10 +690,6 @@ export class VcfMonthPicker extends ElementMixin(
730690  private  __overlayOpenedChanged ( e : CustomEvent )  { 
731691    const  opened  =  e . detail . value ; 
732692    this . opened  =  opened ; 
733-     this . textField ?. setAttribute ( 
734-       'aria-expanded' , 
735-       this . opened  ? 'true'  : 'false' 
736-     ) ; 
737693    if  ( opened )  { 
738694      this . textField ?. focus ( ) ; 
739695    } 
0 commit comments