UNPKG

@ng-bootstrap/ng-bootstrap

Version:
1,194 lines (1,177 loc) 551 kB
import * as i0 from '@angular/core'; import { Injectable, inject, ElementRef, NgZone, EventEmitter, Directive, Input, Output, TemplateRef, ViewContainerRef, Component, ViewChild, ContentChild, ChangeDetectorRef, DestroyRef, ContentChildren, NgModule, ChangeDetectionStrategy, ViewEncapsulation, PLATFORM_ID, Injector, afterNextRender, LOCALE_ID, forwardRef, afterRender, ApplicationRef, EnvironmentInjector, createComponent, Attribute, ViewChildren, InjectionToken } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { Observable, EMPTY, of, Subject, fromEvent, timer, race, BehaviorSubject, combineLatest, NEVER, zip, merge } from 'rxjs'; import { endWith, takeUntil, filter, map, startWith, distinctUntilChanged, switchMap, take, tap, withLatestFrom, delay, mergeMap, skip, finalize } from 'rxjs/operators'; import { isPlatformBrowser, NgTemplateOutlet, formatDate, DOCUMENT, PercentPipe } from '@angular/common'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; import { flip, preventOverflow, arrow, createPopperLite, offset } from '@popperjs/core'; const environment = { animation: true, transitionTimerDelayMs: 5, }; /** * Global ng-bootstrap config * * @since 8.0.0 */ class NgbConfig { constructor() { this.animation = environment.animation; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbConfig, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbConfig, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /** * A configuration service for the [`NgbAccordionDirective`](#/components/accordion/api#NgbAccordionDirective). * * You can inject this service, typically in your root component, and customize its properties * to provide default values for all accordions used in the application. */ class NgbAccordionConfig { constructor() { this._ngbConfig = inject(NgbConfig); this.closeOthers = false; this.destroyOnHide = true; } get animation() { return this._animation ?? this._ngbConfig.animation; } set animation(animation) { this._animation = animation; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionConfig, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionConfig, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); function getTransitionDurationMs(element) { const { transitionDelay, transitionDuration } = window.getComputedStyle(element); const transitionDelaySec = parseFloat(transitionDelay); const transitionDurationSec = parseFloat(transitionDuration); return (transitionDelaySec + transitionDurationSec) * 1000; } function toInteger(value) { return parseInt(`${value}`, 10); } function toString(value) { return value !== undefined && value !== null ? `${value}` : ''; } function getValueInRange(value, max, min = 0) { return Math.max(Math.min(value, max), min); } function isString(value) { return typeof value === 'string'; } function isNumber(value) { return !isNaN(toInteger(value)); } function isInteger(value) { return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; } function isDefined(value) { return value !== undefined && value !== null; } function isPromise(v) { return v && v.then; } function padNumber(value) { if (isNumber(value)) { return `0${value}`.slice(-2); } else { return ''; } } function regExpEscape(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); } function closest(element, selector) { if (!selector) { return null; } /* * In certain browsers (e.g. Edge 44.18362.449.0) HTMLDocument does * not support `Element.prototype.closest`. To emulate the correct behaviour * we return null when the method is missing. * * Note that in evergreen browsers `closest(document.documentElement, 'html')` * will return the document element whilst in Edge null will be returned. This * compromise was deemed good enough. */ if (typeof element.closest === 'undefined') { return null; } return element.closest(selector); } /** * Force a browser reflow * @param element element where to apply the reflow */ function reflow(element) { return (element || document.body).getBoundingClientRect(); } /** * Creates an observable where all callbacks are executed inside a given zone * * @param zone */ function runInZone(zone) { return (source) => { return new Observable((observer) => { const next = (value) => zone.run(() => observer.next(value)); const error = (e) => zone.run(() => observer.error(e)); const complete = () => zone.run(() => observer.complete()); return source.subscribe({ next, error, complete }); }); }; } function removeAccents(str) { return str.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); } /** * Returns the active element in the given root. * If the active element is inside a shadow root, it is searched recursively. */ function getActiveElement(root = document) { const activeEl = root?.activeElement; if (!activeEl) { return null; } return activeEl.shadowRoot ? getActiveElement(activeEl.shadowRoot) : activeEl; } const noopFn = () => { }; const { transitionTimerDelayMs } = environment; const runningTransitions = new Map(); const ngbRunTransition = (zone, element, startFn, options) => { // Getting initial context from options let context = options.context || {}; // Checking if there are already running transitions on the given element. const running = runningTransitions.get(element); if (running) { switch (options.runningTransition) { // If there is one running and we want for it to 'continue' to run, we have to cancel the new one. // We're not emitting any values, but simply completing the observable (EMPTY). case 'continue': return EMPTY; // If there is one running and we want for it to 'stop', we have to complete the running one. // We're simply completing the running one and not emitting any values and merging newly provided context // with the one coming from currently running transition. case 'stop': zone.run(() => running.transition$.complete()); context = Object.assign(running.context, context); runningTransitions.delete(element); } } // Running the start function const endFn = startFn(element, options.animation, context) || noopFn; // If 'prefer-reduced-motion' is enabled, the 'transition' will be set to 'none'. // If animations are disabled, we have to emit a value and complete the observable // In this case we have to call the end function, but can finish immediately by emitting a value, // completing the observable and executing end functions synchronously. if (!options.animation || window.getComputedStyle(element).transitionProperty === 'none') { zone.run(() => endFn()); return of(undefined).pipe(runInZone(zone)); } // Starting a new transition const transition$ = new Subject(); const finishTransition$ = new Subject(); const stop$ = transition$.pipe(endWith(true)); runningTransitions.set(element, { transition$, complete: () => { finishTransition$.next(); finishTransition$.complete(); }, context, }); const transitionDurationMs = getTransitionDurationMs(element); // 1. We have to both listen for the 'transitionend' event and have a 'just-in-case' timer, // because 'transitionend' event might not be fired in some browsers, if the transitioning // element becomes invisible (ex. when scrolling, making browser tab inactive, etc.). The timer // guarantees, that we'll release the DOM element and complete 'ngbRunTransition'. // 2. We need to filter transition end events, because they might bubble from shorter transitions // on inner DOM elements. We're only interested in the transition on the 'element' itself. zone.runOutsideAngular(() => { const transitionEnd$ = fromEvent(element, 'transitionend').pipe(takeUntil(stop$), filter(({ target }) => target === element)); const timer$ = timer(transitionDurationMs + transitionTimerDelayMs).pipe(takeUntil(stop$)); race(timer$, transitionEnd$, finishTransition$) .pipe(takeUntil(stop$)) .subscribe(() => { runningTransitions.delete(element); zone.run(() => { endFn(); transition$.next(); transition$.complete(); }); }); }); return transition$.asObservable(); }; const ngbCompleteTransition = (element) => { runningTransitions.get(element)?.complete(); }; function measureCollapsingElementDimensionPx(element, dimension) { // SSR fix for without injecting the PlatformId if (typeof navigator === 'undefined') { return '0px'; } const { classList } = element; const hasShownClass = classList.contains('show'); if (!hasShownClass) { classList.add('show'); } element.style[dimension] = ''; const dimensionSize = element.getBoundingClientRect()[dimension] + 'px'; if (!hasShownClass) { classList.remove('show'); } return dimensionSize; } const ngbCollapsingTransition = (element, animation, context) => { let { direction, maxSize, dimension } = context; const { classList } = element; function setInitialClasses() { classList.add('collapse'); if (direction === 'show') { classList.add('show'); } else { classList.remove('show'); } } // without animations we just need to set initial classes if (!animation) { setInitialClasses(); return; } // No maxHeight -> running the transition for the first time if (!maxSize) { maxSize = measureCollapsingElementDimensionPx(element, dimension); context.maxSize = maxSize; // Fix the height before starting the animation element.style[dimension] = direction !== 'show' ? maxSize : '0px'; classList.remove('collapse', 'collapsing', 'show'); reflow(element); // Start the animation classList.add('collapsing'); } // Start or revert the animation element.style[dimension] = direction === 'show' ? maxSize : '0px'; return () => { setInitialClasses(); classList.remove('collapsing'); element.style[dimension] = ''; }; }; /** * A configuration service for the [NgbCollapse](#/components/collapse/api#NgbCollapse) component. * * You can inject this service, typically in your root component, and customize its properties * to provide default values for all collapses used in the application. */ class NgbCollapseConfig { constructor() { this._ngbConfig = inject(NgbConfig); this.horizontal = false; } get animation() { return this._animation ?? this._ngbConfig.animation; } set animation(animation) { this._animation = animation; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbCollapseConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbCollapseConfig, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbCollapseConfig, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /** * A directive to provide a simple way of hiding and showing elements on the * page. */ class NgbCollapse { constructor() { this._config = inject(NgbCollapseConfig); this._element = inject(ElementRef); this._zone = inject(NgZone); /** * If `true`, collapse will be animated. * * Animation is triggered only when clicked on triggering element * or via the `.toggle()` function * * @since 8.0.0 */ this.animation = this._config.animation; /** * Flag used to track if the collapse setter is invoked during initialization * or not. This distinction is made in order to avoid running the transition during initialization. */ this._afterInit = false; this._isCollapsed = false; this.ngbCollapseChange = new EventEmitter(); /** * If `true`, will collapse horizontally. * * @since 13.1.0 */ this.horizontal = this._config.horizontal; /** * An event emitted when the collapse element is shown, after the transition. * It has no payload. * * @since 8.0.0 */ this.shown = new EventEmitter(); /** * An event emitted when the collapse element is hidden, after the transition. * It has no payload. * * @since 8.0.0 */ this.hidden = new EventEmitter(); } /** * If `true`, will collapse the element or show it otherwise. */ set collapsed(isCollapsed) { if (this._isCollapsed !== isCollapsed) { this._isCollapsed = isCollapsed; if (this._afterInit) { this._runTransitionWithEvents(isCollapsed, this.animation); } } } ngOnInit() { this._runTransition(this._isCollapsed, false); this._afterInit = true; } /** * Triggers collapsing programmatically. * * If there is a collapsing transition running already, it will be reversed. * If the animations are turned off this happens synchronously. * * @since 8.0.0 */ toggle(open = this._isCollapsed) { this.collapsed = !open; this.ngbCollapseChange.next(this._isCollapsed); } _runTransition(collapsed, animation) { return ngbRunTransition(this._zone, this._element.nativeElement, ngbCollapsingTransition, { animation, runningTransition: 'stop', context: { direction: collapsed ? 'hide' : 'show', dimension: this.horizontal ? 'width' : 'height' }, }); } _runTransitionWithEvents(collapsed, animation) { this._runTransition(collapsed, animation).subscribe(() => { if (collapsed) { this.hidden.emit(); } else { this.shown.emit(); } }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbCollapse, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: NgbCollapse, isStandalone: true, selector: "[ngbCollapse]", inputs: { animation: "animation", collapsed: ["ngbCollapse", "collapsed"], horizontal: "horizontal" }, outputs: { ngbCollapseChange: "ngbCollapseChange", shown: "shown", hidden: "hidden" }, host: { properties: { "class.collapse-horizontal": "horizontal" } }, exportAs: ["ngbCollapse"], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbCollapse, decorators: [{ type: Directive, args: [{ selector: '[ngbCollapse]', exportAs: 'ngbCollapse', standalone: true, host: { '[class.collapse-horizontal]': 'horizontal', }, }] }], propDecorators: { animation: [{ type: Input }], collapsed: [{ type: Input, args: ['ngbCollapse'] }], ngbCollapseChange: [{ type: Output }], horizontal: [{ type: Input }], shown: [{ type: Output }], hidden: [{ type: Output }] } }); let nextId$3 = 0; /** * A directive that wraps the content of an accordion item's collapsible body. * * The actual content is provided in a child `ng-template` element. * Depending on the state of the accordion, the template will be either inserted or removed from the DOM. * * @since 14.1.0 */ class NgbAccordionBody { constructor() { this._item = inject(NgbAccordionItem); this._viewRef = null; /** * the `ElementRef` of the component * * @since 18.0.0 */ this.elementRef = inject(ElementRef); } ngAfterContentChecked() { if (this._bodyTpl) { if (this._item._shouldBeInDOM) { this._createViewIfNotExists(); } else { this._destroyViewIfExists(); } } } ngOnDestroy() { this._destroyViewIfExists(); } _destroyViewIfExists() { this._viewRef?.destroy(); this._viewRef = null; } _createViewIfNotExists() { if (!this._viewRef) { this._viewRef = this._vcr.createEmbeddedView(this._bodyTpl); this._viewRef.detectChanges(); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionBody, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: NgbAccordionBody, isStandalone: true, selector: "[ngbAccordionBody]", host: { classAttribute: "accordion-body" }, queries: [{ propertyName: "_bodyTpl", first: true, predicate: TemplateRef, descendants: true, static: true }], viewQueries: [{ propertyName: "_vcr", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: ` <ng-container #container /> <ng-content /> `, isInline: true }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionBody, decorators: [{ type: Component, args: [{ selector: '[ngbAccordionBody]', standalone: true, template: ` <ng-container #container /> <ng-content /> `, host: { class: 'accordion-body', }, }] }], propDecorators: { _vcr: [{ type: ViewChild, args: ['container', { read: ViewContainerRef, static: true }] }], _bodyTpl: [{ type: ContentChild, args: [TemplateRef, { static: true }] }] } }); /** * A directive that wraps the collapsible item's content of the accordion. * * Internally it reuses the [`NgbCollapse` directive](#/components/collapse) * * @since 14.1.0 */ class NgbAccordionCollapse { constructor() { this.item = inject(NgbAccordionItem); this.ngbCollapse = inject(NgbCollapse); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionCollapse, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: NgbAccordionCollapse, isStandalone: true, selector: "[ngbAccordionCollapse]", host: { attributes: { "role": "region" }, properties: { "id": "item.collapseId", "attr.aria-labelledby": "item.toggleId" }, classAttribute: "accordion-collapse" }, exportAs: ["ngbAccordionCollapse"], hostDirectives: [{ directive: NgbCollapse }], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionCollapse, decorators: [{ type: Directive, args: [{ exportAs: 'ngbAccordionCollapse', standalone: true, selector: '[ngbAccordionCollapse]', host: { role: 'region', class: 'accordion-collapse', '[id]': 'item.collapseId', '[attr.aria-labelledby]': 'item.toggleId', }, hostDirectives: [NgbCollapse], }] }] }); /** * A directive to put on a toggling element inside the accordion item's header. * It will register click handlers that toggle the associated panel and will handle accessibility attributes. * * This directive is used internally by the [`NgbAccordionButton` directive](#/components/accordion/api#NgbAccordionButton). * * @since 14.1.0 */ class NgbAccordionToggle { constructor() { this.item = inject(NgbAccordionItem); this.accordion = inject(NgbAccordionDirective); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionToggle, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: NgbAccordionToggle, isStandalone: true, selector: "[ngbAccordionToggle]", host: { listeners: { "click": "!item.disabled && accordion.toggle(item.id)" }, properties: { "id": "item.toggleId", "class.collapsed": "item.collapsed", "attr.aria-controls": "item.collapseId", "attr.aria-expanded": "!item.collapsed" } }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionToggle, decorators: [{ type: Directive, args: [{ selector: '[ngbAccordionToggle]', standalone: true, host: { '[id]': 'item.toggleId', '[class.collapsed]': 'item.collapsed', '[attr.aria-controls]': 'item.collapseId', '[attr.aria-expanded]': '!item.collapsed', '(click)': '!item.disabled && accordion.toggle(item.id)', }, }] }] }); /** * A directive to put on a button element inside an accordion item's header. * * If you want a custom markup for the header, you can also use the [`NgbAccordionToggle` directive](#/components/accordion/api#NgbAccordionToggle). * * @since 14.1.0 */ class NgbAccordionButton { constructor() { this.item = inject(NgbAccordionItem); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionButton, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: NgbAccordionButton, isStandalone: true, selector: "button[ngbAccordionButton]", host: { attributes: { "type": "button" }, properties: { "disabled": "item.disabled" }, classAttribute: "accordion-button" }, hostDirectives: [{ directive: NgbAccordionToggle }], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionButton, decorators: [{ type: Directive, args: [{ selector: 'button[ngbAccordionButton]', standalone: true, host: { '[disabled]': 'item.disabled', class: 'accordion-button', type: 'button', }, hostDirectives: [NgbAccordionToggle], }] }] }); /** * A directive that wraps an accordion item's header. * * @since 14.1.0 */ class NgbAccordionHeader { constructor() { this.item = inject(NgbAccordionItem); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: NgbAccordionHeader, isStandalone: true, selector: "[ngbAccordionHeader]", host: { attributes: { "role": "heading" }, properties: { "class.collapsed": "item.collapsed" }, classAttribute: "accordion-header" }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionHeader, decorators: [{ type: Directive, args: [{ selector: '[ngbAccordionHeader]', standalone: true, host: { role: 'heading', class: 'accordion-header', '[class.collapsed]': 'item.collapsed', }, }] }] }); /** * A directive that wraps an accordion item: a toggleable header + body that collapses. * * You can get hold of the `NgbAccordionItem` instance in the template with `#item="ngbAccordionItem"`. * It allows to check if the item is collapsed or not, toggle the collapse state, etc. * * Every accordion item has a string ID that is automatically generated in the `ngb-accordion-item-XX` format, unless provided explicitly. * * @since 14.1.0 */ class NgbAccordionItem { constructor() { this._accordion = inject(NgbAccordionDirective); this._cd = inject(ChangeDetectorRef); this._destroyRef = inject(DestroyRef); this._collapsed = true; this._id = `ngb-accordion-item-${nextId$3++}`; this._collapseAnimationRunning = false; /** * If `true`, the accordion item will be disabled. * It won't react to user's clicks, but still will be toggelable programmatically. */ this.disabled = false; /** * Event emitted before the expanding animation starts. It has no payload. * * @since 15.1.0 */ this.show = new EventEmitter(); /** * Event emitted when the expanding animation is finished. It has no payload. */ this.shown = new EventEmitter(); /** * Event emitted before the collapsing animation starts. It has no payload. * * @since 15.1.0 */ this.hide = new EventEmitter(); /** * Event emitted when the collapsing animation is finished and before the content is removed from DOM. * It has no payload. */ this.hidden = new EventEmitter(); } /** * Sets the custom ID of the accordion item. It must be unique for the document. * * @param id The ID of the accordion item, must be a non-empty string */ set id(id) { if (isString(id) && id !== '') { this._id = id; } } /** * If `true`, the content of the accordion item's body will be removed from the DOM. It will be just hidden otherwise. * * This property can also be set up on the parent [`NgbAccordion` directive](#/components/accordion/api#NgbAccordionDirective). */ set destroyOnHide(destroyOnHide) { this._destroyOnHide = destroyOnHide; } get destroyOnHide() { return this._destroyOnHide === undefined ? this._accordion.destroyOnHide : this._destroyOnHide; } /** * If `true`, the accordion item will be collapsed. Otherwise, it will be expanded. * * @param collapsed New state of the accordion item. */ set collapsed(collapsed) { if (collapsed) { this.collapse(); } else { this.expand(); } } get collapsed() { return this._collapsed; } get id() { return `${this._id}`; } get toggleId() { return `${this.id}-toggle`; } get collapseId() { return `${this.id}-collapse`; } get _shouldBeInDOM() { return !this.collapsed || this._collapseAnimationRunning || !this.destroyOnHide; } ngAfterContentInit() { const { ngbCollapse } = this._collapse; // we need to disable the animation for the first init ngbCollapse.animation = false; ngbCollapse.collapsed = this.collapsed; // we set the animation to the default of the accordion ngbCollapse.animation = this._accordion.animation; // event forwarding from 'ngbCollapse' to 'ngbAccordion' ngbCollapse.hidden.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => { // when the animation finishes we can remove the template from DOM this._collapseAnimationRunning = false; this.hidden.emit(); this._accordion.hidden.emit(this.id); // need if the accordion is used inside a component having OnPush change detection strategy this._cd.markForCheck(); }); ngbCollapse.shown.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => { this.shown.emit(); this._accordion.shown.emit(this.id); // need if the accordion is used inside a component having OnPush change detection strategy this._cd.markForCheck(); }); } /** * Toggles an accordion item. */ toggle() { this.collapsed = !this.collapsed; } /** * Expands an accordion item. */ expand() { if (this.collapsed) { // checking if accordion allows to expand the panel in respect to 'closeOthers' flag if (!this._accordion._ensureCanExpand(this)) { return; } this._collapsed = false; // need if the accordion is used inside a component having OnPush change detection strategy this._cd.markForCheck(); // we need force CD to get template into DOM before starting animation to calculate its height correctly // this will synchronously put the item body into DOM, because `this._collapsed` was flipped to `false` this._cd.detectChanges(); // firing events before starting animations this.show.emit(); this._accordion.show.emit(this.id); // we also need to make sure 'animation' flag is up-to- date this._collapse.ngbCollapse.animation = this._accordion.animation; this._collapse.ngbCollapse.collapsed = false; } } /** * Collapses an accordion item. */ collapse() { if (!this.collapsed) { this._collapsed = true; this._collapseAnimationRunning = true; // need if the accordion is used inside a component having OnPush change detection strategy this._cd.markForCheck(); // firing events before starting animations this.hide.emit(); this._accordion.hide.emit(this.id); // we also need to make sure 'animation' flag is up-to- date this._collapse.ngbCollapse.animation = this._accordion.animation; this._collapse.ngbCollapse.collapsed = true; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: NgbAccordionItem, isStandalone: true, selector: "[ngbAccordionItem]", inputs: { id: ["ngbAccordionItem", "id"], destroyOnHide: "destroyOnHide", disabled: "disabled", collapsed: "collapsed" }, outputs: { show: "show", shown: "shown", hide: "hide", hidden: "hidden" }, host: { properties: { "id": "id" }, classAttribute: "accordion-item" }, queries: [{ propertyName: "_collapse", first: true, predicate: NgbAccordionCollapse, descendants: true, static: true }], exportAs: ["ngbAccordionItem"], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionItem, decorators: [{ type: Directive, args: [{ selector: '[ngbAccordionItem]', exportAs: 'ngbAccordionItem', standalone: true, host: { '[id]': 'id', class: 'accordion-item', }, }] }], propDecorators: { _collapse: [{ type: ContentChild, args: [NgbAccordionCollapse, { static: true }] }], id: [{ type: Input, args: ['ngbAccordionItem'] }], destroyOnHide: [{ type: Input }], disabled: [{ type: Input }], collapsed: [{ type: Input }], show: [{ type: Output }], shown: [{ type: Output }], hide: [{ type: Output }], hidden: [{ type: Output }] } }); /** * Accordion is a stack of cards that have a header and collapsible body. * * This directive is a container for these items and provides an API to handle them. * * @since 14.1.0 */ class NgbAccordionDirective { constructor() { this._config = inject(NgbAccordionConfig); this._anItemWasAlreadyExpandedDuringInitialisation = false; /** * If `true`, accordion will be animated. */ this.animation = this._config.animation; /** * If `true`, only one item at the time can stay open. */ this.closeOthers = this._config.closeOthers; /** * If `true`, the content of the accordion items body will be removed from the DOM. It will be just hidden otherwise. * * This property can be overwritten at the [`NgbAccordionItem`](#/components/accordion/api#NgbAccordionItem) level */ this.destroyOnHide = this._config.destroyOnHide; /** * Event emitted before expanding animation starts. The payload is the id of shown accordion item. * * @since 15.1.0 */ this.show = new EventEmitter(); /** * Event emitted when the expanding animation is finished. The payload is the id of shown accordion item. */ this.shown = new EventEmitter(); /** * Event emitted before the collapsing animation starts. The payload is the id of hidden accordion item. * * @since 15.1.0 */ this.hide = new EventEmitter(); /** * Event emitted when the collapsing animation is finished and before the content is removed from DOM. * The payload is the id of hidden accordion item. */ this.hidden = new EventEmitter(); } /** * Toggles an item with the given id. * * It will toggle an item, even if it is disabled. * * @param itemId The id of the item to toggle. */ toggle(itemId) { this._getItem(itemId)?.toggle(); } /** * Expands an item with the given id. * * If `closeOthers` is `true`, it will collapse other panels. * * @param itemId The id of the item to expand. */ expand(itemId) { this._getItem(itemId)?.expand(); } /** * Expands all items. * * If `closeOthers` is `true` and all items are closed, it will open the first one. Otherwise, it will keep the opened one. */ expandAll() { if (this._items) { if (this.closeOthers) { // we check if there is an item open and if it is not we can expand the first item // (otherwise we toggle nothing) if (!this._items.find((item) => !item.collapsed)) { this._items.first.expand(); } } else { this._items.forEach((item) => item.expand()); } } } /** * Collapses an item with the given id. * * Has no effect if the `itemId` does not correspond to any item. * * @param itemId The id of the item to collapse. */ collapse(itemId) { this._getItem(itemId)?.collapse(); } /** * Collapses all items. */ collapseAll() { this._items?.forEach((item) => item.collapse()); } /** * Checks if an item with the given id is expanded. * * If the `itemId` does not correspond to any item, it returns `false`. * * @param itemId The id of the item to check. */ isExpanded(itemId) { const item = this._getItem(itemId); return item ? !item.collapsed : false; } /** * It checks, if the item can be expanded in the current state of the accordion. * With `closeOthers` there can be only one expanded item at a time. * * @internal */ _ensureCanExpand(toExpand) { if (!this.closeOthers) { return true; } // special case during the initialization of the [collapse]="false" inputs // `this._items` QueryList is not yet initialized, but we need to ensure only one item can be expanded at a time if (!this._items) { if (!this._anItemWasAlreadyExpandedDuringInitialisation) { this._anItemWasAlreadyExpandedDuringInitialisation = true; return true; } return false; } // if there is an expanded item, we need to collapse it first this._items.find((item) => !item.collapsed && toExpand !== item)?.collapse(); return true; } _getItem(itemId) { return this._items?.find((item) => item.id === itemId); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: NgbAccordionDirective, isStandalone: true, selector: "[ngbAccordion]", inputs: { animation: "animation", closeOthers: "closeOthers", destroyOnHide: "destroyOnHide" }, outputs: { show: "show", shown: "shown", hide: "hide", hidden: "hidden" }, host: { classAttribute: "accordion" }, queries: [{ propertyName: "_items", predicate: NgbAccordionItem }], exportAs: ["ngbAccordion"], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionDirective, decorators: [{ type: Directive, args: [{ selector: '[ngbAccordion]', standalone: true, exportAs: 'ngbAccordion', host: { class: 'accordion', }, }] }], propDecorators: { _items: [{ type: ContentChildren, args: [NgbAccordionItem, { descendants: false }] }], animation: [{ type: Input }], closeOthers: [{ type: Input }], destroyOnHide: [{ type: Input }], show: [{ type: Output }], shown: [{ type: Output }], hide: [{ type: Output }], hidden: [{ type: Output }] } }); const NGB_ACCORDION_DIRECTIVES = [ NgbAccordionButton, NgbAccordionDirective, NgbAccordionItem, NgbAccordionHeader, NgbAccordionToggle, NgbAccordionBody, NgbAccordionCollapse, ]; class NgbAccordionModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionModule, imports: [NgbAccordionButton, NgbAccordionDirective, NgbAccordionItem, NgbAccordionHeader, NgbAccordionToggle, NgbAccordionBody, NgbAccordionCollapse], exports: [NgbAccordionButton, NgbAccordionDirective, NgbAccordionItem, NgbAccordionHeader, NgbAccordionToggle, NgbAccordionBody, NgbAccordionCollapse] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionModule }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAccordionModule, decorators: [{ type: NgModule, args: [{ imports: NGB_ACCORDION_DIRECTIVES, exports: NGB_ACCORDION_DIRECTIVES, }] }] }); /** * A configuration service for the [NgbAlert](#/components/alert/api#NgbAlert) component. * * You can inject this service, typically in your root component, and customize its properties * to provide default values for all alerts used in the application. */ class NgbAlertConfig { constructor() { this._ngbConfig = inject(NgbConfig); this.dismissible = true; this.type = 'warning'; } get animation() { return this._animation ?? this._ngbConfig.animation; } set animation(animation) { this._animation = animation; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAlertConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAlertConfig, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAlertConfig, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); const ngbAlertFadingTransition = ({ classList }) => { classList.remove('show'); }; /** * Alert is a component to provide contextual feedback messages for user. * * It supports several alert types and can be dismissed. */ class NgbAlert { constructor() { this._config = inject(NgbAlertConfig); this._elementRef = inject((ElementRef)); this._zone = inject(NgZone); /** * If `true`, alert closing will be animated. * * Animation is triggered only when clicked on the close button (×) * or via the `.close()` function * * @since 8.0.0 */ this.animation = this._config.animation; /** * If `true`, alert can be dismissed by the user. * * The close button (×) will be displayed and you can be notified * of the event with the `(closed)` output. */ this.dismissible = this._config.dismissible; /** * Type of the alert. * * Bootstrap provides styles for the following types: `'success'`, `'info'`, `'warning'`, `'danger'`, `'primary'`, * `'secondary'`, `'light'` and `'dark'`. */ this.type = this._config.type; /** * An event emitted when the close button is clicked. It has no payload and only relevant for dismissible alerts. * * @since 8.0.0 */ this.closed = new EventEmitter(); } /** * Triggers alert closing programmatically (same as clicking on the close button (×)). * * The returned observable will emit and be completed once the closing transition has finished. * If the animations are turned off this happens synchronously. * * Alternatively you could listen or subscribe to the `(closed)` output * * @since 8.0.0 */ close() { const transition = ngbRunTransition(this._zone, this._elementRef.nativeElement, ngbAlertFadingTransition, { animation: this.animation, runningTransition: 'continue', }); transition.subscribe(() => this.closed.emit()); return transition; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAlert, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.3", type: NgbAlert, isStandalone: true, selector: "ngb-alert", inputs: { animation: "animation", dismissible: "dismissible", type: "type" }, outputs: { closed: "closed" }, host: { attributes: { "role": "alert" }, properties: { "class": "\"alert show\" + (type ? \" alert-\" + type : \"\")", "class.fade": "animation", "class.alert-dismissible": "dismissible" } }, exportAs: ["ngbAlert"], ngImport: i0, template: ` <ng-content /> @if (dismissible) { <button type="button" class="btn-close" aria-label="Close" i18n-aria-label="@@ngb.alert.close" (click)="close()" ></button> } `, isInline: true, styles: ["ngb-alert{display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAlert, decorators: [{ type: Component, args: [{ selector: 'ngb-alert', exportAs: 'ngbAlert', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { role: 'alert', '[class]': '"alert show" + (type ? " alert-" + type : "")', '[class.fade]': 'animation', '[class.alert-dismissible]': 'dismissible', }, template: ` <ng-content /> @if (dismissible) { <button type="button" class="btn-close" aria-label="Close" i18n-aria-label="@@ngb.alert.close" (click)="close()" ></button> } `, styles: ["ngb-alert{display:block}\n"] }] }], propDecorators: { animation: [{ type: Input }], dismissible: [{ type: Input }], type: [{ type: Input }], closed: [{ type: Output }] } }); class NgbAlertModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAlertModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.3", ngImport: i0, type: NgbAlertModule, imports: [NgbAlert], exports: [NgbAlert] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAlertModule }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbAlertModule, decorators: [{ type: NgModule, args: [{ imports: [NgbAlert], exports: [NgbAlert], }] }] }); /** * A configuration service for the [NgbCarousel](#/components/carousel/api#NgbCarousel) component. * * You can inject this service, typically in your root component, and customize its properties * to provide default values for all carousels used in the application. */ class NgbCarouselConfig { constructor() { this._ngbConfig = inject(NgbConfig); this.interval = 5000; this.wrap = true; this.keyboard = true; this.pauseOnHover = true; this.pauseOnFocus = true; this.showNavigationArrows = true; this.showNavigationIndicators = true; } get animation() { return this._animation ?? this._ngbConfig.animation; } set animation(animation) { this._animation = animation; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbCarouselConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbCarouselConfig, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgbCarouselConfig, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /** * Defines the carousel slide transition direction. */ var NgbSlideEventDirection; (function (NgbSlideEventDirection) { NgbSlideEventDirection["START"] = "start"; NgbSlideEventDirection["END"] = "end"; })(NgbSlideEventDirection || (NgbSlideEventDirection = {})); const isBeingAnimated = ({ classList }) => { return classList.contains('carousel-item-start') || classList.contains('carousel-item-end'); }; const removeDirectionClasses = (classList) => { classList.remove('carousel-item-start', 'carousel-ite