license import { MDCFoundation } from '@material/base/foundation' ; import { Direction , EventSource , jumpChipKeys , navigationKeys , strings as chipStrings } from '../chip/constants' ; import { MDCChipInteractionEventDetail , MDCChipNavigationEventDetail , MDCChipRemovalEventDetail , MDCChipSelectionEventDetail } from '../chip/types' ; import { MDCChipSetAdapter } from './adapter' ; import { cssClasses , strings } from './constants' ; export class MDCChipSetFoundation extends MDCFoundation < MDCChipSetAdapter > { static override get strings ( ) { return strings ; } static override get cssClasses ( ) { return cssClasses ; } static override get defaultAdapter ( ) : MDCChipSetAdapter { return { announceMessage : ( ) => undefined , focusChipPrimaryActionAtIndex : ( ) => undefined , focusChipTrailingActionAtIndex : ( ) => undefined , getChipListCount : ( ) => - 1 , getIndexOfChipById : ( ) => - 1 , hasClass : ( ) => false , isRTL : ( ) => false , removeChipAtIndex : ( ) => undefined , removeFocusFromChipAtIndex : ( ) => undefined , selectChipAtIndex : ( ) => undefined , } ; } /**
     * The ids of the selected chips in the set. Only used for choice chip set or filter chip set.
     */ private selectedChipIds : string [ ] = [ ] ; constructor ( adapter ? ) { super ( { ... MDCChipSetFoundation . defaultAdapter , ... adapter } ) ; } /**
     * Returns an array of the IDs of all selected chips.
     */ getSelectedChipIds ( ) { return this . selectedChipIds . slice ( ) ; } /**
     * Selects the chip with the given id. Deselects all other chips if the chip set is of the choice variant.
     * Does not notify clients of the updated selection state.
     */ select ( chipId ) { this . selectImpl ( chipId , false ) ; } /**
     * Handles a chip interaction event
     */ handleChipInteraction ( { chipId } ) { const index = this . adapter . getIndexOfChipById ( chipId ) ; this . removeFocusFromChipsExcept ( index ) ; if ( this . adapter . hasClass ( cssClasses . CHOICE ) || this . adapter . hasClass ( cssClasses . FILTER ) ) { this . toggleSelect ( chipId ) ; } } /**
     * Handles a chip selection event, used to handle discrepancy when selection state is set directly on the Chip.
     */ handleChipSelection ( { chipId , selected , shouldIgnore } ) { if ( shouldIgnore ) { return ; } const chipIsSelected = this . selectedChipIds . indexOf ( chipId ) >= 0 ; if ( selected && ! chipIsSelected ) { this . select ( chipId ) ; } else if ( ! selected && chipIsSelected ) { this . deselectImpl ( chipId ) ; } } /**
     * Handles the event when a chip is removed.
     */ handleChipRemoval ( { chipId , removedAnnouncement } ) { if ( removedAnnouncement ) { this . adapter . announceMessage ( removedAnnouncement ) ; } const index = this . adapter . getIndexOfChipById ( chipId ) ; this . deselectAndNotifyClients ( chipId ) ; this . adapter . removeChipAtIndex ( index ) ; const maxIndex = this . adapter . getChipListCount ( ) - 1 ; if ( maxIndex < 0 ) { return ; } const nextIndex = Math . min ( index , maxIndex ) ; this . removeFocusFromChipsExcept ( nextIndex ) ; this . adapter . focusChipTrailingActionAtIndex ( nextIndex ) ; } /**
     * Handles a chip navigation event.
     */ handleChipNavigation ( { chipId , key , source } ) { const maxIndex = this . adapter . getChipListCount ( ) - 1 ; let index = this . adapter . getIndexOfChipById ( chipId ) ; if ( index === - 1 || ! navigationKeys . has ( key ) ) { return ; } const isRTL = this . adapter . isRTL ( ) ; const isLeftKey = key === chipStrings . ARROW_LEFT_KEY || key === chipStrings . IE_ARROW_LEFT_KEY ; const isRightKey = key === chipStrings . ARROW_RIGHT_KEY || key === chipStrings . IE_ARROW_RIGHT_KEY ; const isDownKey = key === chipStrings . ARROW_DOWN_KEY || key === chipStrings . IE_ARROW_DOWN_KEY ; const shouldIncrement = ! isRTL && isRightKey || isRTL && isLeftKey || isDownKey ; const isHome = key === chipStrings . HOME_KEY ; const isEnd = key === chipStrings . END_KEY ; if ( shouldIncrement ) { index ++ ; } else if ( isHome ) { index = 0 ; } else if ( isEnd ) { index = maxIndex ; } else { index -- ; } if ( index < 0 || index > maxIndex ) { return ; } this . removeFocusFromChipsExcept ( index ) ; this . focusChipAction ( index , key , source ) ; } private focusChipAction ( index , key , source ) { const shouldJumpChips = jumpChipKeys . has ( key ) ; if ( shouldJumpChips && source === EventSource . PRIMARY ) { return this . adapter . focusChipPrimaryActionAtIndex ( index ) ; } if ( shouldJumpChips && source === EventSource . TRAILING ) { return this . adapter . focusChipTrailingActionAtIndex ( index ) ; } const dir = this . getDirection ( key ) ; if ( dir === Direction . LEFT ) { return this . adapter . focusChipTrailingActionAtIndex ( index ) ; } if ( dir === Direction . RIGHT ) { return this . adapter . focusChipPrimaryActionAtIndex ( index ) ; } } private getDirection ( key ) { const isRTL = this . adapter . isRTL ( ) ; const isLeftKey = key === chipStrings . ARROW_LEFT_KEY || key === chipStrings . IE_ARROW_LEFT_KEY ; const isRightKey = key === chipStrings . ARROW_RIGHT_KEY || key === chipStrings . IE_ARROW_RIGHT_KEY ; if ( ! isRTL && isLeftKey || isRTL && isRightKey ) { return Direction . LEFT ; } return Direction . RIGHT ; } /**
     * Deselects the chip with the given id and optionally notifies clients.
     */ private deselectImpl ( chipId , shouldNotifyClients = false ) { const index = this . selectedChipIds . indexOf ( chipId ) ; if ( index >= 0 ) { this . selectedChipIds . splice ( index , 1 ) ; const chipIndex = this . adapter . getIndexOfChipById ( chipId ) ; this . adapter . selectChipAtIndex ( chipIndex , false , shouldNotifyClients ) ; } } /**
     * Deselects the chip with the given id and notifies clients.
     */ private deselectAndNotifyClients ( chipId ) { this . deselectImpl ( chipId , true ) ; } /**
     * Toggles selection of the chip with the given id.
     */ private toggleSelect ( chipId ) { if ( this . selectedChipIds . indexOf ( chipId ) >= 0 ) { this . deselectAndNotifyClients ( chipId ) ; } else { this . selectAndNotifyClients ( chipId ) ; } } private removeFocusFromChipsExcept ( index ) { const chipCount = this . adapter . getChipListCount ( ) ; for ( let i = 0 ; i < chipCount ; i ++ ) { if ( i !== index ) { this . adapter . removeFocusFromChipAtIndex ( i ) ; } } } private selectAndNotifyClients ( chipId ) { this . selectImpl ( chipId , true ) ; } private selectImpl ( chipId , shouldNotifyClients ) { if ( this . selectedChipIds . indexOf ( chipId ) >= 0 ) { return ; } if ( this . adapter . hasClass ( cssClasses . CHOICE ) && this . selectedChipIds . length > 0 ) { const previouslySelectedChip = this . selectedChipIds [ 0 ] ; const previouslySelectedIndex = this . adapter . getIndexOfChipById ( previouslySelectedChip ) ; this . selectedChipIds = [ ] ; this . adapter . selectChipAtIndex ( previouslySelectedIndex , false , shouldNotifyClients ) ; } this . selectedChipIds . push ( chipId ) ; const index = this . adapter . getIndexOfChipById ( chipId ) ; this . adapter . selectChipAtIndex ( index , true , shouldNotifyClients ) ; } } export default MDCChipSetFoundation ;