UNPKG

@coreui/angular-pro

Version:

CoreUI Pro Components Library for Angular

864 lines (844 loc) 1.31 MB
import * as i0 from '@angular/core'; import { inject, ElementRef, Directive, input, Renderer2, effect, TemplateRef, booleanAttribute, untracked, NgModule, computed, Injectable, Component, afterNextRender, linkedSignal, output, signal, contentChildren, DestroyRef, forwardRef, DOCUMENT, NgZone, ChangeDetectorRef, contentChild, Input, ChangeDetectionStrategy, IterableDiffers, numberAttribute, ViewChild, ContentChildren, ViewChildren, PLATFORM_ID, RendererFactory2, viewChildren, viewChild, ViewContainerRef, inputBinding, outputBinding, KeyValueDiffers, Pipe, HostBinding, model, afterEveryRender, afterRenderEffect, HostListener, Injector, runInInjectionContext } from '@angular/core'; import { NgTemplateOutlet, I18nPluralPipe, NgStyle, AsyncPipe, isPlatformServer, isPlatformBrowser, formatDate } from '@angular/common'; import { animation, animate, style, AnimationBuilder, useAnimation, trigger, state, transition, group, query, animateChild } from '@angular/animations'; import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; import * as i1 from '@angular/forms'; import { FormsModule, NG_VALUE_ACCESSOR, FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; import { BehaviorSubject, Subject, fromEvent, skip, switchMap, timer, merge, takeWhile, map as map$1, debounceTime as debounceTime$1 } from 'rxjs'; import { tap, filter, distinctUntilChanged, debounceTime, map, delay, combineLatestWith, take, finalize, zipWith, withLatestFrom } from 'rxjs/operators'; import * as i1$2 from '@angular/cdk/a11y'; import { FocusKeyManager, FocusMonitor, A11yModule } from '@angular/cdk/a11y'; import { createPopper } from '@popperjs/core'; import { SelectionModel } from '@angular/cdk/collections'; import { DomPortal, CdkPortalOutlet } from '@angular/cdk/portal'; import { DomSanitizer } from '@angular/platform-browser'; import * as i1$1 from '@angular/router'; import { RouterModule, Router, ActivatedRoute, NavigationEnd, RouterLink } from '@angular/router'; import { BreakpointObserver } from '@angular/cdk/layout'; import { IconDirective } from '@coreui/icons-angular'; var BreakpointInfix; (function (BreakpointInfix) { BreakpointInfix["xs"] = "xs"; BreakpointInfix["sm"] = "sm"; BreakpointInfix["md"] = "md"; BreakpointInfix["lg"] = "lg"; BreakpointInfix["xl"] = "xl"; BreakpointInfix["xxl"] = "xxl"; })(BreakpointInfix || (BreakpointInfix = {})); class ElementRefDirective { elementRef = inject(ElementRef); static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ElementRefDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: ElementRefDirective, isStandalone: true, selector: "[cElementRef]", exportAs: ["cElementRef"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ElementRefDirective, decorators: [{ type: Directive, args: [{ selector: '[cElementRef]', exportAs: 'cElementRef' }] }] }); class HtmlAttributesDirective { cHtmlAttr = input(...(ngDevMode ? [undefined, { debugName: "cHtmlAttr" }] : [])); #renderer = inject(Renderer2); #elementRef = inject(ElementRef); #attrEffect = effect(() => { const attribs = this.cHtmlAttr(); for (const attr in attribs) { if (attr === 'style' && typeof attribs[attr] === 'object') { this.setStyle(attribs[attr]); } else if (attr === 'class') { this.addClass(attribs[attr]); } else { this.setAttrib(attr, attribs[attr]); } } }, ...(ngDevMode ? [{ debugName: "#attrEffect" }] : [])); setStyle(styles) { for (const style in styles) { if (style) { this.#renderer.setStyle(this.#elementRef.nativeElement, style, styles[style]); } } } addClass(classes) { const classArray = Array.isArray(classes) ? classes : classes.split(' '); classArray .filter((element) => element.length > 0) .forEach((element) => { this.#renderer.addClass(this.#elementRef.nativeElement, element); }); } setAttrib(key, value) { value !== null ? this.#renderer.setAttribute(this.#elementRef.nativeElement, key, value) : this.#renderer.removeAttribute(this.#elementRef.nativeElement, key); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: HtmlAttributesDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: HtmlAttributesDirective, isStandalone: true, selector: "[cHtmlAttr]", inputs: { cHtmlAttr: { classPropertyName: "cHtmlAttr", publicName: "cHtmlAttr", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["cHtmlAttr"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: HtmlAttributesDirective, decorators: [{ type: Directive, args: [{ selector: '[cHtmlAttr]', exportAs: 'cHtmlAttr' }] }], propDecorators: { cHtmlAttr: [{ type: i0.Input, args: [{ isSignal: true, alias: "cHtmlAttr", required: false }] }] } }); class TemplateIdDirective { templateRef = inject(TemplateRef); cTemplateId = input.required(...(ngDevMode ? [{ debugName: "cTemplateId" }] : [])); get id() { return this.cTemplateId(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TemplateIdDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: TemplateIdDirective, isStandalone: true, selector: "[cTemplateId]", inputs: { cTemplateId: { classPropertyName: "cTemplateId", publicName: "cTemplateId", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TemplateIdDirective, decorators: [{ type: Directive, args: [{ selector: '[cTemplateId]' }] }], propDecorators: { cTemplateId: [{ type: i0.Input, args: [{ isSignal: true, alias: "cTemplateId", required: true }] }] } }); class ThemeDirective { #hostElement = inject(ElementRef); #renderer = inject(Renderer2); /** * Add dark theme attribute. * @return 'dark' | 'light' | undefined */ colorScheme = input(...(ngDevMode ? [undefined, { debugName: "colorScheme" }] : [])); #colorSchemeChange = effect(() => { const colorScheme = this.colorScheme(); colorScheme ? this.setTheme(colorScheme) : this.unsetTheme(); }, ...(ngDevMode ? [{ debugName: "#colorSchemeChange" }] : [])); dark = input(false, { ...(ngDevMode ? { debugName: "dark" } : {}), transform: booleanAttribute }); #darkChange = effect(() => { const darkTheme = this.dark() || untracked(this.colorScheme) === 'dark'; darkTheme ? this.setTheme('dark') : this.unsetTheme(); }, ...(ngDevMode ? [{ debugName: "#darkChange" }] : [])); setTheme(theme) { if (theme) { this.#renderer.setAttribute(this.#hostElement.nativeElement, 'data-coreui-theme', theme); } } unsetTheme() { this.#renderer.removeAttribute(this.#hostElement.nativeElement, 'data-coreui-theme'); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ThemeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: ThemeDirective, isStandalone: true, selector: "[cTheme]", inputs: { colorScheme: { classPropertyName: "colorScheme", publicName: "colorScheme", isSignal: true, isRequired: false, transformFunction: null }, dark: { classPropertyName: "dark", publicName: "dark", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["cTheme"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ThemeDirective, decorators: [{ type: Directive, args: [{ selector: '[cTheme]', exportAs: 'cTheme' }] }], propDecorators: { colorScheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorScheme", required: false }] }], dark: [{ type: i0.Input, args: [{ isSignal: true, alias: "dark", required: false }] }] } }); class SharedModule { static forRoot() { return { ngModule: SharedModule, }; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SharedModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: SharedModule, imports: [ElementRefDirective, HtmlAttributesDirective, TemplateIdDirective, ThemeDirective], exports: [ElementRefDirective, HtmlAttributesDirective, TemplateIdDirective, ThemeDirective] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SharedModule }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SharedModule, decorators: [{ type: NgModule, args: [{ imports: [ElementRefDirective, HtmlAttributesDirective, TemplateIdDirective, ThemeDirective], exports: [ElementRefDirective, HtmlAttributesDirective, TemplateIdDirective, ThemeDirective], }] }] }); class AccordionButtonDirective { /** * Toggles an accordion button collapsed state. Use in accordionHeaderTemplate. [docs] * @type boolean */ collapsed = input(undefined, ...(ngDevMode ? [{ debugName: "collapsed" }] : [])); /** * Default type for cAccordionButton. [docs] * @type string * @default 'button' */ type = input('button', ...(ngDevMode ? [{ debugName: "type" }] : [])); hostClasses = computed(() => { return { 'accordion-button': true, collapsed: this.collapsed() }; }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : [])); ariaExpanded = computed(() => !this.collapsed(), ...(ngDevMode ? [{ debugName: "ariaExpanded" }] : [])); static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: AccordionButtonDirective, isStandalone: true, selector: "[cAccordionButton]", inputs: { collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "attr.type": "type()", "attr.aria-expanded": "ariaExpanded()" } }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionButtonDirective, decorators: [{ type: Directive, args: [{ selector: '[cAccordionButton]', host: { '[class]': 'hostClasses()', '[attr.type]': 'type()', '[attr.aria-expanded]': 'ariaExpanded()' } }] }], propDecorators: { collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }] } }); class AccordionService { items = []; alwaysOpen = false; addItem(item) { this.items.push(item); } removeItem(item) { const index = this.items.indexOf(item); if (index !== -1) { this.items.splice(index, 1); } } toggleItem(item) { item.itemVisible.update((value) => !value); this.closeOtherItems(item); } closeOtherItems(openItem) { if (!this.alwaysOpen) { this.items.forEach((item) => { if (item !== openItem) { item.itemVisible.set(false); } }); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionService, decorators: [{ type: Injectable }] }); class AccordionComponent { #accordionService = inject(AccordionService); /** * Removes the default background-color, some borders, and some rounded corners to render accordions edge-to-edge with their parent container. * @type boolean */ flush = input(false, { ...(ngDevMode ? { debugName: "flush" } : {}), transform: booleanAttribute }); /** * Make accordion items stay open when another item is opened * @type boolean */ alwaysOpen = input(false, { ...(ngDevMode ? { debugName: "alwaysOpen" } : {}), transform: booleanAttribute }); #alwaysOpenEffect = effect(() => { this.#accordionService.alwaysOpen = this.alwaysOpen(); }, ...(ngDevMode ? [{ debugName: "#alwaysOpenEffect" }] : [])); hostClasses = computed(() => ({ accordion: true, 'accordion-flush': this.flush() }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : [])); static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.0", type: AccordionComponent, isStandalone: true, selector: "c-accordion", inputs: { flush: { classPropertyName: "flush", publicName: "flush", isSignal: true, isRequired: false, transformFunction: null }, alwaysOpen: { classPropertyName: "alwaysOpen", publicName: "alwaysOpen", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, providers: [AccordionService], exportAs: ["cAccordionItem"], ngImport: i0, template: '<ng-content />', isInline: true, styles: [":host{display:block}\n"] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionComponent, decorators: [{ type: Component, args: [{ selector: 'c-accordion', template: '<ng-content />', exportAs: 'cAccordionItem', providers: [AccordionService], host: { '[class]': 'hostClasses()' }, styles: [":host{display:block}\n"] }] }], propDecorators: { flush: [{ type: i0.Input, args: [{ isSignal: true, alias: "flush", required: false }] }], alwaysOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "alwaysOpen", required: false }] }] } }); const expandAnimation = animation([animate('{{ time }} {{ easing }}')]); const collapseAnimation = animation([ style({ height: '*', minHeight: '*' }), animate('{{ time }} {{ easing }}', style({ height: 0, minHeight: 0 })) ]); const expandHorizontalAnimation = animation([animate('{{ time }} {{ easing }}')]); const collapseHorizontalAnimation = animation([animate('{{ time }} {{ easing }}')]); class CollapseDirective { #animationBuilder = inject(AnimationBuilder); #hostElement = inject(ElementRef); #renderer = inject(Renderer2); #player = undefined; constructor() { afterNextRender({ read: () => { this.#initialized.set(true); } }); } /** * @ignore */ animateInput = input(true, { ...(ngDevMode ? { debugName: "animateInput" } : {}), transform: booleanAttribute, alias: 'animate' }); animate = linkedSignal({ ...(ngDevMode ? { debugName: "animate" } : {}), source: this.animateInput, computation: (value) => value }); /** * Set horizontal collapsing to transition the width instead of height. * @type boolean * @default false */ horizontal = input(false, { ...(ngDevMode ? { debugName: "horizontal" } : {}), transform: booleanAttribute }); /** * Toggle the visibility of collapsible element. * @type boolean * @default false */ visibleInput = input(false, { ...(ngDevMode ? { debugName: "visibleInput" } : {}), transform: booleanAttribute, alias: 'visible' }); visibleChange = output(); visible = linkedSignal({ ...(ngDevMode ? { debugName: "visible" } : {}), source: this.visibleInput, computation: (value) => value }); #initialized = signal(false, ...(ngDevMode ? [{ debugName: "#initialized" }] : [])); #visibleEffect = effect(() => { const visible = this.visible(); if (this.#initialized()) { this.createPlayer(visible); } }, ...(ngDevMode ? [{ debugName: "#visibleEffect" }] : [])); /** * Add `navbar` prop for grouping and hiding navbar contents by a parent breakpoint. * @type boolean * @default false */ navbar = input(false, { ...(ngDevMode ? { debugName: "navbar" } : {}), transform: booleanAttribute }); /** * @ignore */ duration = input('350ms', ...(ngDevMode ? [{ debugName: "duration" }] : [])); /** * @ignore */ transition = input('ease', ...(ngDevMode ? [{ debugName: "transition" }] : [])); /** * Event emitted on visibility change. [docs] * @type string */ collapseChange = output(); hostClasses = computed(() => { return { 'navbar-collapse': this.navbar(), 'collapse-horizontal': this.horizontal() }; }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : [])); ngOnDestroy() { this.destroyPlayer(); } toggle(visible = !this.visible()) { this.visible.set(visible); } destroyPlayer() { this.#player?.destroy(); this.#player = undefined; } createPlayer(visible = this.visible()) { if (this.#player?.hasStarted()) { this.destroyPlayer(); } const host = this.#hostElement.nativeElement; if (visible) { this.#renderer.removeStyle(host, 'display'); } const duration = this.animate() ? this.duration() : '0ms'; const expand = this.horizontal() ? expandHorizontalAnimation : expandAnimation; const collapse = this.horizontal() ? collapseHorizontalAnimation : collapseAnimation; const dimension = this.horizontal() ? 'width' : 'height'; const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); const scrollSize = `scroll${capitalizedDimension}`; const animationFactory = this.#animationBuilder?.build(useAnimation(visible ? expand : collapse, { params: { time: duration, easing: this.transition() } })); this.#player = animationFactory.create(host); !visible && host.offsetHeight && host.style[dimension] && host.scrollHeight; this.#renderer.setStyle(host, dimension, visible ? 0 : `${host.getBoundingClientRect()[dimension]}px`); this.#player.onStart(() => { this.setMaxSize(); this.#renderer.removeClass(host, 'collapse'); this.#renderer.addClass(host, 'collapsing'); this.#renderer.removeClass(host, 'show'); this.#renderer.setStyle(host, dimension, visible ? `${host[scrollSize]}px` : ''); if (this.#player) { this.collapseChange?.emit(visible ? 'opening' : 'collapsing'); } }); this.#player.onDone(() => { this.#renderer.removeClass(host, 'collapsing'); this.#renderer.addClass(host, 'collapse'); if (visible) { this.#renderer.addClass(host, 'show'); this.#renderer.setStyle(host, dimension, ''); } else { this.#renderer.removeClass(host, 'show'); } if (this.#player) { this.collapseChange?.emit(visible ? 'open' : 'collapsed'); this.visibleChange?.emit(visible); } this.destroyPlayer(); }); this.#player?.play(); } setMaxSize() { const host = this.#hostElement.nativeElement; if (this.horizontal()) { host.scrollWidth > 0 && this.#renderer.setStyle(host, 'maxWidth', `${host.scrollWidth}px`); // } else { // host.scrollHeight > 0 && this.#renderer.setStyle(host, 'maxHeight', `${host.scrollHeight}px`); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CollapseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: CollapseDirective, isStandalone: true, selector: "[cCollapse]", inputs: { animateInput: { classPropertyName: "animateInput", publicName: "animate", isSignal: true, isRequired: false, transformFunction: null }, horizontal: { classPropertyName: "horizontal", publicName: "horizontal", isSignal: true, isRequired: false, transformFunction: null }, visibleInput: { classPropertyName: "visibleInput", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, navbar: { classPropertyName: "navbar", publicName: "navbar", isSignal: true, isRequired: false, transformFunction: null }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, transition: { classPropertyName: "transition", publicName: "transition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visibleChange: "visibleChange", collapseChange: "collapseChange" }, host: { properties: { "class": "hostClasses()", "style": "{ display: \"none\" }" } }, exportAs: ["cCollapse"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CollapseDirective, decorators: [{ type: Directive, args: [{ selector: '[cCollapse]', exportAs: 'cCollapse', host: { '[class]': 'hostClasses()', '[style]': '{ display: "none" }' } }] }], ctorParameters: () => [], propDecorators: { animateInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "animate", required: false }] }], horizontal: [{ type: i0.Input, args: [{ isSignal: true, alias: "horizontal", required: false }] }], visibleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], visibleChange: [{ type: i0.Output, args: ["visibleChange"] }], navbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "navbar", required: false }] }], duration: [{ type: i0.Input, args: [{ isSignal: true, alias: "duration", required: false }] }], transition: [{ type: i0.Input, args: [{ isSignal: true, alias: "transition", required: false }] }], collapseChange: [{ type: i0.Output, args: ["collapseChange"] }] } }); class CollapseModule { static forRoot() { return { ngModule: CollapseModule, providers: [] }; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CollapseModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: CollapseModule, imports: [CollapseDirective], exports: [CollapseDirective] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CollapseModule }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CollapseModule, decorators: [{ type: NgModule, args: [{ exports: [CollapseDirective], imports: [CollapseDirective] }] }] }); let nextId$3 = 0; class AccordionItemComponent { #accordionService = inject(AccordionService); /** * Toggle an accordion item programmatically * @return boolean * @default false */ visibleInput = input(false, { ...(ngDevMode ? { debugName: "visibleInput" } : {}), transform: booleanAttribute, alias: 'visible' }); itemVisible = signal(false, ...(ngDevMode ? [{ debugName: "itemVisible" }] : [])); #visibleInputChange = effect(() => { this.visible = this.visibleInput(); }, ...(ngDevMode ? [{ debugName: "#visibleInputChange" }] : [])); set visible(value) { this.itemVisible.set(value); } get visible() { return this.itemVisible(); } contentId = `accordion-item-${nextId$3++}`; get itemContext() { return { $implicit: this.itemVisible() }; } contentTemplates = contentChildren(TemplateIdDirective, { ...(ngDevMode ? { debugName: "contentTemplates" } : {}), descendants: true }); templates = computed(() => { return this.contentTemplates().reduce((acc, child) => { acc[child.id] = child.templateRef; return acc; }, {}); }, ...(ngDevMode ? [{ debugName: "templates" }] : [])); ngOnInit() { this.#accordionService.addItem(this); } ngOnDestroy() { this.#accordionService.removeItem(this); } toggleItem() { this.#accordionService.toggleItem(this); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.0", type: AccordionItemComponent, isStandalone: true, selector: "c-accordion-item", inputs: { visibleInput: { classPropertyName: "visibleInput", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "accordion-item" }, queries: [{ propertyName: "contentTemplates", predicate: TemplateIdDirective, descendants: true, isSignal: true }], exportAs: ["cAccordionItem"], ngImport: i0, template: "@let tmpl = templates();\n<ng-container>\n <div class=\"accordion-header\">\n <ng-container *ngTemplateOutlet=\"tmpl['accordionHeaderTemplate'] || defaultAccordionHeaderTemplate; context: itemContext\" />\n </div>\n <div class=\"accordion-collapse\" cCollapse [visible]=\"itemVisible()\" [attr.aria-expanded]=\"itemVisible()\" [id]=\"contentId\">\n <ng-container *ngTemplateOutlet=\"tmpl['accordionBodyTemplate'] || defaultAccordionBodyTemplate; context: itemContext\" />\n </div>\n</ng-container>\n\n<ng-template #defaultAccordionHeaderTemplate>\n <button cAccordionButton [collapsed]=\"!itemVisible()\" [attr.aria-controls]=\"contentId\" (click)=\"toggleItem()\">\n <ng-container *ngTemplateOutlet=\"tmpl['accordionHeader'] || defaultAccordionHeaderContentTemplate; context: itemContext\" />\n </button>\n</ng-template>\n\n<ng-template #defaultAccordionHeaderContentTemplate>\n <ng-content />\n</ng-template>\n\n<ng-template #defaultAccordionBodyTemplate>\n <div class=\"accordion-body\">\n <ng-container *ngTemplateOutlet=\"tmpl['accordionBody'] || defaultAccordionBodyContentTemplate; context: itemContext\" />\n </div>\n</ng-template>\n\n<ng-template #defaultAccordionBodyContentTemplate>\n <ng-content />\n</ng-template>\n", styles: [":host{display:block;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: AccordionButtonDirective, selector: "[cAccordionButton]", inputs: ["collapsed", "type"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CollapseDirective, selector: "[cCollapse]", inputs: ["animate", "horizontal", "visible", "navbar", "duration", "transition"], outputs: ["visibleChange", "collapseChange"], exportAs: ["cCollapse"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionItemComponent, decorators: [{ type: Component, args: [{ selector: 'c-accordion-item', exportAs: 'cAccordionItem', imports: [AccordionButtonDirective, NgTemplateOutlet, CollapseDirective], host: { class: 'accordion-item' }, template: "@let tmpl = templates();\n<ng-container>\n <div class=\"accordion-header\">\n <ng-container *ngTemplateOutlet=\"tmpl['accordionHeaderTemplate'] || defaultAccordionHeaderTemplate; context: itemContext\" />\n </div>\n <div class=\"accordion-collapse\" cCollapse [visible]=\"itemVisible()\" [attr.aria-expanded]=\"itemVisible()\" [id]=\"contentId\">\n <ng-container *ngTemplateOutlet=\"tmpl['accordionBodyTemplate'] || defaultAccordionBodyTemplate; context: itemContext\" />\n </div>\n</ng-container>\n\n<ng-template #defaultAccordionHeaderTemplate>\n <button cAccordionButton [collapsed]=\"!itemVisible()\" [attr.aria-controls]=\"contentId\" (click)=\"toggleItem()\">\n <ng-container *ngTemplateOutlet=\"tmpl['accordionHeader'] || defaultAccordionHeaderContentTemplate; context: itemContext\" />\n </button>\n</ng-template>\n\n<ng-template #defaultAccordionHeaderContentTemplate>\n <ng-content />\n</ng-template>\n\n<ng-template #defaultAccordionBodyTemplate>\n <div class=\"accordion-body\">\n <ng-container *ngTemplateOutlet=\"tmpl['accordionBody'] || defaultAccordionBodyContentTemplate; context: itemContext\" />\n </div>\n</ng-template>\n\n<ng-template #defaultAccordionBodyContentTemplate>\n <ng-content />\n</ng-template>\n", styles: [":host{display:block;overflow:hidden}\n"] }] }], propDecorators: { visibleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], contentTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TemplateIdDirective), { ...{ descendants: true }, isSignal: true }] }] } }); class AccordionModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.0", ngImport: i0, type: AccordionModule, imports: [AccordionButtonDirective, AccordionComponent, AccordionItemComponent], exports: [AccordionComponent, AccordionButtonDirective, AccordionItemComponent] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionModule, providers: [ AccordionService ] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AccordionModule, decorators: [{ type: NgModule, args: [{ imports: [ AccordionButtonDirective, AccordionComponent, AccordionItemComponent ], exports: [ AccordionComponent, AccordionButtonDirective, AccordionItemComponent ], providers: [ AccordionService ] }] }] }); const normalizeOptionsArray = (options) => { return options.map((option) => { if (typeof option === 'string') { option = { label: option }; } if (option.options) { option.options = [...normalizeOptionsArray(option.options)]; } return { ...option }; }); }; const filterOptions = (options, search) => { const result = []; options.forEach((item) => { if ('options' in item && Array.isArray(item.options)) { const filteredOptions = filterOptions(item.options, search); if (filteredOptions.length > 0) { result.push({ ...item, options: filteredOptions }); } } else if (getOptionLabel(item).toLowerCase().includes(search.toLowerCase())) { result.push(item); } }); return result; }; const flattenOptionsArray = (options) => { const optionsList = []; for (const option of options) { if ('options' in option && Array.isArray(option.options)) { optionsList.push(...option.options); } else { optionsList.push(option); } } return optionsList; }; const isExternalSearch = (search) => { return ((typeof search === 'string' && search === 'external') || (typeof search === 'object' && search.external === true)); }; const isGlobalSearch = (search) => { return (typeof search === 'string' && search === 'global') || (typeof search === 'object' && search.global === true); }; const getOptionLabel = (option) => (typeof option === 'string' ? option : option.label); const highlightSubstring = (string, query) => { if (query) { const regex = new RegExp(query, 'gi'); return string.replace(regex, (string) => `<strong>${string}</strong>`); } return string; }; const isOptionDisabled = (option) => typeof option === 'string' ? false : option.disabled; const isOptionSelected = (option, selected) => { if (!selected) { return false; } if (typeof option === 'string' && typeof selected === 'string') { return selected === option; } if (typeof option !== 'string' && typeof selected !== 'string') { return selected.label === option.label; } return false; }; const getFirstOptionByLabel = (value, options) => { for (const option of options) { if ('options' in option && Array.isArray(option.options)) { const found = getFirstOptionByLabel(value, option.options); if (found) { return found; } } if (getOptionLabel(option).toLowerCase() === value.toLowerCase()) { return option; } } return null; }; const getFirstOptionByValue = (value, options) => { for (const option of options) { if ('options' in option && Array.isArray(option.options)) { const found = getFirstOptionByValue(value, option.options); if (found) { return found; } } if ('value' in option && option.value === value) { return option; } } return null; }; const findHintOption = (searchValue, options) => { return searchValue.length > 0 ? options .flatMap((option) => (Array.isArray(option.options) ? option.options : [option])) .find((option) => getOptionLabel(option).toLowerCase().startsWith(searchValue.toLowerCase())) : undefined; }; class DropdownDividerDirective { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownDividerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: DropdownDividerDirective, isStandalone: true, selector: "[cDropdownDivider]", host: { classAttribute: "dropdown-divider" }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownDividerDirective, decorators: [{ type: Directive, args: [{ selector: '[cDropdownDivider]', host: { class: 'dropdown-divider' } }] }] }); class DropdownHeaderDirective { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: DropdownHeaderDirective, isStandalone: true, selector: "[cDropdownHeader]", host: { classAttribute: "dropdown-header" }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownHeaderDirective, decorators: [{ type: Directive, args: [{ selector: '[cDropdownHeader]', host: { class: 'dropdown-header' } }] }] }); class DropdownService { #dropdownState = new BehaviorSubject({}); dropdownState$ = this.#dropdownState.asObservable(); toggle(state) { this.#dropdownState.next(state); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); class DropdownMenuDirective { #destroyRef = inject(DestroyRef); elementRef = inject(ElementRef); #dropdownService = inject(DropdownService); #focusKeyManager; /** * Set alignment of dropdown menu. * @return 'start' | 'end' */ alignment = input(...(ngDevMode ? [undefined, { debugName: "alignment" }] : [])); /** * Toggle the visibility of dropdown menu component. * @return boolean */ visibleInput = input(false, { ...(ngDevMode ? { debugName: "visibleInput" } : {}), transform: booleanAttribute, alias: 'visible' }); visible = linkedSignal({ ...(ngDevMode ? { debugName: "visible" } : {}), source: this.visibleInput, computation: (value) => value }); hostClasses = computed(() => { const alignment = this.alignment(); const visible = this.visible(); return { 'dropdown-menu': true, [`dropdown-menu-${alignment}`]: !!alignment, show: visible }; }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : [])); hostStyles = computed(() => { // workaround for popper position calculate (see also: dropdown.component) const visible = this.visible(); return { visibility: visible ? null : '', display: visible ? null : '' }; }, ...(ngDevMode ? [{ debugName: "hostStyles" }] : [])); onKeyDown($event) { if (!this.visible()) { return; } if (['Space', 'ArrowDown'].includes($event.code)) { $event.preventDefault(); } this.#focusKeyManager.onKeydown($event); } onKeyUp($event) { if (!this.visible()) { return; } if (['Tab'].includes($event.key)) { if (this.#focusKeyManager.activeItem) { $event.shiftKey ? this.#focusKeyManager.setPreviousItemActive() : this.#focusKeyManager.setNextItemActive(); } else { this.#focusKeyManager.setFirstItemActive(); } } } dropdownItemsContent = contentChildren(forwardRef(() => DropdownItemDirective), { ...(ngDevMode ? { debugName: "dropdownItemsContent" } : {}), descendants: true }); items$ = toObservable(this.dropdownItemsContent); ngAfterContentInit() { this.focusKeyManagerInit(); this.items$ .pipe(tap((change) => { this.focusKeyManagerInit(); }), takeUntilDestroyed(this.#destroyRef)) .subscribe(); } ngOnInit() { this.#dropdownService.dropdownState$ .pipe(tap((state) => { if ('visible' in state) { this.visible.update((visible) => (state.visible === 'toggle' ? !visible : state.visible)); if (!this.visible()) { this.#focusKeyManager?.setActiveItem(-1); } } }), takeUntilDestroyed(this.#destroyRef)) .subscribe(); } focusKeyManagerInit() { this.#focusKeyManager = new FocusKeyManager(this.dropdownItemsContent()) .withHomeAndEnd() .withPageUpDown() .withWrap() .skipPredicate((dropdownItem) => dropdownItem.disabled === true); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownMenuDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.1.0", type: DropdownMenuDirective, isStandalone: true, selector: "[cDropdownMenu]", inputs: { alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, visibleInput: { classPropertyName: "visibleInput", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown": "onKeyDown($event)", "keyup": "onKeyUp($event)" }, properties: { "class": "hostClasses()", "style": "hostStyles()" }, classAttribute: "dropdown-menu" }, queries: [{ propertyName: "dropdownItemsContent", predicate: i0.forwardRef(() => DropdownItemDirective), descendants: true, isSignal: true }], exportAs: ["cDropdownMenu"], hostDirectives: [{ directive: ThemeDirective, inputs: ["dark", "dark"] }], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownMenuDirective, decorators: [{ type: Directive, args: [{ selector: '[cDropdownMenu]', exportAs: 'cDropdownMenu', hostDirectives: [{ directive: ThemeDirective, inputs: ['dark'] }], host: { class: 'dropdown-menu', '[class]': 'hostClasses()', '[style]': 'hostStyles()', '(keydown)': 'onKeyDown($event)', '(keyup)': 'onKeyUp($event)' } }] }], propDecorators: { alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], visibleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], dropdownItemsContent: [{ type: i0.ContentChildren, args: [forwardRef(() => DropdownItemDirective), { ...{ descendants: true }, isSignal: true }] }] } }); // lightweight injection token class DropdownToken { } class DropdownToggleDirective { // injections #destroyRef = inject(DestroyRef); elementRef = inject(ElementRef); #dropdownService = inject(DropdownService); dropdown = inject(DropdownToken, { optional: true }); /** * Reference to dropdown component. * @return DropdownComponent | undefined * @default undefined */ dropdownComponent = input(...(ngDevMode ? [undefined, { debugName: "dropdownComponent" }] : [])); /** * Disables the toggler. * @return boolean * @default false */ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : {}), transform: booleanAttribute }); /** * Enables pseudo element caret on toggler. * @return boolean */ caret = input(true, ...(ngDevMode ? [{ debugName: "caret" }] : [])); /** * Create split button dropdowns with virtually the same markup as single button dropdowns, * but with the addition of `.dropdown-toggle-split` class for proper spacing around the dropdown caret. * @return boolean * @default false */ split = input(false, { ...(ngDevMode ? { debugName: "split" } : {}), transform: booleanAttribute }); hostClasses = computed(() => { return { 'dropdown-toggle': this.caret(), 'dropdown-toggle-split': this.split(), disabled: this.disabled() }; }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : [])); #ariaExpanded = signal(false, ...(ngDevMode ? [{ debugName: "#ariaExpanded" }] : [])); get ariaExpanded() { return this.#ariaExpanded(); } onClick($event) { $event.preventDefault(); !this.disabled() && this.#dropdownService.toggle({ visible: 'toggle', dropdown: this.dropdown }); } ngAfterViewInit() { const dropdownComponent = this.dropdownComponent(); if (dropdownComponent) { this.dropdown = dropdownComponent; this.#dropdownService = dropdownComponent?.dropdownService; } if (this.dropdown) { const dropdown = this.dropdown; dropdown?.visibleChange?.subscribe((visible) => { this.#ariaExpanded.set(visible); }); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownToggleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: DropdownToggleDirective, isStandalone: true, selector: "[cDropdownToggle]", inputs: { dropdownComponent: { classPropertyName: "dropdownComponent", publicName: "dropdownComponent", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, caret: { classPropertyName: "caret", publicName: "caret", isSignal: true, isRequired: false, transformFunction: null }, split: { classPropertyName: "split", publicName: "split", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "onClick($event)" }, properties: { "class": "hostClasses()", "attr.aria-expanded": "ariaExpanded" } }, providers: [{ provide: DropdownToken, useExisting: forwardRef(() => DropdownComponent) }], exportAs: ["cDropdownToggle"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: DropdownToggleDirective, decorators: [{ type: Directive, args: [{ selector: '[cDropdownToggle]', providers: [{ provide: DropdownToken, useExisting: forwardRef(() => DropdownComponent) }], exportAs: 'cDropdownToggle', host: { '[class]': 'hostClasses()', '[attr.aria-expanded]': 'ariaExpanded', '(click)': 'onClick($event)' } }] }], propDecorators: { dropdownComponent: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownComponent", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], caret: [{ type: i0.Input, args: [{ isSignal: true, alias: "caret", required: false }] }], split: [{ type: i0.Input, args: [{ isSignal: true, alias: "split", required: false }] }] } }); class DropdownComponent { #destroyRef = inject(DestroyRef); #document = inject(DOCUMENT); #elementRef = inject(ElementRef); #renderer = inject(Renderer2); #ngZone = inject(NgZone); #changeDetectorRef = inject(ChangeDetectorRef); dropdownService = inject(DropdownService); constructor() { this.dropdownStateSubscribe(); } /** * Set alignment of dropdown menu. * @return {'start' | 'end' | { xs: 'start' | 'end' } | { sm: 'start' | 'end' } | { md: 'start' | 'end' } | { lg: 'start' | 'end' } | { xl: 'start' | 'end'} | { xxl: 'start' | 'end'}} */ alignment = input(...(ngDevMode ? [undefined, { debugName: "alignment" }] : [])); /** * Automatically close dropdown when clicking outside the dropdown menu. */ autoClose = input(true, ...(ngDevMode ? [{ debugName: "autoClose" }] : [])); /** * Sets a specified direction and location of the dropdown menu. * @return 'dropup' | 'dropend' | 'dropstart' */ direction = input(...(ngDevMode ? [undefined, { debugName: "direction" }] : [])); /** * Describes the placement of your component after Popper.js has applied all the modifiers * that may have flipped or altered the originally provided placement property. * @return Placement */ placement = input('bottom-start', ...(ngDevMode ? [{ debugName: "placement" }] : [])); /** * If you want to disable dynamic positioning set this property to `false`. * @return boolean * @default true */ popper = input(true, { ...(ngDevMode ? { debugName: "popper" } : {}), transform: booleanAttribute }); /** * Optional popper Options object, placement prop takes precedence over * @return Partial<Options> */ popperOptionsInput = input({}, { ...(ngDevMode ? { debugName: "popperOptionsInput" } : {}), alias: 'popperOptions' }); #popperOptionsEffect = effect(() => { this.popperOptions = { ...untracked(this.#popperOptions), ...this.popperOptionsInput() }; }, ...(ngDevMode ? [{ debugName: "#popperOptionsEffect" }] : [])); set popperOptions(value) { this.#popperOptions.update((popperOptions) => ({ ...popperOptions, ...value })); } get popperOptions() { let placement = this.p