@ng-bootstrap/ng-bootstrap
Version:
Angular powered Bootstrap
1,194 lines (1,177 loc) • 551 kB
JavaScript
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