@ -1,6 +1,6 @@
import { throttle } from 'throttle-debounce' ;
import { createTippy } from '../modules/tippy.ts' ;
import { isDocumentFragmentOrElementNode} from '../utils/dom.ts' ;
import { addDelegatedEventListener, isDocumentFragmentOrElementNode} from '../utils/dom.ts' ;
import octiconKebabHorizontal from '../../../public/assets/img/svg/octicon-kebab-horizontal.svg' ;
window . customElements . define ( 'overflow-menu' , class extends HTMLElement {
@ -12,10 +12,14 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
mutationObserver : MutationObserver ;
lastWidth : number ;
updateButtonActivationState() {
if ( ! this . button || ! this . tippyContent ) return ;
this . button . classList . toggle ( 'active' , Boolean ( this . tippyContent . querySelector ( '.item.active' ) ) ) ;
}
updateItems = throttle ( 100 , ( ) = > {
if ( ! this . tippyContent ) {
const div = document . createElement ( 'div' ) ;
div . classList . add ( 'tippy-target' ) ;
div . tabIndex = - 1 ; // for initial focus, programmatic focus only
div . addEventListener ( 'keydown' , ( e ) = > {
if ( e . key === 'Tab' ) {
@ -64,9 +68,10 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
}
}
} ) ;
this . append ( div ) ;
div . classList . add ( 'tippy-target' ) ;
this . handleItemClick ( div , '.tippy-target > .item' ) ;
this . tippyContent = div ;
}
} // end if: no tippyContent and create a new one
const itemFlexSpace = this . menuItemsEl . querySelector < HTMLSpanElement > ( '.item-flex-space' ) ;
const itemOverFlowMenuButton = this . querySelector < HTMLButtonElement > ( '.overflow-menu-button' ) ;
@ -88,7 +93,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
const menuRight = this . offsetLeft + this . offsetWidth ;
const menuItems = this . menuItemsEl . querySelectorAll < HTMLElement > ( '.item, .item-flex-space' ) ;
let afterFlexSpace = false ;
for ( const item of menuItems ) {
for ( const [ idx , item ] of menuItems . entries ( ) ) {
if ( item . classList . contains ( 'item-flex-space' ) ) {
afterFlexSpace = true ;
continue ;
@ -96,7 +101,10 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
if ( afterFlexSpace ) item . setAttribute ( 'data-after-flex-space' , 'true' ) ;
const itemRight = item . offsetLeft + item . offsetWidth ;
if ( menuRight - itemRight < 38 ) { // roughly the width of .overflow-menu-button with some extra space
this . tippyItems . push ( item ) ;
const onlyLastItem = idx === menuItems . length - 1 && this . tippyItems . length === 0 ;
const lastItemFit = onlyLastItem && menuRight - itemRight > 0 ;
const moveToPopup = ! onlyLastItem || ! lastItemFit ;
if ( moveToPopup ) this . tippyItems . push ( item ) ;
}
}
itemFlexSpace ? . style . removeProperty ( 'display' ) ;
@ -107,6 +115,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
const btn = this . querySelector ( '.overflow-menu-button' ) ;
btn ? . _tippy ? . destroy ( ) ;
btn ? . remove ( ) ;
this . button = null ;
return ;
}
@ -126,18 +135,17 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
// update existing tippy
if ( this . button ? . _tippy ) {
this . button . _tippy . setContent ( this . tippyContent ) ;
this . updateButtonActivationState ( ) ;
return ;
}
// create button initially
const btn = document . createElement ( 'button' ) ;
btn . classList . add ( 'overflow-menu-button' ) ;
btn . setAttribute ( 'aria-label' , window . config . i18n . more_items ) ;
btn . innerHTML = octiconKebabHorizontal ;
this . append ( btn ) ;
this . button = btn ;
createTippy ( btn , {
this . button = document . createElement ( 'button' ) ;
this . button . classList . add ( 'overflow-menu-button' ) ;
this . button . setAttribute ( 'aria-label' , window . config . i18n . more_items ) ;
this . button . innerHTML = octiconKebabHorizontal ;
this . append ( this . button ) ;
createTippy ( this . button , {
trigger : 'click' ,
hideOnClick : true ,
interactive : true ,
@ -151,6 +159,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
} , 0 ) ;
} ,
} ) ;
this . updateButtonActivationState ( ) ;
} ) ;
init() {
@ -187,6 +196,14 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
}
} ) ;
this . resizeObserver . observe ( this ) ;
this . handleItemClick ( this , '.overflow-menu-items > .item' ) ;
}
handleItemClick ( el : Element , selector : string ) {
addDelegatedEventListener ( el , 'click' , selector , ( ) = > {
this . button ? . _tippy ? . hide ( ) ;
this . updateButtonActivationState ( ) ;
} ) ;
}
connectedCallback() {