11import  { throttle }  from  'throttle-debounce' ; 
22import  { createTippy }  from  '../modules/tippy.ts' ; 
3- import  { isDocumentFragmentOrElementNode }  from  '../utils/dom.ts' ; 
3+ import  { addDelegatedEventListener ,   isDocumentFragmentOrElementNode }  from  '../utils/dom.ts' ; 
44import  octiconKebabHorizontal  from  '../../../public/assets/img/svg/octicon-kebab-horizontal.svg' ; 
55
66window . customElements . define ( 'overflow-menu' ,  class  extends  HTMLElement  { 
@@ -12,10 +12,14 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
1212  mutationObserver : MutationObserver ; 
1313  lastWidth : number ; 
1414
15+   updateButtonActivationState ( )  { 
16+     if  ( ! this . button  ||  ! this . tippyContent )  return ; 
17+     this . button . classList . toggle ( 'active' ,  Boolean ( this . tippyContent . querySelector ( '.item.active' ) ) ) ; 
18+   } 
19+ 
1520  updateItems  =  throttle ( 100 ,  ( )  =>  { 
1621    if  ( ! this . tippyContent )  { 
1722      const  div  =  document . createElement ( 'div' ) ; 
18-       div . classList . add ( 'tippy-target' ) ; 
1923      div . tabIndex  =  - 1 ;  // for initial focus, programmatic focus only 
2024      div . addEventListener ( 'keydown' ,  ( e )  =>  { 
2125        if  ( e . key  ===  'Tab' )  { 
@@ -64,9 +68,10 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
6468          } 
6569        } 
6670      } ) ; 
67-       this . append ( div ) ; 
71+       div . classList . add ( 'tippy-target' ) ; 
72+       this . handleItemClick ( div ,  '.tippy-target > .item' ) ; 
6873      this . tippyContent  =  div ; 
69-     } 
74+     }   // end if: no tippyContent and create a new one 
7075
7176    const  itemFlexSpace  =  this . menuItemsEl . querySelector < HTMLSpanElement > ( '.item-flex-space' ) ; 
7277    const  itemOverFlowMenuButton  =  this . querySelector < HTMLButtonElement > ( '.overflow-menu-button' ) ; 
@@ -88,15 +93,18 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
8893    const  menuRight  =  this . offsetLeft  +  this . offsetWidth ; 
8994    const  menuItems  =  this . menuItemsEl . querySelectorAll < HTMLElement > ( '.item, .item-flex-space' ) ; 
9095    let  afterFlexSpace  =  false ; 
91-     for  ( const  item  of  menuItems )  { 
96+     for  ( const  [ idx ,   item ]  of  menuItems . entries ( ) )  { 
9297      if  ( item . classList . contains ( 'item-flex-space' ) )  { 
9398        afterFlexSpace  =  true ; 
9499        continue ; 
95100      } 
96101      if  ( afterFlexSpace )  item . setAttribute ( 'data-after-flex-space' ,  'true' ) ; 
97102      const  itemRight  =  item . offsetLeft  +  item . offsetWidth ; 
98103      if  ( menuRight  -  itemRight  <  38 )  {  // roughly the width of .overflow-menu-button with some extra space 
99-         this . tippyItems . push ( item ) ; 
104+         const  onlyLastItem  =  idx  ===  menuItems . length  -  1  &&  this . tippyItems . length  ===  0 ; 
105+         const  lastItemFit  =  onlyLastItem  &&  menuRight  -  itemRight  >  0 ; 
106+         const  moveToPopup  =  ! onlyLastItem  ||  ! lastItemFit ; 
107+         if  ( moveToPopup )  this . tippyItems . push ( item ) ; 
100108      } 
101109    } 
102110    itemFlexSpace ?. style . removeProperty ( 'display' ) ; 
@@ -107,6 +115,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
107115      const  btn  =  this . querySelector ( '.overflow-menu-button' ) ; 
108116      btn ?. _tippy ?. destroy ( ) ; 
109117      btn ?. remove ( ) ; 
118+       this . button  =  null ; 
110119      return ; 
111120    } 
112121
@@ -126,18 +135,17 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
126135    // update existing tippy 
127136    if  ( this . button ?. _tippy )  { 
128137      this . button . _tippy . setContent ( this . tippyContent ) ; 
138+       this . updateButtonActivationState ( ) ; 
129139      return ; 
130140    } 
131141
132142    // create button initially 
133-     const  btn  =  document . createElement ( 'button' ) ; 
134-     btn . classList . add ( 'overflow-menu-button' ) ; 
135-     btn . setAttribute ( 'aria-label' ,  window . config . i18n . more_items ) ; 
136-     btn . innerHTML  =  octiconKebabHorizontal ; 
137-     this . append ( btn ) ; 
138-     this . button  =  btn ; 
139- 
140-     createTippy ( btn ,  { 
143+     this . button  =  document . createElement ( 'button' ) ; 
144+     this . button . classList . add ( 'overflow-menu-button' ) ; 
145+     this . button . setAttribute ( 'aria-label' ,  window . config . i18n . more_items ) ; 
146+     this . button . innerHTML  =  octiconKebabHorizontal ; 
147+     this . append ( this . button ) ; 
148+     createTippy ( this . button ,  { 
141149      trigger : 'click' , 
142150      hideOnClick : true , 
143151      interactive : true , 
@@ -151,6 +159,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
151159        } ,  0 ) ; 
152160      } , 
153161    } ) ; 
162+     this . updateButtonActivationState ( ) ; 
154163  } ) ; 
155164
156165  init ( )  { 
@@ -187,6 +196,14 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
187196      } 
188197    } ) ; 
189198    this . resizeObserver . observe ( this ) ; 
199+     this . handleItemClick ( this ,  '.overflow-menu-items > .item' ) ; 
200+   } 
201+ 
202+   handleItemClick ( el : Element ,  selector : string )  { 
203+     addDelegatedEventListener ( el ,  'click' ,  selector ,  ( )  =>  { 
204+       this . button ?. _tippy ?. hide ( ) ; 
205+       this . updateButtonActivationState ( ) ; 
206+     } ) ; 
190207  } 
191208
192209  connectedCallback ( )  { 
0 commit comments