import { AfterViewInit , Component , ContentChild , ContentChildren , EventEmitter , HostBinding , Input , OnChanges , OnInit , Output , TemplateRef , TrackByFunction , ViewChild , } from '@angular/core' ; import { ThemeColor } from '@kirbydesign/core' ; import { ItemComponent } from '../item/item.component' ; import { InfiniteScrollDirective } from './directives/infinite-scroll.directive' ; import { ListHelper } from './helpers/list-helper' ; import { BoundaryClass } from './list-item/list-item.component' ; import { ListSwipeAction } from './list-swipe-action.type' ; import { ListFooterDirective , ListHeaderDirective , ListItemTemplateDirective , ListSectionHeaderDirective , } from './list.directive' ; import { LoadOnDemandEvent , LoadOnDemandEventData } from './list.event' ; import { GroupByPipe } from './pipes/group-by.pipe' ; export type ListShape = 'square' | 'rounded' | 'none' ; @ Component ( { selector : 'kirby-list' , templateUrl : './list.component.html' , styleUrls : [ './list.component.scss' ] , providers : [ ListHelper , GroupByPipe ] , } ) export class ListComponent implements OnInit , AfterViewInit , OnChanges { @ ViewChild ( 'list' , { static : true } ) list : any ; @ ViewChild ( InfiniteScrollDirective ) scrollDirective : InfiniteScrollDirective ; /**
     * Provide items for the list to render. Items must be provided in the order you expect them to be rendered.
     */ @ Input ( ) items : any [ ] = [ ] ; @ Input ( ) getItemColor : ( item : any ) => ThemeColor ; /**
     * Callback to determine name of section. Sections will be ordered alphabetically.
     */ @ Input ( ) getSectionName : ( item : any ) => string ; /**
     * Callback that defines how to track changes for items in the iterable.
     */ @ Input ( ) trackBy : TrackByFunction < any > ; /**
     * Text to display when no more items can be loaded (used for "on demand"-loading).
     */ @ Input ( ) noMoreItemsText : string ; /**
     * Determines if dividers (bottom-border on list items) should be shown or not.
     */ @ Input ( ) showDivider = false ; /**
     * Determines if list row text should turn bold on selection
     */ @ Input ( ) markSelectedRow = false ; /**
     * Determine outline shape of:
     * - list, if  {@link #isSectionsEnabled} is `false`
     * - section, if  {@link #isSectionsEnabled} is `true`
     *
     * `square` means **without** rounded corners, `rounded` means **with** rounded corners.,  `none` means **without** padding, border, box-shadow and background.
      @ Input ( ) shape : ListShape = 'rounded' ; @ HostBinding ( 'class.shape-rounded' ) public get isShapeRounded ( ) : boolean { return this . shape === 'rounded' ; } @ HostBinding ( 'class.shape-none' ) public get isShapeNone ( ) : boolean { return this . shape === 'none' ; } @ HostBinding ( 'class.item-spacing' ) @ Input ( ) hasItemSpacing : boolean ; /**
     * Determines if the loadOnDemand event should be emitted.
     * Will default to true if there is at least one subscriber to the loadOnDemand event
     */ @ Input ( ) isLoadOnDemandEnabled : boolean ; /**
     * Emitting event when more items are to be loaded.
     */ @ Output ( ) loadOnDemand = new EventEmitter < LoadOnDemandEvent > ( ) ; /**
     * Determines if list items should have swipe actions or not
     * - the order of swipe actions is used to determine edge actions,
     * as well as their order of appearance on the screen.
     */ @ Input ( ) swipeActions : ListSwipeAction [ ] = [ ] ; /**
     * Emitting event when an item is selected (tapped on mobile, clicked on web)
     */ @ Output ( ) itemSelect = new EventEmitter < any > ( ) ; @ Input ( ) disableSelectionHighlight : boolean = false ; @ ContentChildren ( ItemComponent ) kirbyItems : ItemComponent [ ] ; @ ContentChild ( ListHeaderDirective , { static : false , read : TemplateRef } ) headerTemplate : TemplateRef < any > ; @ ContentChild ( ListSectionHeaderDirective , { static : false , read : TemplateRef } ) sectionHeaderTemplate : TemplateRef < any > ; @ ContentChild ( ListFooterDirective , { static : false , read : TemplateRef } ) footerTemplate : TemplateRef < any > ; /**
     * The first element that matches ListItemDirective.
     * As a structural directive it unfolds into a template. This is a reference to that.
     */ @ ContentChild ( ListItemTemplateDirective , { static : true , read : TemplateRef } ) itemTemplate : TemplateRef < any > ; @ HostBinding ( 'class.has-sections' ) _isSectionsEnabled : boolean ; _isSelectable : boolean ; _isLoading : boolean ; _groupedItems : any [ ] ; _selectedItem : any ; constructor ( private listHelper , private groupBy ) { } ngOnInit ( ) { this . _isSelectable = this . itemSelect . observers . length > 0 ; if ( this . isLoadOnDemandEnabled === undefined ) { this . isLoadOnDemandEnabled = this . loadOnDemand . observers . length > 0 ; } } ngAfterViewInit ( ) { if ( this . _isSelectable ) { setTimeout ( ( ) => { this . kirbyItems . forEach ( ( item ) => { item . selectable = true ; } ) ; } ) ; } } ngOnChanges ( ) { this . _isSectionsEnabled = ! ! this . getSectionName ; this . _groupedItems = this . _isSectionsEnabled ? this . groupBy . transform ( this . items , this . getSectionName ) : null ; } _onLoadOnDemand ( event ? ) { this . listHelper . onLoadOnDemand ( this , event ) ; } defaultTrackBy ( index ) { return index ; } sectionTrackBy ( _ , section ) { return section . name ; } onItemSelect ( item ) { if ( ! this . disableSelectionHighlight ) { this . _selectedItem = item ; } this . itemSelect . emit ( item ) ; } onSwipeActionSelect ( args ) { args . swipeAction . onSelected ( args . item ) ; this . list . closeSlidingItems ( ) ; args . event . stopPropagation ( ) ; } _getBoundaryClass ( index , section ? ) { let _items = section || this . items ; if ( index === 0 || _items [ index - 1 ] ?. headingName ) return this . headerTemplate ? null : 'first' ; if ( index === _items . length - 1 || _items [ index + 1 ] ?. headingName ) return this . footerTemplate ? null : 'last' ; } }