import { CSSResultArray , html , PropertyValues , TemplateResult , } from '@spectrum-web-components/base' ; import { property , queryAssignedNodes , } from '@spectrum-web-components/base/src/decorators.js' ; import { AccordionItem } from './AccordionItem.js' ; import styles from './accordion.css.js' ; import { Focusable , getActiveElement } from '@spectrum-web-components/shared' ; element slot export class Accordion extends Focusable { public static get styles ( ) : CSSResultArray { return [ styles ] ; } /**
     * Allows multiple accordion items to be opened at the same time
     */ @ property ( { type : Boolean , reflect : true , attribute : 'allow-multiple' } ) public allowMultiple = false ; @ queryAssignedNodes ( ) private defaultNodes ! : NodeListOf < AccordionItem > ; private get items ( ) : AccordionItem [ ] { return [ ... ( this . defaultNodes || [ ] ) ] . filter ( ( node ) => typeof node . tagName !== 'undefined' ) as AccordionItem [ ] ; } public focus ( ) { if ( this . focusElement === this ) { return ; } super . focus ( ) ; } private public get focusElement ( ) : Accordion | AccordionItem { const items = this . items ; if ( items && ! items . length ) { return this ; } let index = 0 ; while ( index < items . length && items [ index ] && items [ index ] . disabled ) { index += 1 ; } if ( items [ index ] ) { return items [ index ] ; } return this ; } public startListeningToKeyboard ( ) { const items = this . items ; if ( items && ! items . length ) { return ; } this . addEventListener ( 'keydown' , this . handleKeydown ) ; } public stopListeningToKeyboard ( ) { this . removeEventListener ( 'keydown' , this . handleKeydown ) ; } private handleKeydown ( event ) { const { code } = event ; if ( code !== 'ArrowDown' && code !== 'ArrowUp' ) { return ; } event . preventDefault ( ) ; const direction = code === 'ArrowDown' ? 1 : - 1 ; this . focusItemByOffset ( direction ) ; } private focusItemByOffset ( direction ) { const items = this . items ; const focused = items . indexOf ( getActiveElement ( this ) as AccordionItem ) ; let next = focused ; let nextItem = items [ next ] ; while ( nextItem && ( nextItem . disabled || next === focused ) ) { next = ( items . length + next + direction ) % items . length ; nextItem = items [ next ] ; } if ( ! nextItem || nextItem . disabled || next === focused ) { return ; } nextItem . focus ( ) ; } private async onToggle ( event ) { await 0 ; if ( this . allowMultiple || event . defaultPrevented ) { return ; } const target = event . target as AccordionItem ; const items = [ ... this . items ] as AccordionItem [ ] ; if ( items && ! items . length ) { return ; } items . forEach ( ( item ) => { if ( item !== target ) { item . open = false ; } } ) ; } protected render ( ) { return html `
            <slot></slot>
        ` ; } protected firstUpdated ( changed ) { super . firstUpdated ( changed ) ; this . addEventListener ( 'focusin' , this . startListeningToKeyboard ) ; this . addEventListener ( 'focusout' , this . stopListeningToKeyboard ) ; this . addEventListener ( 'sp-accordion-item-toggle' , this . onToggle ) ; } }