UNPKG

ngx-bootstrap

Version:
432 lines (423 loc) 20.2 kB
import * as i0 from '@angular/core'; import { Directive, Input, Injectable, Component, HostBinding, EventEmitter, Output, NgModule } from '@angular/core'; import { NgClass, NgFor, NgIf, CommonModule } from '@angular/common'; class NgTranscludeDirective { set ngTransclude(templateRef) { this._ngTransclude = templateRef; if (templateRef) { this.viewRef.createEmbeddedView(templateRef); } } // eslint-disable-next-line @typescript-eslint/no-explicit-any get ngTransclude() { return this._ngTransclude; } constructor(viewRef) { this.viewRef = viewRef; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: NgTranscludeDirective, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.1", type: NgTranscludeDirective, isStandalone: true, selector: "[ngTransclude]", inputs: { ngTransclude: "ngTransclude" }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: NgTranscludeDirective, decorators: [{ type: Directive, args: [{ selector: '[ngTransclude]', standalone: true }] }], ctorParameters: () => [{ type: i0.ViewContainerRef }], propDecorators: { ngTransclude: [{ type: Input }] } }); class TabsetConfig { constructor() { /** provides default navigation context class: 'tabs' or 'pills' */ this.type = 'tabs'; /** provides possibility to set keyNavigations enable or disable, by default is enable */ this.isKeysAllowed = true; /** aria label for tab list */ this.ariaLabel = 'Tabs'; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabsetConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabsetConfig, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabsetConfig, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); // todo: add active event to tab // todo: fix? mixing static and dynamic tabs position tabs in order of creation class TabsetComponent { /** if true tabs will be placed vertically */ get vertical() { return this._vertical; } set vertical(value) { this._vertical = value; this.setClassMap(); } /** if true tabs fill the container and have a consistent width */ get justified() { return this._justified; } set justified(value) { this._justified = value; this.setClassMap(); } /** navigation context class: 'tabs' or 'pills' */ get type() { return this._type; } set type(value) { this._type = value; this.setClassMap(); } get isKeysAllowed() { return this._isKeysAllowed; } set isKeysAllowed(value) { this._isKeysAllowed = value; } constructor(config, renderer, elementRef) { this.renderer = renderer; this.elementRef = elementRef; this.clazz = true; this.tabs = []; this.classMap = {}; /** aria label for tab list */ this.ariaLabel = 'Tabs'; this.isDestroyed = false; this._vertical = false; this._justified = false; this._type = 'tabs'; this._isKeysAllowed = true; Object.assign(this, config); } ngOnDestroy() { this.isDestroyed = true; } addTab(tab) { this.tabs.push(tab); tab.active = this.tabs.length === 1 && !tab.active; } removeTab(tab, options = { reselect: true, emit: true }) { const index = this.tabs.indexOf(tab); if (index === -1 || this.isDestroyed) { return; } // Select a new tab if the tab to be removed is selected and not destroyed if (options.reselect && tab.active && this.hasAvailableTabs(index)) { const newActiveIndex = this.getClosestTabIndex(index); this.tabs[newActiveIndex].active = true; } if (options.emit) { tab.removed.emit(tab); } this.tabs.splice(index, 1); if (tab.elementRef.nativeElement.parentNode) { this.renderer.removeChild(tab.elementRef.nativeElement.parentNode, tab.elementRef.nativeElement); } } keyNavActions(event, index) { if (!this.isKeysAllowed) { return; } const list = Array.from(this.elementRef.nativeElement.querySelectorAll('.nav-link')); // const activeElList = list.filter((el: HTMLElement) => !el.classList.contains('disabled')); if (event.keyCode === 13 || event.key === 'Enter' || event.keyCode === 32 || event.key === 'Space') { event.preventDefault(); const currentTab = list[(index) % list.length]; currentTab.click(); return; } if (event.keyCode === 39 || event.key === 'RightArrow') { let nextTab; let shift = 1; do { nextTab = list[(index + shift) % list.length]; shift++; } while (nextTab.classList.contains('disabled')); nextTab.focus(); return; } if (event.keyCode === 37 || event.key === 'LeftArrow') { let previousTab; let shift = 1; let i = index; do { if ((i - shift) < 0) { i = list.length - 1; previousTab = list[i]; shift = 0; } else { previousTab = list[i - shift]; } shift++; } while (previousTab.classList.contains('disabled')); previousTab.focus(); return; } if (event.keyCode === 36 || event.key === 'Home') { event.preventDefault(); let firstTab; let shift = 0; do { firstTab = list[shift % list.length]; shift++; } while (firstTab.classList.contains('disabled')); firstTab.focus(); return; } if (event.keyCode === 35 || event.key === 'End') { event.preventDefault(); let lastTab; let shift = 1; let i = index; do { if ((i - shift) < 0) { i = list.length - 1; lastTab = list[i]; shift = 0; } else { lastTab = list[i - shift]; } shift++; } while (lastTab.classList.contains('disabled')); lastTab.focus(); return; } if (event.keyCode === 46 || event.key === 'Delete') { if (this.tabs[index].removable) { this.removeTab(this.tabs[index]); if (list[index + 1]) { list[(index + 1) % list.length].focus(); return; } if (list[list.length - 1]) { list[0].focus(); } } } } getClosestTabIndex(index) { const tabsLength = this.tabs.length; if (!tabsLength) { return -1; } for (let step = 1; step <= tabsLength; step += 1) { const prevIndex = index - step; const nextIndex = index + step; if (this.tabs[prevIndex] && !this.tabs[prevIndex].disabled) { return prevIndex; } if (this.tabs[nextIndex] && !this.tabs[nextIndex].disabled) { return nextIndex; } } return -1; } hasAvailableTabs(index) { const tabsLength = this.tabs.length; if (!tabsLength) { return false; } for (let i = 0; i < tabsLength; i += 1) { if (!this.tabs[i].disabled && i !== index) { return true; } } return false; } setClassMap() { this.classMap = { 'nav-stacked': this.vertical, 'flex-column': this.vertical, 'nav-justified': this.justified, [`nav-${this.type}`]: true }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabsetComponent, deps: [{ token: TabsetConfig }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.1", type: TabsetComponent, isStandalone: true, selector: "tabset", inputs: { vertical: "vertical", justified: "justified", type: "type" }, host: { properties: { "class.tab-container": "this.clazz" } }, ngImport: i0, template: "<ul class=\"nav\" [ngClass]=\"classMap\"\n (click)=\"$event.preventDefault()\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"tablist\">\n <li *ngFor=\"let tabz of tabs; let i = index\" [ngClass]=\"['nav-item', tabz.customClass || '']\"\n [class.active]=\"tabz.active\" [class.disabled]=\"tabz.disabled\" (keydown)=\"keyNavActions($event, i)\">\n <a href=\"javascript:void(0);\" class=\"nav-link\" role=\"tab\"\n [attr.aria-controls]=\"tabz.id ? tabz.id : ''\"\n [attr.aria-selected]=\"!!tabz.active\"\n [attr.id]=\"tabz.id ? tabz.id + '-link' : ''\"\n [class.active]=\"tabz.active\" [class.disabled]=\"tabz.disabled\"\n (click)=\"tabz.active = true\">\n <span [ngTransclude]=\"tabz.headingRef\">{{ tabz.heading }}</span>\n <span *ngIf=\"tabz.removable\" (click)=\"$event.preventDefault(); removeTab(tabz);\" class=\"bs-remove-tab\"> &#10060;</span>\n </a>\n </li>\n</ul>\n<div class=\"tab-content\">\n <ng-content></ng-content>\n</div>\n", styles: [":host .nav-tabs .nav-item.disabled a.disabled{cursor:default}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgTranscludeDirective, selector: "[ngTransclude]", inputs: ["ngTransclude"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabsetComponent, decorators: [{ type: Component, args: [{ selector: 'tabset', standalone: true, imports: [NgClass, NgFor, NgTranscludeDirective, NgIf], template: "<ul class=\"nav\" [ngClass]=\"classMap\"\n (click)=\"$event.preventDefault()\"\n [attr.aria-label]=\"ariaLabel\"\n role=\"tablist\">\n <li *ngFor=\"let tabz of tabs; let i = index\" [ngClass]=\"['nav-item', tabz.customClass || '']\"\n [class.active]=\"tabz.active\" [class.disabled]=\"tabz.disabled\" (keydown)=\"keyNavActions($event, i)\">\n <a href=\"javascript:void(0);\" class=\"nav-link\" role=\"tab\"\n [attr.aria-controls]=\"tabz.id ? tabz.id : ''\"\n [attr.aria-selected]=\"!!tabz.active\"\n [attr.id]=\"tabz.id ? tabz.id + '-link' : ''\"\n [class.active]=\"tabz.active\" [class.disabled]=\"tabz.disabled\"\n (click)=\"tabz.active = true\">\n <span [ngTransclude]=\"tabz.headingRef\">{{ tabz.heading }}</span>\n <span *ngIf=\"tabz.removable\" (click)=\"$event.preventDefault(); removeTab(tabz);\" class=\"bs-remove-tab\"> &#10060;</span>\n </a>\n </li>\n</ul>\n<div class=\"tab-content\">\n <ng-content></ng-content>\n</div>\n", styles: [":host .nav-tabs .nav-item.disabled a.disabled{cursor:default}\n"] }] }], ctorParameters: () => [{ type: TabsetConfig }, { type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { vertical: [{ type: Input }], justified: [{ type: Input }], type: [{ type: Input }], clazz: [{ type: HostBinding, args: ['class.tab-container'] }] } }); class TabDirective { /** if set, will be added to the tab's class attribute. Multiple classes are supported. */ get customClass() { return this._customClass; } set customClass(customClass) { if (this.customClass) { this.customClass.split(' ').forEach((cssClass) => { this.renderer.removeClass(this.elementRef.nativeElement, cssClass); }); } this._customClass = customClass ? customClass.trim() : ''; if (this.customClass) { this.customClass.split(' ').forEach((cssClass) => { this.renderer.addClass(this.elementRef.nativeElement, cssClass); }); } } /** tab active state toggle */ get active() { return this._active; } set active(active) { if (this._active === active) { return; } if ((this.disabled && active) || !active) { if (this._active && !active) { this.deselect.emit(this); this._active = active; } return; } this._active = active; this.selectTab.emit(this); this.tabset.tabs.forEach((tab) => { if (tab !== this) { tab.active = false; } }); } get ariaLabelledby() { return this.id ? `${this.id}-link` : ''; } constructor(tabset, elementRef, renderer) { this.elementRef = elementRef; this.renderer = renderer; /** if true tab can not be activated */ this.disabled = false; /** if true tab can be removable, additional button will appear */ this.removable = false; /** fired when tab became active, $event:Tab equals to selected instance of Tab component */ this.selectTab = new EventEmitter(); /** fired when tab became inactive, $event:Tab equals to deselected instance of Tab component */ this.deselect = new EventEmitter(); /** fired before tab will be removed, $event:Tab equals to instance of removed tab */ this.removed = new EventEmitter(); this.addClass = true; this.role = 'tabpanel'; this._active = false; this._customClass = ''; this.tabset = tabset; this.tabset.addTab(this); } ngOnInit() { this.removable = !!this.removable; } ngOnDestroy() { this.tabset.removeTab(this, { reselect: false, emit: false }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabDirective, deps: [{ token: TabsetComponent }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.1", type: TabDirective, isStandalone: true, selector: "tab, [tab]", inputs: { heading: "heading", id: "id", disabled: "disabled", removable: "removable", customClass: "customClass", active: "active" }, outputs: { selectTab: "selectTab", deselect: "deselect", removed: "removed" }, host: { properties: { "attr.id": "this.id", "class.active": "this.active", "class.tab-pane": "this.addClass", "attr.role": "this.role", "attr.aria-labelledby": "this.ariaLabelledby" } }, exportAs: ["tab"], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabDirective, decorators: [{ type: Directive, args: [{ selector: 'tab, [tab]', exportAs: 'tab', standalone: true }] }], ctorParameters: () => [{ type: TabsetComponent }, { type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { heading: [{ type: Input }], id: [{ type: HostBinding, args: ['attr.id'] }, { type: Input }], disabled: [{ type: Input }], removable: [{ type: Input }], customClass: [{ type: Input }], active: [{ type: HostBinding, args: ['class.active'] }, { type: Input }], selectTab: [{ type: Output }], deselect: [{ type: Output }], removed: [{ type: Output }], addClass: [{ type: HostBinding, args: ['class.tab-pane'] }], role: [{ type: HostBinding, args: ['attr.role'] }], ariaLabelledby: [{ type: HostBinding, args: ['attr.aria-labelledby'] }] } }); /** Should be used to mark <ng-template> element as a template for tab heading */ class TabHeadingDirective { // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(templateRef, tab) { tab.headingRef = templateRef; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabHeadingDirective, deps: [{ token: i0.TemplateRef }, { token: TabDirective }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.1", type: TabHeadingDirective, isStandalone: true, selector: "[tabHeading]", ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabHeadingDirective, decorators: [{ type: Directive, args: [{ selector: '[tabHeading]', standalone: true }] }], ctorParameters: () => [{ type: i0.TemplateRef }, { type: TabDirective }] }); class TabsModule { // @deprecated method not required anymore, will be deleted in v19.0.0 static forRoot() { return { ngModule: TabsModule, providers: [] }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.1", ngImport: i0, type: TabsModule, imports: [CommonModule, NgTranscludeDirective, TabDirective, TabsetComponent, TabHeadingDirective], exports: [TabDirective, TabsetComponent, TabHeadingDirective, NgTranscludeDirective] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabsModule, imports: [CommonModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.1", ngImport: i0, type: TabsModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, NgTranscludeDirective, TabDirective, TabsetComponent, TabHeadingDirective], exports: [ TabDirective, TabsetComponent, TabHeadingDirective, NgTranscludeDirective ] }] }] }); /** * Generated bundle index. Do not edit. */ export { NgTranscludeDirective, TabDirective, TabHeadingDirective, TabsModule, TabsetComponent, TabsetConfig }; //# sourceMappingURL=ngx-bootstrap-tabs.mjs.map