@bimeister/pupakit.kit
Version:
PupaKit is an open source collection of Angular components based on an atomic approach to building interfaces, which guarantees better performance and greater development flexibility.
1 lines • 521 kB
Source Map (JSON)
{"version":3,"file":"bimeister-pupakit.kit.mjs","sources":["../../src/components/accordion/components/accordion/accordion.component.ts","../../src/components/accordion/components/accordion/accordion.component.html","../../src/components/accordion/components/accordion-header/accordion-header.component.ts","../../src/components/accordion/components/accordion-header/accordion-header.component.html","../../src/components/accordion/components/accordion-description/accordion-description.component.ts","../../src/components/accordion/components/accordion-description/accordion-description.component.html","../../src/components/accordion/components/accordion-title/accordion-title.component.ts","../../src/components/accordion/components/accordion-title/accordion-title.component.html","../../src/components/accordion/components/accordion-body/accordion-body.component.ts","../../src/components/accordion/components/accordion-body/accordion-body.component.html","../../src/components/accordion/components/accordion-group/accordion-group.component.ts","../../src/components/accordion/components/accordion-group/accordion-group.component.html","../../src/components/accordion/accordion.module.ts","../../src/declarations/functions/get-initials.function.ts","../../src/components/avatar/components/avatar/avatar.component.ts","../../src/components/avatar/components/avatar/avatar.component.html","../../src/components/avatar/avatar.module.ts","../../src/components/badge/components/badge-indicator/badge-indicator.component.ts","../../src/components/badge/components/badge-indicator/badge-indicator.component.html","../../src/components/badge/components/badge-marker-block/badge-marker-block.component.ts","../../src/components/badge/components/badge-marker-block/badge-marker-block.component.html","../../src/components/badge/components/badge-marker/badge-marker.component.ts","../../src/components/badge/components/badge-marker/badge-marker.component.html","../../src/components/badge/components/badge/badge.component.ts","../../src/components/badge/components/badge/badge.component.html","../../src/components/badge/badge.module.ts","../../src/declarations/tokens/dropdown-container-data.token.ts","../../src/components/theme-wrapper/services/theme-wrapper.service.ts","../../src/components/theme-wrapper/components/theme-wrapper/theme-wrapper.component.ts","../../src/components/theme-wrapper/components/theme-wrapper/theme-wrapper.component.html","../../src/components/dropdown/components/dropdown-container/dropdown-container.component.ts","../../src/components/dropdown/components/dropdown-container/dropdown-container.component.html","../../src/declarations/classes/dropdown-ref.class.ts","../../src/declarations/classes/opened-dropdown.class.ts","../../src/declarations/classes/abstract/dropdown-component-base.abstract.ts","../../src/components/dropdown/components/dropdown-template/dropdown-template.component.ts","../../src/components/dropdown/components/dropdown-template/dropdown-template.component.html","../../src/services/dropdowns.service.ts","../../src/components/dropdown/directives/dropdown.directive.ts","../../src/components/theme-wrapper/theme-wrapper.module.ts","../../src/components/dropdown/directives/dropdown-template.directive.ts","../../src/components/dropdown/dropdown.module.ts","../../src/components/spinner/components/bagel-spinner/bagel-spinner.component.ts","../../src/components/spinner/components/bagel-spinner/bagel-spinner.component.html","../../src/components/spinner/components/spinner/spinner.component.ts","../../src/components/spinner/components/spinner/spinner.component.html","../../src/components/spinner/spinner.module.ts","../../src/components/buttons/components/button-icon/button-icon.component.ts","../../src/components/buttons/components/button-icon/button-icon.component.html","../../src/components/buttons/components/button/button.component.ts","../../src/components/buttons/components/button/button.component.html","../../src/components/buttons/components/button-multi/button-multi.component.ts","../../src/components/buttons/components/button-multi/button-multi.component.html","../../src/components/buttons/components/button-round/button-round.component.ts","../../src/components/buttons/components/button-round/button-round.component.html","../../src/components/buttons/buttons.module.ts","../../src/components/dropdown-menu/services/dropdown-menu-context.service.ts","../../src/components/option/directives/option-actions-right.directive.ts","../../src/components/checkbox/services/checkbox.service.ts","../../src/components/checkbox/components/checkbox/checkbox.component.ts","../../src/components/checkbox/components/checkbox/checkbox.component.html","../../src/components/option/components/option/option.component.ts","../../src/components/option/components/option/option.component.html","../../src/components/dropdown-menu/components/dropdown-menu-item/dropdown-menu-item.component.ts","../../src/components/dropdown-menu/components/dropdown-menu-item/dropdown-menu-item.component.html","../../src/components/dropdown-menu/components/dropdown-menu-separator/dropdown-menu-separator.component.ts","../../src/components/dropdown-menu/components/dropdown-menu-separator/dropdown-menu-separator.component.html","../../src/components/checkbox/checkbox.module.ts","../../src/components/option/components/option-description/option-description.component.ts","../../src/components/option/components/option-description/option-description.component.html","../../src/components/option/components/option-icon/option-icon.component.ts","../../src/components/option/components/option-icon/option-icon.component.html","../../src/components/option/components/option-title/option-title.component.ts","../../src/components/option/components/option-title/option-title.component.html","../../src/components/option/option.module.ts","../../src/components/scrollable/directives/scrollable-content.directive.ts","../../src/declarations/classes/scrollbar.class.ts","../../src/components/scrollable/components/scrollable/scrollable.component.ts","../../src/components/scrollable/components/scrollable/scrollable.component.html","../../src/components/scrollable/scrollable.module.ts","../../src/components/dropdown-menu/components/dropdown-menu/dropdown-menu.component.ts","../../src/components/dropdown-menu/components/dropdown-menu/dropdown-menu.component.html","../../src/components/dropdown-menu/dropdown-menu.module.ts","../../src/declarations/tokens/tooltip-service.token.ts","../../src/components/tooltip/components/tooltip-content/tooltip-content.component.ts","../../src/components/tooltip/components/tooltip-content/tooltip-content.component.html","../../src/components/tooltip/positions.ts","../../src/components/tooltip/services/tooltip.service.ts","../../src/components/tooltip/directives/tooltip.directive.ts","../../src/components/tooltip/tooltip.module.ts","../../src/components/breadcrumbs/components/breadcrumb-separator/breadcrumb-separator.component.ts","../../src/components/breadcrumbs/components/breadcrumb-separator/breadcrumb-separator.component.html","../../src/components/breadcrumbs/components/breadcrumb-unfit-trigger/breadcrumb-unfit-trigger.component.ts","../../src/components/breadcrumbs/components/breadcrumb-unfit-trigger/breadcrumb-unfit-trigger.component.html","../../src/components/breadcrumbs/components/breadcrumb/breadcrumb.component.ts","../../src/components/breadcrumbs/components/breadcrumb/breadcrumb.component.html","../../src/declarations/classes/breadcrumbs-producer.class.ts","../../src/components/breadcrumbs/directives/breadcrumb-template.directive.ts","../../src/components/breadcrumbs/components/breadcrumbs/breadcrumbs.component.ts","../../src/components/breadcrumbs/components/breadcrumbs/breadcrumbs.component.html","../../src/components/breadcrumbs/breadcrumbs.module.ts","../../src/declarations/classes/abstract/tabs-service-base.abstract.ts","../../src/declarations/tokens/button-group-state-service.token.ts","../../src/components/button-group/services/button-group-state.service.ts","../../src/components/button-group/components/button-group-container/button-group-container.component.ts","../../src/components/button-group/components/button-group-container/button-group-container.component.html","../../src/declarations/classes/abstract/tabs-content-base.abstract.ts","../../src/components/button-group/directives/button-group-item-content-template.directive.ts","../../src/components/button-group/components/button-group-content/button-group-content.component.ts","../../src/components/button-group/components/button-group-content/button-group-content.component.html","../../src/declarations/classes/abstract/tabs-item-base.abstract.ts","../../src/components/button-group/components/button-group-item/button-group-item.component.ts","../../src/components/button-group/components/button-group-item/button-group-item.component.html","../../src/declarations/classes/abstract/tabs-base.abstract.ts","../../src/components/button-group/components/button-group/button-group.component.ts","../../src/components/button-group/components/button-group/button-group.component.html","../../src/components/button-group/button-group.module.ts","../../src/components/card/components/card-action/card-action.component.ts","../../src/components/card/components/card-action/card-action.component.html","../../src/components/card/components/card-container/card-container.component.ts","../../src/components/card/components/card-container/card-container.component.html","../../src/components/card/components/card-cover/card-cover.component.ts","../../src/components/card/components/card-cover/card-cover.component.html","../../src/components/card/components/card-description/card-description.component.ts","../../src/components/card/components/card-description/card-description.component.html","../../src/components/card/components/card-header/card-header.component.ts","../../src/components/card/components/card-header/card-header.component.html","../../src/components/card/components/card-title/card-title.component.ts","../../src/components/card/components/card-title/card-title.component.html","../../src/components/card/service/card-state.service.ts","../../src/components/card/components/card/card.component.ts","../../src/components/card/components/card/card.component.html","../../src/components/card/card.module.ts","../../src/components/counter/components/counter/counter.component.ts","../../src/components/counter/components/counter/counter.component.html","../../src/components/counter/counter.module.ts","../../src/components/icon-holder/components/icon-holder/icon-holder.component.ts","../../src/components/icon-holder/components/icon-holder/icon-holder.component.html","../../src/components/icon-holder/icon-holder.module.ts","../../src/services/grid-state.service.ts","../../src/services/loader.service.ts","../../src/components/layout/components/layout/layout.component.ts","../../src/components/layout/components/layout/layout.component.html","../../src/components/layout/components/loader/loader.component.ts","../../src/components/layout/components/loader/loader.component.html","../../src/components/layout/layout.module.ts","../../src/components/link/components/link/link.component.ts","../../src/components/link/components/link/link.component.html","../../src/components/link/link.module.ts","../../src/components/progress-bar/components/progress-bar/progress-bar.component.ts","../../src/components/progress-bar/components/progress-bar/progress-bar.component.html","../../src/components/progress-bar/progress-bar.module.ts","../../src/components/section/components/section-container/section-container.component.ts","../../src/components/section/components/section-container/section-container.component.html","../../src/components/section/components/section-sub-title/section-sub-title.component.ts","../../src/components/section/components/section-sub-title/section-sub-title.component.html","../../src/components/section/components/section-title/section-title.component.ts","../../src/components/section/components/section-title/section-title.component.html","../../src/components/section/section.module.ts","../../src/components/skeleton/components/skeleton-group/skeleton-group.component.ts","../../src/components/skeleton/components/skeleton-group/skeleton-group.component.html","../../src/components/skeleton/components/skeleton/skeleton.component.ts","../../src/components/skeleton/components/skeleton/skeleton.component.html","../../src/components/skeleton/components/skeleton-line/skeleton-line.component.ts","../../src/components/skeleton/components/skeleton-line/skeleton-line.component.html","../../src/components/skeleton/skeleton.module.ts","../../src/components/status/components/status/status.component.ts","../../src/components/status/components/status/status.component.html","../../src/components/status/status.module.ts","../../src/declarations/tokens/stepper-container-state-service.token.ts","../../src/components/stepper/services/stepper-state.service.ts","../../src/components/stepper/components/stepper-container/stepper-container.component.ts","../../src/components/stepper/components/stepper-container/stepper-container.component.html","../../src/components/tabs/services/tabs-state.service.ts","../../src/components/stepper/directives/stepper-item-content.directive.ts","../../src/components/stepper/components/stepper-content/stepper-content.component.ts","../../src/components/stepper/components/stepper-content/stepper-content.component.html","../../src/components/stepper/components/stepper-counter/stepper-counter.component.ts","../../src/components/stepper/components/stepper-counter/stepper-counter.component.html","../../src/components/stepper/services/stepper-registry.service.ts","../../src/components/stepper/components/stepper-item/stepper-item.component.ts","../../src/components/stepper/components/stepper-item/stepper-item.component.html","../../src/components/stepper/components/stepper/stepper.component.ts","../../src/components/stepper/components/stepper/stepper.component.html","../../src/components/stepper/stepper.module.ts","../../src/declarations/tokens/tabs-container-state-service.token.ts","../../src/components/tabs/components/tabs-container/tabs-container.component.ts","../../src/components/tabs/components/tabs-container/tabs-container.component.html","../../src/components/tabs/directives/tabs-item-content-template.directive.ts","../../src/components/tabs/components/tabs-content/tabs-content.component.ts","../../src/components/tabs/components/tabs-content/tabs-content.component.html","../../src/components/tabs/components/tabs-item/tabs-item.component.ts","../../src/components/tabs/components/tabs-item/tabs-item.component.html","../../src/components/tabs/components/tabs-separator/tabs-separator.component.ts","../../src/components/tabs/components/tabs-separator/tabs-separator.component.html","../../src/components/tabs/components/tabs/tabs.component.ts","../../src/components/tabs/components/tabs/tabs.component.html","../../src/components/tabs/tabs.module.ts","../../src/components/tag/services/tag-state.service.ts","../../src/components/tag/components/pupa-tag-delete-button/pupa-tag-delete-button.component.ts","../../src/components/tag/components/pupa-tag-delete-button/pupa-tag-delete-button.component.html","../../src/components/tag/components/pupa-tag-text/pupa-tag-text.component.ts","../../src/components/tag/components/pupa-tag-text/pupa-tag-text.component.html","../../src/components/tag/components/tag-action-button/tag-action-button.component.ts","../../src/components/tag/components/tag-action-button/tag-action-button.component.html","../../src/declarations/classes/abstract/tag-base.abstract.ts","../../src/components/tag/components/tag-inline/tag-inline.component.ts","../../src/components/tag/components/tag-inline/tag-inline.component.html","../../src/components/tag/directives/tag-action-button-template.directive.ts","../../src/components/tag/components/tag/tag.component.ts","../../src/components/tag/components/tag/tag.component.html","../../src/components/tag/tag.module.ts","../../src/components/timer/components/timer-round/timer-round.component.ts","../../src/components/timer/components/timer-round/timer-round.component.html","../../src/components/timer/timer.module.ts","../../src/kit.module.ts"],"sourcesContent":["import { animate, state, style, transition, trigger } from '@angular/animations';\nimport {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n EventEmitter,\n Input,\n OnChanges,\n Output,\n ViewEncapsulation,\n} from '@angular/core';\nimport { AccordionKind } from '../../../../declarations/types/accordion-kind.type';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { ComponentChanges, ComponentChange } from '@bimeister/pupakit.common';\n\nenum AnimationState {\n Void = 'void',\n Expanded = 'expanded',\n}\n\nconst TRANSITION: string = '300ms ease-in-out';\n\n@Component({\n selector: 'pupa-accordion',\n templateUrl: './accordion.component.html',\n styleUrls: ['./accordion.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n animations: [\n trigger('accordionExpanded', [\n state(AnimationState.Void, style({ opacity: '0', height: '0px', visibility: 'hidden', overflow: 'hidden' })),\n state(AnimationState.Expanded, style({ height: '*', overflow: 'hidden' })),\n transition(`${AnimationState.Expanded} => ${AnimationState.Void}`, animate(TRANSITION)),\n transition(`${AnimationState.Void} => ${AnimationState.Expanded}`, animate(TRANSITION)),\n ]),\n trigger('arrowRotated', [\n state(AnimationState.Void, style({ transform: 'rotate(0)' })),\n state(AnimationState.Expanded, style({ transform: 'rotate(180deg)' })),\n transition(`${AnimationState.Expanded} => ${AnimationState.Void}`, animate(TRANSITION)),\n transition(`${AnimationState.Void} => ${AnimationState.Expanded}`, animate(TRANSITION)),\n ]),\n ],\n})\nexport class AccordionComponent implements OnChanges {\n @Input() public showArrow: boolean = true;\n\n @Input() public destroyable: boolean = true;\n\n @Input() public kind: AccordionKind = 'normal';\n public readonly kind$: BehaviorSubject<AccordionKind> = new BehaviorSubject<AccordionKind>(this.kind);\n\n @Input() public expanded: boolean = false;\n @Output() public readonly expandedChange: EventEmitter<boolean> = new EventEmitter<boolean>();\n public readonly expanded$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(this.expanded);\n\n public readonly animationState$: Observable<AnimationState> = this.expanded$.pipe(\n map((expanded: boolean) => (expanded ? AnimationState.Expanded : AnimationState.Void))\n );\n\n public readonly accordionClass$: Observable<string> = this.kind$.pipe(\n map((kind: AccordionKind) => `accordion_${kind}`)\n );\n\n constructor(private readonly changeDetectionRef: ChangeDetectorRef) {}\n\n public ngOnChanges(changes: ComponentChanges<this>): void {\n if (changes.hasOwnProperty('kind')) {\n this.processKindChange(changes.kind);\n }\n\n if (changes.hasOwnProperty('expanded')) {\n this.processExpandedChange(changes.expanded);\n }\n }\n\n public toggle(): void {\n this.updateExpanded(!this.expanded);\n }\n\n public collapse(): void {\n this.updateExpanded(false);\n }\n\n private updateExpanded(expanded: boolean): void {\n if (this.expanded === expanded) {\n return;\n }\n\n this.expanded = expanded;\n this.expandedChange.emit(expanded);\n this.expanded$.next(expanded);\n this.changeDetectionRef.detectChanges();\n }\n\n private processExpandedChange(expanded: ComponentChange<this, boolean>): void {\n this.expanded$.next(expanded.currentValue);\n }\n\n private processKindChange(kind: ComponentChange<this, AccordionKind>): void {\n this.kind$.next(kind.currentValue);\n }\n}\n","<div class=\"accordion\" [ngClass]=\"accordionClass$ | async\" [class.accordion_expanded]=\"expanded$ | async\">\n <div class=\"accordion-header\" [class.accordion-header_expanded]=\"expanded$ | async\" (click)=\"toggle()\">\n <div class=\"accordion-header__content\" [class.accordion-header__content_with-arrow]=\"showArrow\">\n <ng-content></ng-content>\n </div>\n\n <ng-container *ngIf=\"showArrow\">\n <div class=\"arrow-container\">\n <pupa-icon name=\"app-chevron-down\" [@arrowRotated]=\"animationState$ | async\"></pupa-icon>\n </div>\n </ng-container>\n </div>\n\n <ng-container *ngIf=\"!destroyable || (expanded$ | async)\">\n <div class=\"accordion-body\" [@accordionExpanded]=\"animationState$ | async\">\n <ng-content select=\"pupa-accordion-body\"></ng-content>\n </div>\n </ng-container>\n</div>\n","import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'pupa-accordion-header',\n templateUrl: './accordion-header.component.html',\n styleUrls: ['./accordion-header.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AccordionHeaderComponent {}\n","<ng-content></ng-content>\n","import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'pupa-accordion-description',\n templateUrl: './accordion-description.component.html',\n styleUrls: ['./accordion-description.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AccordionDescriptionComponent {}\n","<ng-content></ng-content>\n","import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'pupa-accordion-title',\n templateUrl: './accordion-title.component.html',\n styleUrls: ['./accordion-title.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AccordionTitleComponent {}\n","<ng-content></ng-content>\n","import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'pupa-accordion-body',\n templateUrl: './accordion-body.component.html',\n styleUrls: ['./accordion-body.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AccordionBodyComponent {}\n","<ng-content></ng-content>\n","import {\n AfterContentInit,\n ChangeDetectionStrategy,\n Component,\n ContentChildren,\n Input,\n OnDestroy,\n QueryList,\n ViewEncapsulation,\n} from '@angular/core';\nimport { filterNotNil, filterTruthy } from '@bimeister/utilities';\nimport { AccordionComponent } from '../accordion/accordion.component';\nimport { merge, Observable, Subscription } from 'rxjs';\nimport { filter, map, mapTo, pairwise, startWith, switchMap } from 'rxjs/operators';\n\n@Component({\n selector: 'pupa-accordion-group',\n templateUrl: './accordion-group.component.html',\n styleUrls: ['./accordion-group.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AccordionGroupComponent implements OnDestroy, AfterContentInit {\n @Input() public readonly closeOthers: boolean = true;\n\n @ContentChildren(AccordionComponent) public readonly accordionList: QueryList<AccordionComponent>;\n\n private readonly subscription: Subscription = new Subscription();\n\n public ngOnDestroy(): void {\n this.subscription.unsubscribe();\n }\n\n public ngAfterContentInit(): void {\n this.subscription.add(this.processCloseOthers());\n }\n\n private processCloseOthers(): Subscription {\n const accordionList$: Observable<AccordionComponent[]> = this.accordionList.changes.pipe(\n map((accordion: QueryList<AccordionComponent>) => accordion.toArray()),\n startWith(this.accordionList.toArray())\n );\n\n const justAddedAccordionExpanded$: Observable<AccordionComponent> = accordionList$.pipe(\n pairwise(),\n map(([previousAccordionList, currentAccordionList]: [AccordionComponent[], AccordionComponent[]]) =>\n currentAccordionList.find(\n (accordion: AccordionComponent) => !previousAccordionList.includes(accordion) && accordion.expanded\n )\n ),\n filterNotNil()\n );\n\n const existingAccordionExpanded$: Observable<AccordionComponent> = accordionList$.pipe(\n switchMap((accordionList: AccordionComponent[]) =>\n merge(\n ...accordionList.map((accordion: AccordionComponent) =>\n accordion.expanded$.pipe(filterTruthy(), mapTo(accordion))\n )\n )\n )\n );\n\n return merge(justAddedAccordionExpanded$, existingAccordionExpanded$)\n .pipe(filter(() => this.closeOthers))\n .subscribe((expandedAccordion: AccordionComponent) => {\n this.accordionList.forEach((accordion: AccordionComponent) => {\n if (expandedAccordion !== accordion && accordion.expanded) {\n accordion.collapse();\n }\n });\n });\n }\n}\n","<ng-content select=\"pupa-accordion\"></ng-content>\n","import { NgModule, Type } from '@angular/core';\nimport { AccordionComponent } from './components/accordion/accordion.component';\nimport { AccordionHeaderComponent } from './components/accordion-header/accordion-header.component';\nimport { AccordionDescriptionComponent } from './components/accordion-description/accordion-description.component';\nimport { AccordionTitleComponent } from './components/accordion-title/accordion-title.component';\nimport { AccordionBodyComponent } from './components/accordion-body/accordion-body.component';\nimport { AccordionGroupComponent } from './components/accordion-group/accordion-group.component';\nimport { CommonModule } from '@angular/common';\nimport { PupaIconsModule } from '@bimeister/pupakit.icons';\n\nconst COMPONENTS: Type<unknown>[] = [\n AccordionComponent,\n AccordionHeaderComponent,\n AccordionTitleComponent,\n AccordionDescriptionComponent,\n AccordionBodyComponent,\n AccordionGroupComponent,\n];\n\n@NgModule({\n declarations: [...COMPONENTS],\n imports: [CommonModule, PupaIconsModule],\n exports: [...COMPONENTS],\n})\nexport class PupaAccordionModule {}\n","import { isEmpty, isNil, Nullable } from '@bimeister/utilities';\n\nexport function getInitials(name: Nullable<string>): string {\n if (isNil(name)) {\n return '';\n }\n const nameSectionsList: string[] = name.trim().split(' ');\n const notEmptyNameSectionsList: string[] = nameSectionsList.filter((item: string) => !isEmpty(item));\n const firstName: string = notEmptyNameSectionsList?.[0]?.trimStart();\n const secondName: string = notEmptyNameSectionsList?.[1]?.trimStart();\n if (isEmpty(firstName)) {\n return '';\n }\n if (isEmpty(secondName)) {\n return firstName[0].toUpperCase();\n }\n return `${firstName[0]}${secondName[0]}`.toUpperCase();\n}\n","import { ChangeDetectionStrategy, Component, Input, OnChanges, ViewEncapsulation } from '@angular/core';\nimport { ComponentChanges, ComponentChange } from '@bimeister/pupakit.common';\nimport { getHslColorFromString, HslColor, isEmpty, isNil, Nullable } from '@bimeister/utilities';\nimport { BehaviorSubject, combineLatest, Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { AvatarSize } from '../../../../declarations/types/avatar-size.type';\nimport { getInitials } from '../../../../declarations/functions/get-initials.function';\n\nconst SATURATION: number = 88;\nconst LIGHTNESS: number = 78;\n\nenum Mode {\n Icon = 'icon',\n Image = 'image',\n Username = 'username',\n Default = 'default',\n}\n\n@Component({\n selector: 'pupa-avatar',\n templateUrl: './avatar.component.html',\n styleUrls: ['./avatar.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AvatarComponent implements OnChanges {\n @Input() public username: string;\n public readonly username$: BehaviorSubject<Nullable<string>> = new BehaviorSubject<Nullable<string>>(null);\n\n @Input() public iconName: string;\n public readonly iconName$: BehaviorSubject<Nullable<string>> = new BehaviorSubject<Nullable<string>>(null);\n\n @Input() public src: string;\n public readonly src$: BehaviorSubject<Nullable<string>> = new BehaviorSubject<Nullable<string>>(null);\n\n @Input() public size: AvatarSize = 'small';\n public readonly size$: BehaviorSubject<AvatarSize> = new BehaviorSubject<AvatarSize>('small');\n\n @Input() public withBorder: boolean = false;\n public readonly withBorder$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n @Input() public disabled: boolean = false;\n public readonly disabled$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n\n public readonly resultClassList$: Observable<string[]> = combineLatest([\n this.size$,\n this.withBorder$.pipe(map((withBorder: boolean) => (Boolean(withBorder) ? 'bordered' : null))),\n ]).pipe(\n map((classes: string[]) =>\n classes\n .filter((innerClass: string) => !isNil(innerClass))\n .map((innerProperty: string) => `avatar_${innerProperty}`)\n )\n );\n\n public readonly isEmptyUserName$: Observable<boolean> = this.username$.pipe(map(isEmpty));\n\n public readonly hslBackgroundColor$: Observable<string> = combineLatest([this.username$, this.disabled$]).pipe(\n map(([username, isDisabled]: [Nullable<string>, boolean]) => {\n if (isEmpty(username) || isDisabled) {\n return null;\n }\n const { h, s, l }: HslColor = getHslColorFromString(username, SATURATION, LIGHTNESS);\n return `hsl(${h}, ${s}%, ${l}%)`;\n })\n );\n public readonly initials$: Observable<Nullable<string>> = this.username$.pipe(\n map((username: Nullable<string>) => getInitials(username))\n );\n\n public readonly backgroundImage$: Observable<string> = this.src$.pipe(\n map((src: Nullable<string>) => `url('${src ?? ''}')`)\n );\n\n public readonly mode$: Observable<Mode> = combineLatest([this.iconName$, this.src$, this.username$]).pipe(\n map(([iconName, src, username]: [Nullable<string>, Nullable<string>, Nullable<string>]) => {\n if (!isNil(iconName)) {\n return Mode.Icon;\n }\n if (!isNil(src)) {\n return Mode.Image;\n }\n if (!isNil(username)) {\n return Mode.Username;\n }\n\n return Mode.Default;\n })\n );\n public readonly mode: typeof Mode = Mode;\n\n public ngOnChanges(changes: ComponentChanges<this>): void {\n this.processUsernameChange(changes?.username);\n this.processIconNameChange(changes?.iconName);\n this.processSrcChange(changes?.src);\n this.processSizeChange(changes?.size);\n this.processWithBorderChange(changes?.withBorder);\n this.processDisabledChange(changes?.disabled);\n }\n\n private processUsernameChange(change: ComponentChange<this, string>): void {\n const updatedValue: string | undefined = change?.currentValue;\n\n if (typeof updatedValue !== 'string') {\n return;\n }\n if (isEmpty(updatedValue.trim())) {\n return this.username$.next(null);\n }\n this.username$.next(updatedValue);\n }\n private processIconNameChange(change: ComponentChange<this, string>): void {\n const updatedValue: string | undefined = change?.currentValue;\n\n if (isNil(updatedValue)) {\n return;\n }\n\n const serializedValue: string = isEmpty(updatedValue) ? null : updatedValue;\n this.iconName$.next(serializedValue);\n }\n\n private processSrcChange(change: ComponentChange<this, string>): void {\n const updatedValue: string | undefined = change?.currentValue;\n\n if (isNil(updatedValue)) {\n return;\n }\n\n const serializedValue: string = isEmpty(updatedValue) ? null : updatedValue;\n this.src$.next(serializedValue);\n }\n\n private processSizeChange(change: ComponentChange<this, AvatarSize>): void {\n const updatedValue: AvatarSize | undefined = change?.currentValue;\n\n if (isNil(updatedValue)) {\n return;\n }\n\n this.size$.next(updatedValue);\n }\n\n private processWithBorderChange(change: ComponentChange<this, boolean>): void {\n const updatedValue: boolean | undefined = change?.currentValue;\n\n if (isNil(updatedValue)) {\n return;\n }\n this.withBorder$.next(updatedValue);\n }\n\n private processDisabledChange(change: ComponentChange<this, boolean>): void {\n const updatedValue: boolean | undefined = change?.currentValue;\n\n if (isNil(updatedValue)) {\n return;\n }\n this.disabled$.next(updatedValue);\n }\n}\n","<div\n class=\"avatar\"\n [ngClass]=\"resultClassList$ | async\"\n [style.background-color]=\"hslBackgroundColor$ | async\"\n [class.avatar_default]=\"isEmptyUserName$ | async\"\n [class.avatar_disabled]=\"disabled$ | async\"\n [ngSwitch]=\"mode$ | async\"\n>\n <ng-container *ngSwitchCase=\"mode.Icon\" [ngTemplateOutlet]=\"iconTemplate\"></ng-container>\n <ng-container *ngSwitchCase=\"mode.Image\" [ngTemplateOutlet]=\"imageTemplate\"></ng-container>\n <ng-container *ngSwitchCase=\"mode.Username\" [ngTemplateOutlet]=\"usernameTemplate\"></ng-container>\n <ng-container *ngSwitchDefault [ngTemplateOutlet]=\"defaultTemplate\"></ng-container>\n</div>\n\n<ng-template #iconTemplate>\n <div class=\"avatar__icon-container\">\n <pupa-icon class=\"avatar__icon\" [name]=\"iconName$ | async\"></pupa-icon>\n </div>\n</ng-template>\n\n<ng-template #imageTemplate>\n <div class=\"avatar__image-container\" [style.background-image]=\"backgroundImage$ | async\"></div>\n</ng-template>\n\n<ng-template #usernameTemplate>\n <div class=\"avatar__text\">{{ initials$ | async }}</div>\n</ng-template>\n\n<ng-template #defaultTemplate>\n <div class=\"avatar__icon-container\">\n <pupa-icon class=\"avatar__icon\" [name]=\"'app-user'\"></pupa-icon>\n </div>\n</ng-template>\n","import { CommonModule } from '@angular/common';\nimport { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';\nimport { PupaPipesModule } from '@bimeister/pupakit.common';\nimport { mdPersonIcon, PupaIconsModule } from '@bimeister/pupakit.icons';\nimport { AvatarComponent } from './components/avatar/avatar.component';\n\n@NgModule({\n declarations: [AvatarComponent],\n exports: [AvatarComponent],\n imports: [CommonModule, PupaIconsModule.forFeature([mdPersonIcon]), PupaPipesModule],\n schemas: [CUSTOM_ELEMENTS_SCHEMA],\n})\nexport class PupaAvatarModule {}\n","import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';\n\ntype BadgeIndicatorState = 'progress' | 'complete' | 'error';\n\n@Component({\n selector: 'pupa-badge-indicator',\n templateUrl: './badge-indicator.component.html',\n styleUrls: ['./badge-indicator.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class BadgeIndicatorComponent {\n @Input() public readonly state: BadgeIndicatorState = 'progress';\n\n public readonly icons: Map<BadgeIndicatorState, string> = new Map([\n ['complete', 'app-exceptions-check-4'],\n ['error', 'app-exceptions-cross-4'],\n ]);\n}\n","<span class=\"badge-indicator\" [ngClass]=\"state\">\n <ng-container *ngIf=\"state === 'progress'; else iconBadge\">\n <span class=\"badge-indicator__icon outer-circle\"></span>\n <span class=\"badge-indicator__icon inner-circle\"></span>\n </ng-container>\n</span>\n<ng-template #iconBadge>\n <ng-container *ngIf=\"icons.get(state) as name\">\n <pupa-icon class=\"badge-indicator__icon\" [name]=\"name\"></pupa-icon>\n </ng-container>\n</ng-template>\n","import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'pupa-badge-marker-block',\n templateUrl: './badge-marker-block.component.html',\n styleUrls: ['./badge-marker-block.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class BadgeMarkerBlockComponent {}\n","<span class=\"badge-marker-block\">\n <ng-content></ng-content>\n</span>\n","import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';\nimport { BadgeSize } from '../../../../declarations/types/badge-size.type';\n\n@Component({\n selector: 'pupa-badge-marker',\n templateUrl: './badge-marker.component.html',\n styleUrls: ['./badge-marker.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class BadgeMarkerComponent {\n @Input() public readonly size: BadgeSize = 'medium';\n}\n","<span\n class=\"badge\"\n [ngClass]=\"{\n badge__medium: size === 'medium',\n badge__small: size === 'small'\n }\"\n>\n <ng-content></ng-content>\n</span>\n","import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'pupa-badge',\n templateUrl: './badge.component.html',\n styleUrls: ['./badge.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class BadgeComponent {}\n","<ng-content> </ng-content>\n","import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { PupaIconsModule } from '@bimeister/pupakit.icons';\nimport { BadgeIndicatorComponent } from './components/badge-indicator/badge-indicator.component';\nimport { BadgeMarkerBlockComponent } from './components/badge-marker-block/badge-marker-block.component';\nimport { BadgeMarkerComponent } from './components/badge-marker/badge-marker.component';\nimport { BadgeComponent } from './components/badge/badge.component';\n\n@NgModule({\n declarations: [BadgeComponent, BadgeMarkerComponent, BadgeIndicatorComponent, BadgeMarkerBlockComponent],\n imports: [CommonModule, PupaIconsModule],\n exports: [BadgeComponent, BadgeMarkerComponent, BadgeIndicatorComponent, BadgeMarkerBlockComponent],\n})\nexport class PupaBadgeModule {}\n","import { InjectionToken } from '@angular/core';\nimport { DropdownContainerData } from '../../declarations/interfaces/dropdown-container-data.interface';\n\nexport const DROPDOWN_CONTAINER_DATA_TOKEN: InjectionToken<DropdownContainerData<unknown>> = new InjectionToken<\n DropdownContainerData<unknown>\n>('DROPDOWN_CONTAINER_DATA_TOKEN');\n","import { Injectable } from '@angular/core';\nimport { DARK_THEME_CLASS, LIGHT_THEME_CLASS, Theme, ThemeService } from '@bimeister/pupakit.common';\nimport { Nullable } from '@bimeister/utilities';\nimport { BehaviorSubject, combineLatest, Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\n@Injectable()\nexport class ThemeWrapperService {\n private readonly themeState$: BehaviorSubject<Nullable<Theme>> = new BehaviorSubject<Nullable<Theme>>(null);\n\n public readonly theme$: Observable<Theme> = combineLatest([this.themeService.theme$, this.themeState$]).pipe(\n map(([globalTheme, localTheme]: [Theme, Theme]) => localTheme ?? globalTheme)\n );\n\n public readonly themeClass$: Observable<string> = this.theme$.pipe(\n map((theme: Theme) => (theme === Theme.Dark ? DARK_THEME_CLASS : LIGHT_THEME_CLASS))\n );\n\n constructor(private readonly themeService: ThemeService) {}\n\n public setTheme(theme: Theme): void {\n this.themeState$.next(theme);\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n Input,\n OnChanges,\n OnDestroy,\n OnInit,\n Renderer2,\n ViewEncapsulation,\n} from '@angular/core';\nimport { ComponentChange, ComponentChanges, Theme } from '@bimeister/pupakit.common';\nimport { isNil } from '@bimeister/utilities';\nimport { BehaviorSubject, Subscription } from 'rxjs';\nimport { distinctUntilChanged, withLatestFrom } from 'rxjs/operators';\nimport { ThemeWrapperService } from '../../services/theme-wrapper.service';\n\n@Component({\n selector: 'pupa-theme-wrapper',\n templateUrl: './theme-wrapper.component.html',\n styleUrls: ['./theme-wrapper.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [ThemeWrapperService],\n})\nexport class ThemeWrapperComponent implements OnChanges, OnInit, OnDestroy {\n @Input() public theme: Theme;\n\n private readonly themeClass$: BehaviorSubject<string | null> = new BehaviorSubject<string | null>(null);\n\n private readonly subscription: Subscription = new Subscription();\n\n constructor(\n private readonly themeWrapperService: ThemeWrapperService,\n private readonly renderer: Renderer2,\n private readonly hostElement: ElementRef\n ) {}\n\n public ngOnInit(): void {\n this.subscription.add(this.processThemeClass());\n }\n\n public ngOnDestroy(): void {\n this.subscription.unsubscribe();\n }\n\n public ngOnChanges(changes: ComponentChanges<this>): void {\n this.processThemeChange(changes?.theme);\n }\n\n private processThemeChange(change: ComponentChange<this, Theme>): void {\n this.themeWrapperService.setTheme(change?.currentValue);\n }\n\n private processThemeClass(): Subscription {\n return this.themeWrapperService.themeClass$\n .pipe(distinctUntilChanged(), withLatestFrom(this.themeClass$))\n .subscribe(([themeClass, localThemeClass]: [string, string | null]) => {\n this.renderer.addClass(this.hostElement.nativeElement, themeClass);\n\n if (!isNil(localThemeClass)) {\n this.renderer.removeClass(this.hostElement.nativeElement, localThemeClass);\n }\n\n this.themeClass$.next(themeClass);\n });\n }\n}\n","<ng-content></ng-content>\n","import { ComponentPortal } from '@angular/cdk/portal';\nimport { ChangeDetectionStrategy, Component, Inject, ViewEncapsulation } from '@angular/core';\nimport { Theme } from '@bimeister/pupakit.common';\nimport { DROPDOWN_CONTAINER_DATA_TOKEN } from '../../../../declarations/tokens/dropdown-container-data.token';\nimport { DropdownContainerData } from '../../../../declarations/interfaces/dropdown-container-data.interface';\n\n@Component({\n selector: 'pupa-dropdown-container',\n templateUrl: './dropdown-container.component.html',\n styleUrls: ['./dropdown-container.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DropdownContainerComponent {\n public readonly componentPortal: ComponentPortal<DropdownContainerComponent> = this.componentData.componentPortal;\n public readonly theme: Theme = this.componentData.theme;\n\n constructor(\n @Inject(DROPDOWN_CONTAINER_DATA_TOKEN)\n private readonly componentData: DropdownContainerData<DropdownContainerComponent>\n ) {}\n\n public stopEvent(event: Event): void {\n event.stopPropagation();\n }\n}\n","<pupa-theme-wrapper class=\"theme-container\" [theme]=\"theme\">\n <div\n class=\"content-container\"\n (mousedown)=\"stopEvent($event)\"\n (touchstart)=\"stopEvent($event)\"\n (touchmove)=\"stopEvent($event)\"\n (wheel)=\"stopEvent($event)\"\n >\n <ng-template [cdkPortalOutlet]=\"componentPortal\"></ng-template>\n </div>\n</pupa-theme-wrapper>\n","import { OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { Observable, Subject } from 'rxjs';\nimport { DropdownContainerComponent } from '../../components/dropdown/components/dropdown-container/dropdown-container.component';\nimport { DropdownConfig } from '../interfaces/dropdown-config.interface';\n\nexport class DropdownRef<TData = unknown> {\n private readonly closedSubject$: Subject<void> = new Subject<void>();\n public readonly closed$: Observable<void> = this.closedSubject$.asObservable();\n\n constructor(private readonly overlayRef: OverlayRef, public readonly config: DropdownConfig<unknown, TData>) {}\n\n public close(): void {\n this.overlayRef.dispose();\n this.closedSubject$.next();\n this.closedSubject$.complete();\n }\n\n public open(componentPortal: ComponentPortal<DropdownContainerComponent>): void {\n this.overlayRef.attach(componentPortal);\n }\n}\n","import { Observable } from 'rxjs';\nimport { DropdownRef } from './dropdown-ref.class';\n\nexport class OpenedDropdown {\n public readonly closed$: Observable<void> = this.dropdownRef.closed$;\n\n constructor(public readonly id: string, private readonly dropdownRef: DropdownRef) {}\n\n public close(): void {\n this.dropdownRef.close();\n }\n}\n","import { animate, AnimationTriggerMetadata, state, style, transition, trigger } from '@angular/animations';\nimport { DOCUMENT } from '@angular/common';\nimport { AfterViewInit, Directive, Inject } from '@angular/core';\nimport { VOID } from '@bimeister/utilities';\nimport { asapScheduler, BehaviorSubject, fromEvent, merge, Observable, of, scheduled } from 'rxjs';\nimport { take } from 'rxjs/operators';\nimport { DropdownRef } from '../dropdown-ref.class';\n\n@Directive()\nexport abstract class DropdownComponentBase<TData> implements AfterViewInit {\n public readonly data: TData = this.dropdownRef.config.data;\n\n private readonly animationStateSubject$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);\n public readonly animationState$: Observable<boolean> = this.animationStateSubject$.asObservable();\n\n public static readonly animations: AnimationTriggerMetadata[] = [\n trigger('show', [\n state('false', style({ transform: 'translateY(10px)', opacity: 0 })),\n state('true', style({ transform: 'translateY(0)', opacity: 1 })),\n transition('false => true', [animate(`150ms ease-in`)]),\n transition('true => false', [animate(`150ms ease-out`)]),\n ]),\n ];\n\n constructor(\n protected readonly dropdownRef: DropdownRef<TData>,\n @Inject(DOCUMENT) private readonly document: Document\n ) {\n this.listenOutsideEventsForClose();\n }\n\n public ngAfterViewInit(): void {\n scheduled(of(VOID), asapScheduler)\n .pipe(take(1))\n .subscribe(() => this.setAnimationState(true));\n\n this.dropdownRef.closed$.pipe(take(1)).subscribe(() => this.setAnimationState(false));\n }\n\n private setAnimationState(animationState: boolean): void {\n this.animationStateSubject$.next(animationState);\n }\n\n private listenOutsideEventsForClose(): void {\n const touchMove$: Observable<MouseEvent> = fromEvent<MouseEvent>(this.document, 'touchmove');\n const wheel$: Observable<MouseEvent> = fromEvent<MouseEvent>(this.document, 'wheel');\n const resize$: Observable<MouseEvent> = fromEvent<MouseEvent>(window, 'resize');\n\n merge(touchMove$, wheel$, resize$)\n .pipe(take(1))\n .subscribe(() => this.dropdownRef.close());\n }\n}\n","import { ChangeDetectionStrategy, Component, TemplateRef, ViewEncapsulation } from '@angular/core';\nimport { DropdownTemplateContext } from '../../../../declarations/interfaces/dropdown-template-context.interface';\nimport { DropdownComponentBase } from '../../../../declarations/classes/abstract/dropdown-component-base.abstract';\nimport { DropdownTemplateData } from '../../../../declarations/interfaces/dropdown-template-data.interface';\n\n@Component({\n selector: 'pupa-dropdown-template',\n templateUrl: './dropdown-template.component.html',\n styleUrls: ['./dropdown-template.component.scss'],\n encapsulation: ViewEncapsulation.Emulated,\n changeDetection: ChangeDetectionStrategy.OnPush,\n animations: DropdownComponentBase.animations,\n})\nexport class DropdownTemplateComponent<TContext> extends DropdownComponentBase<DropdownTemplateData<TContext>> {\n public readonly templateRef: TemplateRef<TContext> = this.data?.templateRef;\n public readonly templateContext: DropdownTemplateContext = { $implicit: this.dropdownRef };\n}\n","<div class=\"dropdown-container\" [@show]=\"animationState$ | async\">\n <ng-container [ngTemplateOutlet]=\"templateRef\" [ngTemplateOutletContext]=\"templateContext\"></ng-container>\n</div>\n","import {\n ConnectionPositionPair,\n FlexibleConnectedPositionStrategy,\n HorizontalConnectionPos,\n Overlay,\n OverlayRef,\n VerticalConnectionPos,\n} from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { Injectable, Injector } from '@angular/core';\nimport { getUuid, isNil, Uuid } from '@bimeister/utilities';\nimport { take } from 'rxjs/operators';\nimport { DROPDOWN_CONTAINER_DATA_TOKEN } from '../declarations/tokens/dropdown-container-data.token';\nimport { DropdownContainerComponent } from '../components/dropdown/components/dropdown-container/dropdown-container.component';\nimport { DropdownTemplateComponent } from '../components/dropdown/components/dropdown-template/dropdown-template.component';\nimport { DropdownComponentBase } from '../declarations/classes/abstract/dropdown-component-base.abstract';\nimport { DropdownRef } from '../declarations/classes/dropdown-ref.class';\nimport { OpenedDropdown } from '../declarations/classes/opened-dropdown.class';\nimport { DropdownConfig } from '../declarations/interfaces/dropdown-config.interface';\nimport { DropdownContainerData } from '../declarations/interfaces/dropdown-container-data.interface';\nimport { DropdownDataType } from '../declarations/types/utility-types/dropdown-data.utility-type';\nimport { OVERLAY_VIEWPORT_MARGIN_PX, Position, Theme } from '@bimeister/pupakit.common';\n\nconst HORIZONTAL_POSITIONS: HorizontalConnectionPos[] = ['center', 'end', 'start'];\nconst VERTICAL_POSITIONS: VerticalConnectionPos[] = ['top', 'bottom'];\n\n@Injectable({ providedIn: 'root' })\nexport class DropdownsService {\n private readonly dropdownStore: Map<string, DropdownRef> = new Map();\n\n constructor(prote