UNPKG

135 kBJavaScriptView Raw
1import * as i7 from '@angular/cdk/a11y';
2import { FocusKeyManager, A11yModule } from '@angular/cdk/a11y';
3import * as i5 from '@angular/cdk/observers';
4import { ObserversModule } from '@angular/cdk/observers';
5import * as i2 from '@angular/cdk/portal';
6import { CdkPortal, TemplatePortal, CdkPortalOutlet, PortalModule } from '@angular/cdk/portal';
7import * as i1$2 from '@angular/common';
8import { DOCUMENT, CommonModule } from '@angular/common';
9import * as i0 from '@angular/core';
10import { InjectionToken, Directive, Inject, Optional, TemplateRef, Component, ChangeDetectionStrategy, ViewEncapsulation, ContentChild, ViewChild, Input, forwardRef, EventEmitter, Output, ContentChildren, QueryList, Attribute, NgModule } from '@angular/core';
11import * as i4 from '@angular/material/core';
12import { mixinDisabled, mixinColor, mixinDisableRipple, mixinTabIndex, MAT_RIPPLE_GLOBAL_OPTIONS, RippleRenderer, MatCommonModule, MatRippleModule } from '@angular/material/core';
13import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';
14import { take, startWith, distinctUntilChanged, takeUntil, switchMap, skip } from 'rxjs/operators';
15import { Subject, Subscription, fromEvent, of, merge, EMPTY, Observable, timer } from 'rxjs';
16import * as i1 from '@angular/cdk/bidi';
17import { trigger, state, style, transition, animate } from '@angular/animations';
18import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
19import * as i1$1 from '@angular/cdk/scrolling';
20import * as i3 from '@angular/cdk/platform';
21import { normalizePassiveListenerOptions } from '@angular/cdk/platform';
22import { hasModifierKey, SPACE, ENTER } from '@angular/cdk/keycodes';
23
24/**
25 * @license
26 * Copyright Google LLC All Rights Reserved.
27 *
28 * Use of this source code is governed by an MIT-style license that can be
29 * found in the LICENSE file at https://angular.io/license
30 */
31/** Injection token for the MatInkBar's Positioner. */
32const _MAT_INK_BAR_POSITIONER = new InjectionToken('MatInkBarPositioner', {
33 providedIn: 'root',
34 factory: _MAT_INK_BAR_POSITIONER_FACTORY,
35});
36/**
37 * The default positioner function for the MatInkBar.
38 * @docs-private
39 */
40function _MAT_INK_BAR_POSITIONER_FACTORY() {
41 const method = (element) => ({
42 left: element ? (element.offsetLeft || 0) + 'px' : '0',
43 width: element ? (element.offsetWidth || 0) + 'px' : '0',
44 });
45 return method;
46}
47/**
48 * The ink-bar is used to display and animate the line underneath the current active tab label.
49 * @docs-private
50 */
51class MatInkBar {
52 constructor(_elementRef, _ngZone, _inkBarPositioner, _animationMode) {
53 this._elementRef = _elementRef;
54 this._ngZone = _ngZone;
55 this._inkBarPositioner = _inkBarPositioner;
56 this._animationMode = _animationMode;
57 }
58 /**
59 * Calculates the styles from the provided element in order to align the ink-bar to that element.
60 * Shows the ink bar if previously set as hidden.
61 * @param element
62 */
63 alignToElement(element) {
64 this.show();
65 this._ngZone.onStable.pipe(take(1)).subscribe(() => {
66 const positions = this._inkBarPositioner(element);
67 const inkBar = this._elementRef.nativeElement;
68 inkBar.style.left = positions.left;
69 inkBar.style.width = positions.width;
70 });
71 }
72 /** Shows the ink bar. */
73 show() {
74 this._elementRef.nativeElement.style.visibility = 'visible';
75 }
76 /** Hides the ink bar. */
77 hide() {
78 this._elementRef.nativeElement.style.visibility = 'hidden';
79 }
80}
81MatInkBar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatInkBar, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: _MAT_INK_BAR_POSITIONER }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
82MatInkBar.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatInkBar, selector: "mat-ink-bar", host: { properties: { "class._mat-animation-noopable": "_animationMode === 'NoopAnimations'" }, classAttribute: "mat-ink-bar" }, ngImport: i0 });
83i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatInkBar, decorators: [{
84 type: Directive,
85 args: [{
86 selector: 'mat-ink-bar',
87 host: {
88 'class': 'mat-ink-bar',
89 '[class._mat-animation-noopable]': `_animationMode === 'NoopAnimations'`,
90 },
91 }]
92 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: undefined, decorators: [{
93 type: Inject,
94 args: [_MAT_INK_BAR_POSITIONER]
95 }] }, { type: undefined, decorators: [{
96 type: Optional
97 }, {
98 type: Inject,
99 args: [ANIMATION_MODULE_TYPE]
100 }] }]; } });
101
102/**
103 * @license
104 * Copyright Google LLC All Rights Reserved.
105 *
106 * Use of this source code is governed by an MIT-style license that can be
107 * found in the LICENSE file at https://angular.io/license
108 */
109/**
110 * Injection token that can be used to reference instances of `MatTabContent`. It serves as
111 * alternative token to the actual `MatTabContent` class which could cause unnecessary
112 * retention of the class and its directive metadata.
113 */
114const MAT_TAB_CONTENT = new InjectionToken('MatTabContent');
115/** Decorates the `ng-template` tags and reads out the template from it. */
116class MatTabContent {
117 constructor(/** Content for the tab. */ template) {
118 this.template = template;
119 }
120}
121MatTabContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabContent, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
122MatTabContent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatTabContent, selector: "[matTabContent]", providers: [{ provide: MAT_TAB_CONTENT, useExisting: MatTabContent }], ngImport: i0 });
123i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabContent, decorators: [{
124 type: Directive,
125 args: [{
126 selector: '[matTabContent]',
127 providers: [{ provide: MAT_TAB_CONTENT, useExisting: MatTabContent }],
128 }]
129 }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
130
131/**
132 * @license
133 * Copyright Google LLC All Rights Reserved.
134 *
135 * Use of this source code is governed by an MIT-style license that can be
136 * found in the LICENSE file at https://angular.io/license
137 */
138/**
139 * Injection token that can be used to reference instances of `MatTabLabel`. It serves as
140 * alternative token to the actual `MatTabLabel` class which could cause unnecessary
141 * retention of the class and its directive metadata.
142 */
143const MAT_TAB_LABEL = new InjectionToken('MatTabLabel');
144/**
145 * Used to provide a tab label to a tab without causing a circular dependency.
146 * @docs-private
147 */
148const MAT_TAB = new InjectionToken('MAT_TAB');
149/** Used to flag tab labels for use with the portal directive */
150class MatTabLabel extends CdkPortal {
151 constructor(templateRef, viewContainerRef, _closestTab) {
152 super(templateRef, viewContainerRef);
153 this._closestTab = _closestTab;
154 }
155}
156MatTabLabel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabLabel, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: MAT_TAB, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
157MatTabLabel.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatTabLabel, selector: "[mat-tab-label], [matTabLabel]", providers: [{ provide: MAT_TAB_LABEL, useExisting: MatTabLabel }], usesInheritance: true, ngImport: i0 });
158i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabLabel, decorators: [{
159 type: Directive,
160 args: [{
161 selector: '[mat-tab-label], [matTabLabel]',
162 providers: [{ provide: MAT_TAB_LABEL, useExisting: MatTabLabel }],
163 }]
164 }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
165 type: Inject,
166 args: [MAT_TAB]
167 }, {
168 type: Optional
169 }] }]; } });
170
171/**
172 * @license
173 * Copyright Google LLC All Rights Reserved.
174 *
175 * Use of this source code is governed by an MIT-style license that can be
176 * found in the LICENSE file at https://angular.io/license
177 */
178// Boilerplate for applying mixins to MatTab.
179/** @docs-private */
180const _MatTabBase = mixinDisabled(class {
181});
182/**
183 * Used to provide a tab group to a tab without causing a circular dependency.
184 * @docs-private
185 */
186const MAT_TAB_GROUP = new InjectionToken('MAT_TAB_GROUP');
187class MatTab extends _MatTabBase {
188 constructor(_viewContainerRef, _closestTabGroup) {
189 super();
190 this._viewContainerRef = _viewContainerRef;
191 this._closestTabGroup = _closestTabGroup;
192 /** Plain text label for the tab, used when there is no template label. */
193 this.textLabel = '';
194 /** Portal that will be the hosted content of the tab */
195 this._contentPortal = null;
196 /** Emits whenever the internal state of the tab changes. */
197 this._stateChanges = new Subject();
198 /**
199 * The relatively indexed position where 0 represents the center, negative is left, and positive
200 * represents the right.
201 */
202 this.position = null;
203 /**
204 * The initial relatively index origin of the tab if it was created and selected after there
205 * was already a selected tab. Provides context of what position the tab should originate from.
206 */
207 this.origin = null;
208 /**
209 * Whether the tab is currently active.
210 */
211 this.isActive = false;
212 }
213 /** Content for the tab label given by `<ng-template mat-tab-label>`. */
214 get templateLabel() {
215 return this._templateLabel;
216 }
217 set templateLabel(value) {
218 this._setTemplateLabelInput(value);
219 }
220 /** @docs-private */
221 get content() {
222 return this._contentPortal;
223 }
224 ngOnChanges(changes) {
225 if (changes.hasOwnProperty('textLabel') || changes.hasOwnProperty('disabled')) {
226 this._stateChanges.next();
227 }
228 }
229 ngOnDestroy() {
230 this._stateChanges.complete();
231 }
232 ngOnInit() {
233 this._contentPortal = new TemplatePortal(this._explicitContent || this._implicitContent, this._viewContainerRef);
234 }
235 /**
236 * This has been extracted to a util because of TS 4 and VE.
237 * View Engine doesn't support property rename inheritance.
238 * TS 4.0 doesn't allow properties to override accessors or vice-versa.
239 * @docs-private
240 */
241 _setTemplateLabelInput(value) {
242 // Only update the label if the query managed to find one. This works around an issue where a
243 // user may have manually set `templateLabel` during creation mode, which would then get
244 // clobbered by `undefined` when the query resolves. Also note that we check that the closest
245 // tab matches the current one so that we don't pick up labels from nested tabs.
246 if (value && value._closestTab === this) {
247 this._templateLabel = value;
248 }
249 }
250}
251MatTab.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTab, deps: [{ token: i0.ViewContainerRef }, { token: MAT_TAB_GROUP, optional: true }], target: i0.ɵɵFactoryTarget.Component });
252MatTab.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatTab, selector: "mat-tab", inputs: { disabled: "disabled", textLabel: ["label", "textLabel"], ariaLabel: ["aria-label", "ariaLabel"], ariaLabelledby: ["aria-labelledby", "ariaLabelledby"], labelClass: "labelClass", bodyClass: "bodyClass" }, providers: [{ provide: MAT_TAB, useExisting: MatTab }], queries: [{ propertyName: "templateLabel", first: true, predicate: MAT_TAB_LABEL, descendants: true }, { propertyName: "_explicitContent", first: true, predicate: MAT_TAB_CONTENT, descendants: true, read: TemplateRef, static: true }], viewQueries: [{ propertyName: "_implicitContent", first: true, predicate: TemplateRef, descendants: true, static: true }], exportAs: ["matTab"], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<!-- Create a template for the content of the <mat-tab> so that we can grab a reference to this\n TemplateRef and use it in a Portal to render the tab content in the appropriate place in the\n tab-group. -->\n<ng-template><ng-content></ng-content></ng-template>\n", changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None });
253i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTab, decorators: [{
254 type: Component,
255 args: [{ selector: 'mat-tab', inputs: ['disabled'], changeDetection: ChangeDetectionStrategy.Default, encapsulation: ViewEncapsulation.None, exportAs: 'matTab', providers: [{ provide: MAT_TAB, useExisting: MatTab }], template: "<!-- Create a template for the content of the <mat-tab> so that we can grab a reference to this\n TemplateRef and use it in a Portal to render the tab content in the appropriate place in the\n tab-group. -->\n<ng-template><ng-content></ng-content></ng-template>\n" }]
256 }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: undefined, decorators: [{
257 type: Inject,
258 args: [MAT_TAB_GROUP]
259 }, {
260 type: Optional
261 }] }]; }, propDecorators: { templateLabel: [{
262 type: ContentChild,
263 args: [MAT_TAB_LABEL]
264 }], _explicitContent: [{
265 type: ContentChild,
266 args: [MAT_TAB_CONTENT, { read: TemplateRef, static: true }]
267 }], _implicitContent: [{
268 type: ViewChild,
269 args: [TemplateRef, { static: true }]
270 }], textLabel: [{
271 type: Input,
272 args: ['label']
273 }], ariaLabel: [{
274 type: Input,
275 args: ['aria-label']
276 }], ariaLabelledby: [{
277 type: Input,
278 args: ['aria-labelledby']
279 }], labelClass: [{
280 type: Input
281 }], bodyClass: [{
282 type: Input
283 }] } });
284
285/**
286 * @license
287 * Copyright Google LLC All Rights Reserved.
288 *
289 * Use of this source code is governed by an MIT-style license that can be
290 * found in the LICENSE file at https://angular.io/license
291 */
292/**
293 * Animations used by the Material tabs.
294 * @docs-private
295 */
296const matTabsAnimations = {
297 /** Animation translates a tab along the X axis. */
298 translateTab: trigger('translateTab', [
299 // Transitions to `none` instead of 0, because some browsers might blur the content.
300 state('center, void, left-origin-center, right-origin-center', style({ transform: 'none' })),
301 // If the tab is either on the left or right, we additionally add a `min-height` of 1px
302 // in order to ensure that the element has a height before its state changes. This is
303 // necessary because Chrome does seem to skip the transition in RTL mode if the element does
304 // not have a static height and is not rendered. See related issue: #9465
305 state('left', style({
306 transform: 'translate3d(-100%, 0, 0)',
307 minHeight: '1px',
308 // Normally this is redundant since we detach the content from the DOM, but if the user
309 // opted into keeping the content in the DOM, we have to hide it so it isn't focusable.
310 visibility: 'hidden',
311 })),
312 state('right', style({
313 transform: 'translate3d(100%, 0, 0)',
314 minHeight: '1px',
315 visibility: 'hidden',
316 })),
317 transition('* => left, * => right, left => center, right => center', animate('{{animationDuration}} cubic-bezier(0.35, 0, 0.25, 1)')),
318 transition('void => left-origin-center', [
319 style({ transform: 'translate3d(-100%, 0, 0)', visibility: 'hidden' }),
320 animate('{{animationDuration}} cubic-bezier(0.35, 0, 0.25, 1)'),
321 ]),
322 transition('void => right-origin-center', [
323 style({ transform: 'translate3d(100%, 0, 0)', visibility: 'hidden' }),
324 animate('{{animationDuration}} cubic-bezier(0.35, 0, 0.25, 1)'),
325 ]),
326 ]),
327};
328
329/**
330 * @license
331 * Copyright Google LLC All Rights Reserved.
332 *
333 * Use of this source code is governed by an MIT-style license that can be
334 * found in the LICENSE file at https://angular.io/license
335 */
336/**
337 * The portal host directive for the contents of the tab.
338 * @docs-private
339 */
340class MatTabBodyPortal extends CdkPortalOutlet {
341 constructor(componentFactoryResolver, viewContainerRef, _host, _document) {
342 super(componentFactoryResolver, viewContainerRef, _document);
343 this._host = _host;
344 /** Subscription to events for when the tab body begins centering. */
345 this._centeringSub = Subscription.EMPTY;
346 /** Subscription to events for when the tab body finishes leaving from center position. */
347 this._leavingSub = Subscription.EMPTY;
348 }
349 /** Set initial visibility or set up subscription for changing visibility. */
350 ngOnInit() {
351 super.ngOnInit();
352 this._centeringSub = this._host._beforeCentering
353 .pipe(startWith(this._host._isCenterPosition(this._host._position)))
354 .subscribe((isCentering) => {
355 if (isCentering && !this.hasAttached()) {
356 this.attach(this._host._content);
357 }
358 });
359 this._leavingSub = this._host._afterLeavingCenter.subscribe(() => {
360 if (!this._host.preserveContent) {
361 this.detach();
362 }
363 });
364 }
365 /** Clean up centering subscription. */
366 ngOnDestroy() {
367 super.ngOnDestroy();
368 this._centeringSub.unsubscribe();
369 this._leavingSub.unsubscribe();
370 }
371}
372MatTabBodyPortal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabBodyPortal, deps: [{ token: i0.ComponentFactoryResolver }, { token: i0.ViewContainerRef }, { token: forwardRef(() => MatTabBody) }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive });
373MatTabBodyPortal.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatTabBodyPortal, selector: "[matTabBodyHost]", usesInheritance: true, ngImport: i0 });
374i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabBodyPortal, decorators: [{
375 type: Directive,
376 args: [{
377 selector: '[matTabBodyHost]',
378 }]
379 }], ctorParameters: function () { return [{ type: i0.ComponentFactoryResolver }, { type: i0.ViewContainerRef }, { type: MatTabBody, decorators: [{
380 type: Inject,
381 args: [forwardRef(() => MatTabBody)]
382 }] }, { type: undefined, decorators: [{
383 type: Inject,
384 args: [DOCUMENT]
385 }] }]; } });
386/**
387 * Base class with all of the `MatTabBody` functionality.
388 * @docs-private
389 */
390class _MatTabBodyBase {
391 constructor(_elementRef, _dir, changeDetectorRef) {
392 this._elementRef = _elementRef;
393 this._dir = _dir;
394 /** Subscription to the directionality change observable. */
395 this._dirChangeSubscription = Subscription.EMPTY;
396 /** Emits when an animation on the tab is complete. */
397 this._translateTabComplete = new Subject();
398 /** Event emitted when the tab begins to animate towards the center as the active tab. */
399 this._onCentering = new EventEmitter();
400 /** Event emitted before the centering of the tab begins. */
401 this._beforeCentering = new EventEmitter();
402 /** Event emitted before the centering of the tab begins. */
403 this._afterLeavingCenter = new EventEmitter();
404 /** Event emitted when the tab completes its animation towards the center. */
405 this._onCentered = new EventEmitter(true);
406 // Note that the default value will always be overwritten by `MatTabBody`, but we need one
407 // anyway to prevent the animations module from throwing an error if the body is used on its own.
408 /** Duration for the tab's animation. */
409 this.animationDuration = '500ms';
410 /** Whether the tab's content should be kept in the DOM while it's off-screen. */
411 this.preserveContent = false;
412 if (_dir) {
413 this._dirChangeSubscription = _dir.change.subscribe((dir) => {
414 this._computePositionAnimationState(dir);
415 changeDetectorRef.markForCheck();
416 });
417 }
418 // Ensure that we get unique animation events, because the `.done` callback can get
419 // invoked twice in some browsers. See https://github.com/angular/angular/issues/24084.
420 this._translateTabComplete
421 .pipe(distinctUntilChanged((x, y) => {
422 return x.fromState === y.fromState && x.toState === y.toState;
423 }))
424 .subscribe(event => {
425 // If the transition to the center is complete, emit an event.
426 if (this._isCenterPosition(event.toState) && this._isCenterPosition(this._position)) {
427 this._onCentered.emit();
428 }
429 if (this._isCenterPosition(event.fromState) && !this._isCenterPosition(this._position)) {
430 this._afterLeavingCenter.emit();
431 }
432 });
433 }
434 /** The shifted index position of the tab body, where zero represents the active center tab. */
435 set position(position) {
436 this._positionIndex = position;
437 this._computePositionAnimationState();
438 }
439 /**
440 * After initialized, check if the content is centered and has an origin. If so, set the
441 * special position states that transition the tab from the left or right before centering.
442 */
443 ngOnInit() {
444 if (this._position == 'center' && this.origin != null) {
445 this._position = this._computePositionFromOrigin(this.origin);
446 }
447 }
448 ngOnDestroy() {
449 this._dirChangeSubscription.unsubscribe();
450 this._translateTabComplete.complete();
451 }
452 _onTranslateTabStarted(event) {
453 const isCentering = this._isCenterPosition(event.toState);
454 this._beforeCentering.emit(isCentering);
455 if (isCentering) {
456 this._onCentering.emit(this._elementRef.nativeElement.clientHeight);
457 }
458 }
459 /** The text direction of the containing app. */
460 _getLayoutDirection() {
461 return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
462 }
463 /** Whether the provided position state is considered center, regardless of origin. */
464 _isCenterPosition(position) {
465 return (position == 'center' || position == 'left-origin-center' || position == 'right-origin-center');
466 }
467 /** Computes the position state that will be used for the tab-body animation trigger. */
468 _computePositionAnimationState(dir = this._getLayoutDirection()) {
469 if (this._positionIndex < 0) {
470 this._position = dir == 'ltr' ? 'left' : 'right';
471 }
472 else if (this._positionIndex > 0) {
473 this._position = dir == 'ltr' ? 'right' : 'left';
474 }
475 else {
476 this._position = 'center';
477 }
478 }
479 /**
480 * Computes the position state based on the specified origin position. This is used if the
481 * tab is becoming visible immediately after creation.
482 */
483 _computePositionFromOrigin(origin) {
484 const dir = this._getLayoutDirection();
485 if ((dir == 'ltr' && origin <= 0) || (dir == 'rtl' && origin > 0)) {
486 return 'left-origin-center';
487 }
488 return 'right-origin-center';
489 }
490}
491_MatTabBodyBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabBodyBase, deps: [{ token: i0.ElementRef }, { token: i1.Directionality, optional: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
492_MatTabBodyBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: _MatTabBodyBase, inputs: { _content: ["content", "_content"], origin: "origin", animationDuration: "animationDuration", preserveContent: "preserveContent", position: "position" }, outputs: { _onCentering: "_onCentering", _beforeCentering: "_beforeCentering", _afterLeavingCenter: "_afterLeavingCenter", _onCentered: "_onCentered" }, ngImport: i0 });
493i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabBodyBase, decorators: [{
494 type: Directive
495 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.Directionality, decorators: [{
496 type: Optional
497 }] }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { _onCentering: [{
498 type: Output
499 }], _beforeCentering: [{
500 type: Output
501 }], _afterLeavingCenter: [{
502 type: Output
503 }], _onCentered: [{
504 type: Output
505 }], _content: [{
506 type: Input,
507 args: ['content']
508 }], origin: [{
509 type: Input
510 }], animationDuration: [{
511 type: Input
512 }], preserveContent: [{
513 type: Input
514 }], position: [{
515 type: Input
516 }] } });
517/**
518 * Wrapper for the contents of a tab.
519 * @docs-private
520 */
521class MatTabBody extends _MatTabBodyBase {
522 constructor(elementRef, dir, changeDetectorRef) {
523 super(elementRef, dir, changeDetectorRef);
524 }
525}
526MatTabBody.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabBody, deps: [{ token: i0.ElementRef }, { token: i1.Directionality, optional: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
527MatTabBody.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatTabBody, selector: "mat-tab-body", host: { classAttribute: "mat-tab-body" }, viewQueries: [{ propertyName: "_portalHost", first: true, predicate: CdkPortalOutlet, descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"mat-tab-body-content\" #content\n [@translateTab]=\"{\n value: _position,\n params: {animationDuration: animationDuration}\n }\"\n (@translateTab.start)=\"_onTranslateTabStarted($event)\"\n (@translateTab.done)=\"_translateTabComplete.next($event)\"\n cdkScrollable>\n <ng-template matTabBodyHost></ng-template>\n</div>\n", styles: [".mat-tab-body-content{height:100%;overflow:auto}.mat-tab-group-dynamic-height .mat-tab-body-content{overflow:hidden}.mat-tab-body-content[style*=\"visibility: hidden\"]{display:none}"], dependencies: [{ kind: "directive", type: MatTabBodyPortal, selector: "[matTabBodyHost]" }], animations: [matTabsAnimations.translateTab], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None });
528i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabBody, decorators: [{
529 type: Component,
530 args: [{ selector: 'mat-tab-body', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.Default, animations: [matTabsAnimations.translateTab], host: {
531 'class': 'mat-tab-body',
532 }, template: "<div class=\"mat-tab-body-content\" #content\n [@translateTab]=\"{\n value: _position,\n params: {animationDuration: animationDuration}\n }\"\n (@translateTab.start)=\"_onTranslateTabStarted($event)\"\n (@translateTab.done)=\"_translateTabComplete.next($event)\"\n cdkScrollable>\n <ng-template matTabBodyHost></ng-template>\n</div>\n", styles: [".mat-tab-body-content{height:100%;overflow:auto}.mat-tab-group-dynamic-height .mat-tab-body-content{overflow:hidden}.mat-tab-body-content[style*=\"visibility: hidden\"]{display:none}"] }]
533 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.Directionality, decorators: [{
534 type: Optional
535 }] }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { _portalHost: [{
536 type: ViewChild,
537 args: [CdkPortalOutlet]
538 }] } });
539
540/**
541 * @license
542 * Copyright Google LLC All Rights Reserved.
543 *
544 * Use of this source code is governed by an MIT-style license that can be
545 * found in the LICENSE file at https://angular.io/license
546 */
547/** Injection token that can be used to provide the default options the tabs module. */
548const MAT_TABS_CONFIG = new InjectionToken('MAT_TABS_CONFIG');
549
550/**
551 * @license
552 * Copyright Google LLC All Rights Reserved.
553 *
554 * Use of this source code is governed by an MIT-style license that can be
555 * found in the LICENSE file at https://angular.io/license
556 */
557// Boilerplate for applying mixins to MatTabLabelWrapper.
558/** @docs-private */
559const _MatTabLabelWrapperBase = mixinDisabled(class {
560});
561/**
562 * Used in the `mat-tab-group` view to display tab labels.
563 * @docs-private
564 */
565class MatTabLabelWrapper extends _MatTabLabelWrapperBase {
566 constructor(elementRef) {
567 super();
568 this.elementRef = elementRef;
569 }
570 /** Sets focus on the wrapper element */
571 focus() {
572 this.elementRef.nativeElement.focus();
573 }
574 getOffsetLeft() {
575 return this.elementRef.nativeElement.offsetLeft;
576 }
577 getOffsetWidth() {
578 return this.elementRef.nativeElement.offsetWidth;
579 }
580}
581MatTabLabelWrapper.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabLabelWrapper, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
582MatTabLabelWrapper.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatTabLabelWrapper, selector: "[matTabLabelWrapper]", inputs: { disabled: "disabled" }, host: { properties: { "class.mat-tab-disabled": "disabled", "attr.aria-disabled": "!!disabled" } }, usesInheritance: true, ngImport: i0 });
583i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabLabelWrapper, decorators: [{
584 type: Directive,
585 args: [{
586 selector: '[matTabLabelWrapper]',
587 inputs: ['disabled'],
588 host: {
589 '[class.mat-tab-disabled]': 'disabled',
590 '[attr.aria-disabled]': '!!disabled',
591 },
592 }]
593 }], ctorParameters: function () { return [{ type: i0.ElementRef }]; } });
594
595/**
596 * @license
597 * Copyright Google LLC All Rights Reserved.
598 *
599 * Use of this source code is governed by an MIT-style license that can be
600 * found in the LICENSE file at https://angular.io/license
601 */
602/** Config used to bind passive event listeners */
603const passiveEventListenerOptions = normalizePassiveListenerOptions({
604 passive: true,
605});
606/**
607 * The distance in pixels that will be overshot when scrolling a tab label into view. This helps
608 * provide a small affordance to the label next to it.
609 */
610const EXAGGERATED_OVERSCROLL = 60;
611/**
612 * Amount of milliseconds to wait before starting to scroll the header automatically.
613 * Set a little conservatively in order to handle fake events dispatched on touch devices.
614 */
615const HEADER_SCROLL_DELAY = 650;
616/**
617 * Interval in milliseconds at which to scroll the header
618 * while the user is holding their pointer.
619 */
620const HEADER_SCROLL_INTERVAL = 100;
621/**
622 * Base class for a tab header that supported pagination.
623 * @docs-private
624 */
625class MatPaginatedTabHeader {
626 constructor(_elementRef, _changeDetectorRef, _viewportRuler, _dir, _ngZone, _platform, _animationMode) {
627 this._elementRef = _elementRef;
628 this._changeDetectorRef = _changeDetectorRef;
629 this._viewportRuler = _viewportRuler;
630 this._dir = _dir;
631 this._ngZone = _ngZone;
632 this._platform = _platform;
633 this._animationMode = _animationMode;
634 /** The distance in pixels that the tab labels should be translated to the left. */
635 this._scrollDistance = 0;
636 /** Whether the header should scroll to the selected index after the view has been checked. */
637 this._selectedIndexChanged = false;
638 /** Emits when the component is destroyed. */
639 this._destroyed = new Subject();
640 /** Whether the controls for pagination should be displayed */
641 this._showPaginationControls = false;
642 /** Whether the tab list can be scrolled more towards the end of the tab label list. */
643 this._disableScrollAfter = true;
644 /** Whether the tab list can be scrolled more towards the beginning of the tab label list. */
645 this._disableScrollBefore = true;
646 /** Stream that will stop the automated scrolling. */
647 this._stopScrolling = new Subject();
648 this._disablePagination = false;
649 this._selectedIndex = 0;
650 /** Event emitted when the option is selected. */
651 this.selectFocusedIndex = new EventEmitter();
652 /** Event emitted when a label is focused. */
653 this.indexFocused = new EventEmitter();
654 // Bind the `mouseleave` event on the outside since it doesn't change anything in the view.
655 _ngZone.runOutsideAngular(() => {
656 fromEvent(_elementRef.nativeElement, 'mouseleave')
657 .pipe(takeUntil(this._destroyed))
658 .subscribe(() => {
659 this._stopInterval();
660 });
661 });
662 }
663 /**
664 * Whether pagination should be disabled. This can be used to avoid unnecessary
665 * layout recalculations if it's known that pagination won't be required.
666 */
667 get disablePagination() {
668 return this._disablePagination;
669 }
670 set disablePagination(value) {
671 this._disablePagination = coerceBooleanProperty(value);
672 }
673 /** The index of the active tab. */
674 get selectedIndex() {
675 return this._selectedIndex;
676 }
677 set selectedIndex(value) {
678 value = coerceNumberProperty(value);
679 if (this._selectedIndex != value) {
680 this._selectedIndexChanged = true;
681 this._selectedIndex = value;
682 if (this._keyManager) {
683 this._keyManager.updateActiveItem(value);
684 }
685 }
686 }
687 ngAfterViewInit() {
688 // We need to handle these events manually, because we want to bind passive event listeners.
689 fromEvent(this._previousPaginator.nativeElement, 'touchstart', passiveEventListenerOptions)
690 .pipe(takeUntil(this._destroyed))
691 .subscribe(() => {
692 this._handlePaginatorPress('before');
693 });
694 fromEvent(this._nextPaginator.nativeElement, 'touchstart', passiveEventListenerOptions)
695 .pipe(takeUntil(this._destroyed))
696 .subscribe(() => {
697 this._handlePaginatorPress('after');
698 });
699 }
700 ngAfterContentInit() {
701 const dirChange = this._dir ? this._dir.change : of('ltr');
702 const resize = this._viewportRuler.change(150);
703 const realign = () => {
704 this.updatePagination();
705 this._alignInkBarToSelectedTab();
706 };
707 this._keyManager = new FocusKeyManager(this._items)
708 .withHorizontalOrientation(this._getLayoutDirection())
709 .withHomeAndEnd()
710 .withWrap();
711 this._keyManager.updateActiveItem(this._selectedIndex);
712 // Defer the first call in order to allow for slower browsers to lay out the elements.
713 // This helps in cases where the user lands directly on a page with paginated tabs.
714 // Note that we use `onStable` instead of `requestAnimationFrame`, because the latter
715 // can hold up tests that are in a background tab.
716 this._ngZone.onStable.pipe(take(1)).subscribe(realign);
717 // On dir change or window resize, realign the ink bar and update the orientation of
718 // the key manager if the direction has changed.
719 merge(dirChange, resize, this._items.changes, this._itemsResized())
720 .pipe(takeUntil(this._destroyed))
721 .subscribe(() => {
722 // We need to defer this to give the browser some time to recalculate
723 // the element dimensions. The call has to be wrapped in `NgZone.run`,
724 // because the viewport change handler runs outside of Angular.
725 this._ngZone.run(() => {
726 Promise.resolve().then(() => {
727 // Clamp the scroll distance, because it can change with the number of tabs.
728 this._scrollDistance = Math.max(0, Math.min(this._getMaxScrollDistance(), this._scrollDistance));
729 realign();
730 });
731 });
732 this._keyManager.withHorizontalOrientation(this._getLayoutDirection());
733 });
734 // If there is a change in the focus key manager we need to emit the `indexFocused`
735 // event in order to provide a public event that notifies about focus changes. Also we realign
736 // the tabs container by scrolling the new focused tab into the visible section.
737 this._keyManager.change.pipe(takeUntil(this._destroyed)).subscribe(newFocusIndex => {
738 this.indexFocused.emit(newFocusIndex);
739 this._setTabFocus(newFocusIndex);
740 });
741 }
742 /** Sends any changes that could affect the layout of the items. */
743 _itemsResized() {
744 if (typeof ResizeObserver !== 'function') {
745 return EMPTY;
746 }
747 return this._items.changes.pipe(startWith(this._items), switchMap((tabItems) => new Observable((observer) => this._ngZone.runOutsideAngular(() => {
748 const resizeObserver = new ResizeObserver(() => {
749 observer.next();
750 });
751 tabItems.forEach(item => {
752 resizeObserver.observe(item.elementRef.nativeElement);
753 });
754 return () => {
755 resizeObserver.disconnect();
756 };
757 }))),
758 // Skip the first emit since the resize observer emits when an item
759 // is observed for new items when the tab is already inserted
760 skip(1));
761 }
762 ngAfterContentChecked() {
763 // If the number of tab labels have changed, check if scrolling should be enabled
764 if (this._tabLabelCount != this._items.length) {
765 this.updatePagination();
766 this._tabLabelCount = this._items.length;
767 this._changeDetectorRef.markForCheck();
768 }
769 // If the selected index has changed, scroll to the label and check if the scrolling controls
770 // should be disabled.
771 if (this._selectedIndexChanged) {
772 this._scrollToLabel(this._selectedIndex);
773 this._checkScrollingControls();
774 this._alignInkBarToSelectedTab();
775 this._selectedIndexChanged = false;
776 this._changeDetectorRef.markForCheck();
777 }
778 // If the scroll distance has been changed (tab selected, focused, scroll controls activated),
779 // then translate the header to reflect this.
780 if (this._scrollDistanceChanged) {
781 this._updateTabScrollPosition();
782 this._scrollDistanceChanged = false;
783 this._changeDetectorRef.markForCheck();
784 }
785 }
786 ngOnDestroy() {
787 this._destroyed.next();
788 this._destroyed.complete();
789 this._stopScrolling.complete();
790 }
791 /** Handles keyboard events on the header. */
792 _handleKeydown(event) {
793 // We don't handle any key bindings with a modifier key.
794 if (hasModifierKey(event)) {
795 return;
796 }
797 switch (event.keyCode) {
798 case ENTER:
799 case SPACE:
800 if (this.focusIndex !== this.selectedIndex) {
801 this.selectFocusedIndex.emit(this.focusIndex);
802 this._itemSelected(event);
803 }
804 break;
805 default:
806 this._keyManager.onKeydown(event);
807 }
808 }
809 /**
810 * Callback for when the MutationObserver detects that the content has changed.
811 */
812 _onContentChanges() {
813 const textContent = this._elementRef.nativeElement.textContent;
814 // We need to diff the text content of the header, because the MutationObserver callback
815 // will fire even if the text content didn't change which is inefficient and is prone
816 // to infinite loops if a poorly constructed expression is passed in (see #14249).
817 if (textContent !== this._currentTextContent) {
818 this._currentTextContent = textContent || '';
819 // The content observer runs outside the `NgZone` by default, which
820 // means that we need to bring the callback back in ourselves.
821 this._ngZone.run(() => {
822 this.updatePagination();
823 this._alignInkBarToSelectedTab();
824 this._changeDetectorRef.markForCheck();
825 });
826 }
827 }
828 /**
829 * Updates the view whether pagination should be enabled or not.
830 *
831 * WARNING: Calling this method can be very costly in terms of performance. It should be called
832 * as infrequently as possible from outside of the Tabs component as it causes a reflow of the
833 * page.
834 */
835 updatePagination() {
836 this._checkPaginationEnabled();
837 this._checkScrollingControls();
838 this._updateTabScrollPosition();
839 }
840 /** Tracks which element has focus; used for keyboard navigation */
841 get focusIndex() {
842 return this._keyManager ? this._keyManager.activeItemIndex : 0;
843 }
844 /** When the focus index is set, we must manually send focus to the correct label */
845 set focusIndex(value) {
846 if (!this._isValidIndex(value) || this.focusIndex === value || !this._keyManager) {
847 return;
848 }
849 this._keyManager.setActiveItem(value);
850 }
851 /**
852 * Determines if an index is valid. If the tabs are not ready yet, we assume that the user is
853 * providing a valid index and return true.
854 */
855 _isValidIndex(index) {
856 if (!this._items) {
857 return true;
858 }
859 const tab = this._items ? this._items.toArray()[index] : null;
860 return !!tab && !tab.disabled;
861 }
862 /**
863 * Sets focus on the HTML element for the label wrapper and scrolls it into the view if
864 * scrolling is enabled.
865 */
866 _setTabFocus(tabIndex) {
867 if (this._showPaginationControls) {
868 this._scrollToLabel(tabIndex);
869 }
870 if (this._items && this._items.length) {
871 this._items.toArray()[tabIndex].focus();
872 // Do not let the browser manage scrolling to focus the element, this will be handled
873 // by using translation. In LTR, the scroll left should be 0. In RTL, the scroll width
874 // should be the full width minus the offset width.
875 const containerEl = this._tabListContainer.nativeElement;
876 const dir = this._getLayoutDirection();
877 if (dir == 'ltr') {
878 containerEl.scrollLeft = 0;
879 }
880 else {
881 containerEl.scrollLeft = containerEl.scrollWidth - containerEl.offsetWidth;
882 }
883 }
884 }
885 /** The layout direction of the containing app. */
886 _getLayoutDirection() {
887 return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
888 }
889 /** Performs the CSS transformation on the tab list that will cause the list to scroll. */
890 _updateTabScrollPosition() {
891 if (this.disablePagination) {
892 return;
893 }
894 const scrollDistance = this.scrollDistance;
895 const translateX = this._getLayoutDirection() === 'ltr' ? -scrollDistance : scrollDistance;
896 // Don't use `translate3d` here because we don't want to create a new layer. A new layer
897 // seems to cause flickering and overflow in Internet Explorer. For example, the ink bar
898 // and ripples will exceed the boundaries of the visible tab bar.
899 // See: https://github.com/angular/components/issues/10276
900 // We round the `transform` here, because transforms with sub-pixel precision cause some
901 // browsers to blur the content of the element.
902 this._tabList.nativeElement.style.transform = `translateX(${Math.round(translateX)}px)`;
903 // Setting the `transform` on IE will change the scroll offset of the parent, causing the
904 // position to be thrown off in some cases. We have to reset it ourselves to ensure that
905 // it doesn't get thrown off. Note that we scope it only to IE and Edge, because messing
906 // with the scroll position throws off Chrome 71+ in RTL mode (see #14689).
907 if (this._platform.TRIDENT || this._platform.EDGE) {
908 this._tabListContainer.nativeElement.scrollLeft = 0;
909 }
910 }
911 /** Sets the distance in pixels that the tab header should be transformed in the X-axis. */
912 get scrollDistance() {
913 return this._scrollDistance;
914 }
915 set scrollDistance(value) {
916 this._scrollTo(value);
917 }
918 /**
919 * Moves the tab list in the 'before' or 'after' direction (towards the beginning of the list or
920 * the end of the list, respectively). The distance to scroll is computed to be a third of the
921 * length of the tab list view window.
922 *
923 * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
924 * should be called sparingly.
925 */
926 _scrollHeader(direction) {
927 const viewLength = this._tabListContainer.nativeElement.offsetWidth;
928 // Move the scroll distance one-third the length of the tab list's viewport.
929 const scrollAmount = ((direction == 'before' ? -1 : 1) * viewLength) / 3;
930 return this._scrollTo(this._scrollDistance + scrollAmount);
931 }
932 /** Handles click events on the pagination arrows. */
933 _handlePaginatorClick(direction) {
934 this._stopInterval();
935 this._scrollHeader(direction);
936 }
937 /**
938 * Moves the tab list such that the desired tab label (marked by index) is moved into view.
939 *
940 * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
941 * should be called sparingly.
942 */
943 _scrollToLabel(labelIndex) {
944 if (this.disablePagination) {
945 return;
946 }
947 const selectedLabel = this._items ? this._items.toArray()[labelIndex] : null;
948 if (!selectedLabel) {
949 return;
950 }
951 // The view length is the visible width of the tab labels.
952 const viewLength = this._tabListContainer.nativeElement.offsetWidth;
953 const { offsetLeft, offsetWidth } = selectedLabel.elementRef.nativeElement;
954 let labelBeforePos, labelAfterPos;
955 if (this._getLayoutDirection() == 'ltr') {
956 labelBeforePos = offsetLeft;
957 labelAfterPos = labelBeforePos + offsetWidth;
958 }
959 else {
960 labelAfterPos = this._tabListInner.nativeElement.offsetWidth - offsetLeft;
961 labelBeforePos = labelAfterPos - offsetWidth;
962 }
963 const beforeVisiblePos = this.scrollDistance;
964 const afterVisiblePos = this.scrollDistance + viewLength;
965 if (labelBeforePos < beforeVisiblePos) {
966 // Scroll header to move label to the before direction
967 this.scrollDistance -= beforeVisiblePos - labelBeforePos + EXAGGERATED_OVERSCROLL;
968 }
969 else if (labelAfterPos > afterVisiblePos) {
970 // Scroll header to move label to the after direction
971 this.scrollDistance += labelAfterPos - afterVisiblePos + EXAGGERATED_OVERSCROLL;
972 }
973 }
974 /**
975 * Evaluate whether the pagination controls should be displayed. If the scroll width of the
976 * tab list is wider than the size of the header container, then the pagination controls should
977 * be shown.
978 *
979 * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
980 * should be called sparingly.
981 */
982 _checkPaginationEnabled() {
983 if (this.disablePagination) {
984 this._showPaginationControls = false;
985 }
986 else {
987 const isEnabled = this._tabListInner.nativeElement.scrollWidth > this._elementRef.nativeElement.offsetWidth;
988 if (!isEnabled) {
989 this.scrollDistance = 0;
990 }
991 if (isEnabled !== this._showPaginationControls) {
992 this._changeDetectorRef.markForCheck();
993 }
994 this._showPaginationControls = isEnabled;
995 }
996 }
997 /**
998 * Evaluate whether the before and after controls should be enabled or disabled.
999 * If the header is at the beginning of the list (scroll distance is equal to 0) then disable the
1000 * before button. If the header is at the end of the list (scroll distance is equal to the
1001 * maximum distance we can scroll), then disable the after button.
1002 *
1003 * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
1004 * should be called sparingly.
1005 */
1006 _checkScrollingControls() {
1007 if (this.disablePagination) {
1008 this._disableScrollAfter = this._disableScrollBefore = true;
1009 }
1010 else {
1011 // Check if the pagination arrows should be activated.
1012 this._disableScrollBefore = this.scrollDistance == 0;
1013 this._disableScrollAfter = this.scrollDistance == this._getMaxScrollDistance();
1014 this._changeDetectorRef.markForCheck();
1015 }
1016 }
1017 /**
1018 * Determines what is the maximum length in pixels that can be set for the scroll distance. This
1019 * is equal to the difference in width between the tab list container and tab header container.
1020 *
1021 * This is an expensive call that forces a layout reflow to compute box and scroll metrics and
1022 * should be called sparingly.
1023 */
1024 _getMaxScrollDistance() {
1025 const lengthOfTabList = this._tabListInner.nativeElement.scrollWidth;
1026 const viewLength = this._tabListContainer.nativeElement.offsetWidth;
1027 return lengthOfTabList - viewLength || 0;
1028 }
1029 /** Tells the ink-bar to align itself to the current label wrapper */
1030 _alignInkBarToSelectedTab() {
1031 const selectedItem = this._items && this._items.length ? this._items.toArray()[this.selectedIndex] : null;
1032 const selectedLabelWrapper = selectedItem ? selectedItem.elementRef.nativeElement : null;
1033 if (selectedLabelWrapper) {
1034 this._inkBar.alignToElement(selectedLabelWrapper);
1035 }
1036 else {
1037 this._inkBar.hide();
1038 }
1039 }
1040 /** Stops the currently-running paginator interval. */
1041 _stopInterval() {
1042 this._stopScrolling.next();
1043 }
1044 /**
1045 * Handles the user pressing down on one of the paginators.
1046 * Starts scrolling the header after a certain amount of time.
1047 * @param direction In which direction the paginator should be scrolled.
1048 */
1049 _handlePaginatorPress(direction, mouseEvent) {
1050 // Don't start auto scrolling for right mouse button clicks. Note that we shouldn't have to
1051 // null check the `button`, but we do it so we don't break tests that use fake events.
1052 if (mouseEvent && mouseEvent.button != null && mouseEvent.button !== 0) {
1053 return;
1054 }
1055 // Avoid overlapping timers.
1056 this._stopInterval();
1057 // Start a timer after the delay and keep firing based on the interval.
1058 timer(HEADER_SCROLL_DELAY, HEADER_SCROLL_INTERVAL)
1059 // Keep the timer going until something tells it to stop or the component is destroyed.
1060 .pipe(takeUntil(merge(this._stopScrolling, this._destroyed)))
1061 .subscribe(() => {
1062 const { maxScrollDistance, distance } = this._scrollHeader(direction);
1063 // Stop the timer if we've reached the start or the end.
1064 if (distance === 0 || distance >= maxScrollDistance) {
1065 this._stopInterval();
1066 }
1067 });
1068 }
1069 /**
1070 * Scrolls the header to a given position.
1071 * @param position Position to which to scroll.
1072 * @returns Information on the current scroll distance and the maximum.
1073 */
1074 _scrollTo(position) {
1075 if (this.disablePagination) {
1076 return { maxScrollDistance: 0, distance: 0 };
1077 }
1078 const maxScrollDistance = this._getMaxScrollDistance();
1079 this._scrollDistance = Math.max(0, Math.min(maxScrollDistance, position));
1080 // Mark that the scroll distance has changed so that after the view is checked, the CSS
1081 // transformation can move the header.
1082 this._scrollDistanceChanged = true;
1083 this._checkScrollingControls();
1084 return { maxScrollDistance, distance: this._scrollDistance };
1085 }
1086}
1087MatPaginatedTabHeader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatPaginatedTabHeader, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i1$1.ViewportRuler }, { token: i1.Directionality, optional: true }, { token: i0.NgZone }, { token: i3.Platform }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1088MatPaginatedTabHeader.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatPaginatedTabHeader, inputs: { disablePagination: "disablePagination" }, ngImport: i0 });
1089i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatPaginatedTabHeader, decorators: [{
1090 type: Directive
1091 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i1$1.ViewportRuler }, { type: i1.Directionality, decorators: [{
1092 type: Optional
1093 }] }, { type: i0.NgZone }, { type: i3.Platform }, { type: undefined, decorators: [{
1094 type: Optional
1095 }, {
1096 type: Inject,
1097 args: [ANIMATION_MODULE_TYPE]
1098 }] }]; }, propDecorators: { disablePagination: [{
1099 type: Input
1100 }] } });
1101
1102/**
1103 * @license
1104 * Copyright Google LLC All Rights Reserved.
1105 *
1106 * Use of this source code is governed by an MIT-style license that can be
1107 * found in the LICENSE file at https://angular.io/license
1108 */
1109/**
1110 * Base class with all of the `MatTabHeader` functionality.
1111 * @docs-private
1112 */
1113class _MatTabHeaderBase extends MatPaginatedTabHeader {
1114 constructor(elementRef, changeDetectorRef, viewportRuler, dir, ngZone, platform, animationMode) {
1115 super(elementRef, changeDetectorRef, viewportRuler, dir, ngZone, platform, animationMode);
1116 this._disableRipple = false;
1117 }
1118 /** Whether the ripple effect is disabled or not. */
1119 get disableRipple() {
1120 return this._disableRipple;
1121 }
1122 set disableRipple(value) {
1123 this._disableRipple = coerceBooleanProperty(value);
1124 }
1125 _itemSelected(event) {
1126 event.preventDefault();
1127 }
1128}
1129_MatTabHeaderBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabHeaderBase, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i1$1.ViewportRuler }, { token: i1.Directionality, optional: true }, { token: i0.NgZone }, { token: i3.Platform }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1130_MatTabHeaderBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: _MatTabHeaderBase, inputs: { disableRipple: "disableRipple" }, usesInheritance: true, ngImport: i0 });
1131i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabHeaderBase, decorators: [{
1132 type: Directive
1133 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i1$1.ViewportRuler }, { type: i1.Directionality, decorators: [{
1134 type: Optional
1135 }] }, { type: i0.NgZone }, { type: i3.Platform }, { type: undefined, decorators: [{
1136 type: Optional
1137 }, {
1138 type: Inject,
1139 args: [ANIMATION_MODULE_TYPE]
1140 }] }]; }, propDecorators: { disableRipple: [{
1141 type: Input
1142 }] } });
1143/**
1144 * The header of the tab group which displays a list of all the tabs in the tab group. Includes
1145 * an ink bar that follows the currently selected tab. When the tabs list's width exceeds the
1146 * width of the header container, then arrows will be displayed to allow the user to scroll
1147 * left and right across the header.
1148 * @docs-private
1149 */
1150class MatTabHeader extends _MatTabHeaderBase {
1151 constructor(elementRef, changeDetectorRef, viewportRuler, dir, ngZone, platform, animationMode) {
1152 super(elementRef, changeDetectorRef, viewportRuler, dir, ngZone, platform, animationMode);
1153 }
1154}
1155MatTabHeader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabHeader, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i1$1.ViewportRuler }, { token: i1.Directionality, optional: true }, { token: i0.NgZone }, { token: i3.Platform }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1156MatTabHeader.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatTabHeader, selector: "mat-tab-header", inputs: { selectedIndex: "selectedIndex" }, outputs: { selectFocusedIndex: "selectFocusedIndex", indexFocused: "indexFocused" }, host: { properties: { "class.mat-tab-header-pagination-controls-enabled": "_showPaginationControls", "class.mat-tab-header-rtl": "_getLayoutDirection() == 'rtl'" }, classAttribute: "mat-tab-header" }, queries: [{ propertyName: "_items", predicate: MatTabLabelWrapper }], viewQueries: [{ propertyName: "_inkBar", first: true, predicate: MatInkBar, descendants: true, static: true }, { propertyName: "_tabListContainer", first: true, predicate: ["tabListContainer"], descendants: true, static: true }, { propertyName: "_tabList", first: true, predicate: ["tabList"], descendants: true, static: true }, { propertyName: "_tabListInner", first: true, predicate: ["tabListInner"], descendants: true, static: true }, { propertyName: "_nextPaginator", first: true, predicate: ["nextPaginator"], descendants: true }, { propertyName: "_previousPaginator", first: true, predicate: ["previousPaginator"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<button class=\"mat-tab-header-pagination mat-tab-header-pagination-before mat-elevation-z4\"\n #previousPaginator\n aria-hidden=\"true\"\n type=\"button\"\n mat-ripple\n tabindex=\"-1\"\n [matRippleDisabled]=\"_disableScrollBefore || disableRipple\"\n [class.mat-tab-header-pagination-disabled]=\"_disableScrollBefore\"\n [disabled]=\"_disableScrollBefore || null\"\n (click)=\"_handlePaginatorClick('before')\"\n (mousedown)=\"_handlePaginatorPress('before', $event)\"\n (touchend)=\"_stopInterval()\">\n <div class=\"mat-tab-header-pagination-chevron\"></div>\n</button>\n\n<div class=\"mat-tab-label-container\" #tabListContainer (keydown)=\"_handleKeydown($event)\">\n <div\n #tabList\n class=\"mat-tab-list\"\n [class._mat-animation-noopable]=\"_animationMode === 'NoopAnimations'\"\n role=\"tablist\"\n (cdkObserveContent)=\"_onContentChanges()\">\n <div class=\"mat-tab-labels\" #tabListInner>\n <ng-content></ng-content>\n </div>\n <mat-ink-bar></mat-ink-bar>\n </div>\n</div>\n\n<button class=\"mat-tab-header-pagination mat-tab-header-pagination-after mat-elevation-z4\"\n #nextPaginator\n aria-hidden=\"true\"\n type=\"button\"\n mat-ripple\n [matRippleDisabled]=\"_disableScrollAfter || disableRipple\"\n [class.mat-tab-header-pagination-disabled]=\"_disableScrollAfter\"\n [disabled]=\"_disableScrollAfter || null\"\n tabindex=\"-1\"\n (mousedown)=\"_handlePaginatorPress('after', $event)\"\n (click)=\"_handlePaginatorClick('after')\"\n (touchend)=\"_stopInterval()\">\n <div class=\"mat-tab-header-pagination-chevron\"></div>\n</button>\n", styles: [".mat-tab-header{display:flex;overflow:hidden;position:relative;flex-shrink:0}.mat-tab-header-pagination{-webkit-user-select:none;user-select:none;position:relative;display:none;justify-content:center;align-items:center;min-width:32px;cursor:pointer;z-index:2;-webkit-tap-highlight-color:rgba(0,0,0,0);touch-action:none;box-sizing:content-box;background:none;border:none;outline:0;padding:0}.mat-tab-header-pagination::-moz-focus-inner{border:0}.mat-tab-header-pagination-controls-enabled .mat-tab-header-pagination{display:flex}.mat-tab-header-pagination-before,.mat-tab-header-rtl .mat-tab-header-pagination-after{padding-left:4px}.mat-tab-header-pagination-before .mat-tab-header-pagination-chevron,.mat-tab-header-rtl .mat-tab-header-pagination-after .mat-tab-header-pagination-chevron{transform:rotate(-135deg)}.mat-tab-header-rtl .mat-tab-header-pagination-before,.mat-tab-header-pagination-after{padding-right:4px}.mat-tab-header-rtl .mat-tab-header-pagination-before .mat-tab-header-pagination-chevron,.mat-tab-header-pagination-after .mat-tab-header-pagination-chevron{transform:rotate(45deg)}.mat-tab-header-pagination-chevron{border-style:solid;border-width:2px 2px 0 0;height:8px;width:8px}.mat-tab-header-pagination-disabled{box-shadow:none;cursor:default}.mat-tab-list{flex-grow:1;position:relative;transition:transform 500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-ink-bar{position:absolute;bottom:0;height:2px;transition:500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-ink-bar._mat-animation-noopable{transition:none !important;animation:none !important}.mat-tab-group-inverted-header .mat-ink-bar{bottom:auto;top:0}.cdk-high-contrast-active .mat-ink-bar{outline:solid 2px;height:0}.mat-tab-labels{display:flex}[mat-align-tabs=center]>.mat-tab-header .mat-tab-labels{justify-content:center}[mat-align-tabs=end]>.mat-tab-header .mat-tab-labels{justify-content:flex-end}.mat-tab-label-container{display:flex;flex-grow:1;overflow:hidden;z-index:1}.mat-tab-list._mat-animation-noopable{transition:none !important;animation:none !important}.mat-tab-label{height:48px;padding:0 24px;cursor:pointer;box-sizing:border-box;opacity:.6;min-width:160px;text-align:center;display:inline-flex;justify-content:center;align-items:center;white-space:nowrap;position:relative}.mat-tab-label:focus{outline:none}.mat-tab-label:focus:not(.mat-tab-disabled){opacity:1}.cdk-high-contrast-active .mat-tab-label:focus{outline:dotted 2px;outline-offset:-2px}.mat-tab-label.mat-tab-disabled{cursor:default}.cdk-high-contrast-active .mat-tab-label.mat-tab-disabled{opacity:.5}.mat-tab-label .mat-tab-label-content{display:inline-flex;justify-content:center;align-items:center;white-space:nowrap}.cdk-high-contrast-active .mat-tab-label{opacity:1}@media(max-width: 599px){.mat-tab-label{min-width:72px}}"], dependencies: [{ kind: "directive", type: i4.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "directive", type: i5.CdkObserveContent, selector: "[cdkObserveContent]", inputs: ["cdkObserveContentDisabled", "debounce"], outputs: ["cdkObserveContent"], exportAs: ["cdkObserveContent"] }, { kind: "directive", type: MatInkBar, selector: "mat-ink-bar" }], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None });
1157i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabHeader, decorators: [{
1158 type: Component,
1159 args: [{ selector: 'mat-tab-header', inputs: ['selectedIndex'], outputs: ['selectFocusedIndex', 'indexFocused'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.Default, host: {
1160 'class': 'mat-tab-header',
1161 '[class.mat-tab-header-pagination-controls-enabled]': '_showPaginationControls',
1162 '[class.mat-tab-header-rtl]': "_getLayoutDirection() == 'rtl'",
1163 }, template: "<button class=\"mat-tab-header-pagination mat-tab-header-pagination-before mat-elevation-z4\"\n #previousPaginator\n aria-hidden=\"true\"\n type=\"button\"\n mat-ripple\n tabindex=\"-1\"\n [matRippleDisabled]=\"_disableScrollBefore || disableRipple\"\n [class.mat-tab-header-pagination-disabled]=\"_disableScrollBefore\"\n [disabled]=\"_disableScrollBefore || null\"\n (click)=\"_handlePaginatorClick('before')\"\n (mousedown)=\"_handlePaginatorPress('before', $event)\"\n (touchend)=\"_stopInterval()\">\n <div class=\"mat-tab-header-pagination-chevron\"></div>\n</button>\n\n<div class=\"mat-tab-label-container\" #tabListContainer (keydown)=\"_handleKeydown($event)\">\n <div\n #tabList\n class=\"mat-tab-list\"\n [class._mat-animation-noopable]=\"_animationMode === 'NoopAnimations'\"\n role=\"tablist\"\n (cdkObserveContent)=\"_onContentChanges()\">\n <div class=\"mat-tab-labels\" #tabListInner>\n <ng-content></ng-content>\n </div>\n <mat-ink-bar></mat-ink-bar>\n </div>\n</div>\n\n<button class=\"mat-tab-header-pagination mat-tab-header-pagination-after mat-elevation-z4\"\n #nextPaginator\n aria-hidden=\"true\"\n type=\"button\"\n mat-ripple\n [matRippleDisabled]=\"_disableScrollAfter || disableRipple\"\n [class.mat-tab-header-pagination-disabled]=\"_disableScrollAfter\"\n [disabled]=\"_disableScrollAfter || null\"\n tabindex=\"-1\"\n (mousedown)=\"_handlePaginatorPress('after', $event)\"\n (click)=\"_handlePaginatorClick('after')\"\n (touchend)=\"_stopInterval()\">\n <div class=\"mat-tab-header-pagination-chevron\"></div>\n</button>\n", styles: [".mat-tab-header{display:flex;overflow:hidden;position:relative;flex-shrink:0}.mat-tab-header-pagination{-webkit-user-select:none;user-select:none;position:relative;display:none;justify-content:center;align-items:center;min-width:32px;cursor:pointer;z-index:2;-webkit-tap-highlight-color:rgba(0,0,0,0);touch-action:none;box-sizing:content-box;background:none;border:none;outline:0;padding:0}.mat-tab-header-pagination::-moz-focus-inner{border:0}.mat-tab-header-pagination-controls-enabled .mat-tab-header-pagination{display:flex}.mat-tab-header-pagination-before,.mat-tab-header-rtl .mat-tab-header-pagination-after{padding-left:4px}.mat-tab-header-pagination-before .mat-tab-header-pagination-chevron,.mat-tab-header-rtl .mat-tab-header-pagination-after .mat-tab-header-pagination-chevron{transform:rotate(-135deg)}.mat-tab-header-rtl .mat-tab-header-pagination-before,.mat-tab-header-pagination-after{padding-right:4px}.mat-tab-header-rtl .mat-tab-header-pagination-before .mat-tab-header-pagination-chevron,.mat-tab-header-pagination-after .mat-tab-header-pagination-chevron{transform:rotate(45deg)}.mat-tab-header-pagination-chevron{border-style:solid;border-width:2px 2px 0 0;height:8px;width:8px}.mat-tab-header-pagination-disabled{box-shadow:none;cursor:default}.mat-tab-list{flex-grow:1;position:relative;transition:transform 500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-ink-bar{position:absolute;bottom:0;height:2px;transition:500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-ink-bar._mat-animation-noopable{transition:none !important;animation:none !important}.mat-tab-group-inverted-header .mat-ink-bar{bottom:auto;top:0}.cdk-high-contrast-active .mat-ink-bar{outline:solid 2px;height:0}.mat-tab-labels{display:flex}[mat-align-tabs=center]>.mat-tab-header .mat-tab-labels{justify-content:center}[mat-align-tabs=end]>.mat-tab-header .mat-tab-labels{justify-content:flex-end}.mat-tab-label-container{display:flex;flex-grow:1;overflow:hidden;z-index:1}.mat-tab-list._mat-animation-noopable{transition:none !important;animation:none !important}.mat-tab-label{height:48px;padding:0 24px;cursor:pointer;box-sizing:border-box;opacity:.6;min-width:160px;text-align:center;display:inline-flex;justify-content:center;align-items:center;white-space:nowrap;position:relative}.mat-tab-label:focus{outline:none}.mat-tab-label:focus:not(.mat-tab-disabled){opacity:1}.cdk-high-contrast-active .mat-tab-label:focus{outline:dotted 2px;outline-offset:-2px}.mat-tab-label.mat-tab-disabled{cursor:default}.cdk-high-contrast-active .mat-tab-label.mat-tab-disabled{opacity:.5}.mat-tab-label .mat-tab-label-content{display:inline-flex;justify-content:center;align-items:center;white-space:nowrap}.cdk-high-contrast-active .mat-tab-label{opacity:1}@media(max-width: 599px){.mat-tab-label{min-width:72px}}"] }]
1164 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i1$1.ViewportRuler }, { type: i1.Directionality, decorators: [{
1165 type: Optional
1166 }] }, { type: i0.NgZone }, { type: i3.Platform }, { type: undefined, decorators: [{
1167 type: Optional
1168 }, {
1169 type: Inject,
1170 args: [ANIMATION_MODULE_TYPE]
1171 }] }]; }, propDecorators: { _items: [{
1172 type: ContentChildren,
1173 args: [MatTabLabelWrapper, { descendants: false }]
1174 }], _inkBar: [{
1175 type: ViewChild,
1176 args: [MatInkBar, { static: true }]
1177 }], _tabListContainer: [{
1178 type: ViewChild,
1179 args: ['tabListContainer', { static: true }]
1180 }], _tabList: [{
1181 type: ViewChild,
1182 args: ['tabList', { static: true }]
1183 }], _tabListInner: [{
1184 type: ViewChild,
1185 args: ['tabListInner', { static: true }]
1186 }], _nextPaginator: [{
1187 type: ViewChild,
1188 args: ['nextPaginator']
1189 }], _previousPaginator: [{
1190 type: ViewChild,
1191 args: ['previousPaginator']
1192 }] } });
1193
1194/**
1195 * @license
1196 * Copyright Google LLC All Rights Reserved.
1197 *
1198 * Use of this source code is governed by an MIT-style license that can be
1199 * found in the LICENSE file at https://angular.io/license
1200 */
1201/** Used to generate unique ID's for each tab component */
1202let nextId = 0;
1203/** A simple change event emitted on focus or selection changes. */
1204class MatTabChangeEvent {
1205}
1206// Boilerplate for applying mixins to MatTabGroup.
1207/** @docs-private */
1208const _MatTabGroupMixinBase = mixinColor(mixinDisableRipple(class {
1209 constructor(_elementRef) {
1210 this._elementRef = _elementRef;
1211 }
1212}), 'primary');
1213/**
1214 * Base class with all of the `MatTabGroupBase` functionality.
1215 * @docs-private
1216 */
1217class _MatTabGroupBase extends _MatTabGroupMixinBase {
1218 constructor(elementRef, _changeDetectorRef, defaultConfig, _animationMode) {
1219 super(elementRef);
1220 this._changeDetectorRef = _changeDetectorRef;
1221 this._animationMode = _animationMode;
1222 /** All of the tabs that belong to the group. */
1223 this._tabs = new QueryList();
1224 /** The tab index that should be selected after the content has been checked. */
1225 this._indexToSelect = 0;
1226 /** Index of the tab that was focused last. */
1227 this._lastFocusedTabIndex = null;
1228 /** Snapshot of the height of the tab body wrapper before another tab is activated. */
1229 this._tabBodyWrapperHeight = 0;
1230 /** Subscription to tabs being added/removed. */
1231 this._tabsSubscription = Subscription.EMPTY;
1232 /** Subscription to changes in the tab labels. */
1233 this._tabLabelSubscription = Subscription.EMPTY;
1234 this._dynamicHeight = false;
1235 this._selectedIndex = null;
1236 /** Position of the tab header. */
1237 this.headerPosition = 'above';
1238 this._disablePagination = false;
1239 this._preserveContent = false;
1240 /** Output to enable support for two-way binding on `[(selectedIndex)]` */
1241 this.selectedIndexChange = new EventEmitter();
1242 /** Event emitted when focus has changed within a tab group. */
1243 this.focusChange = new EventEmitter();
1244 /** Event emitted when the body animation has completed */
1245 this.animationDone = new EventEmitter();
1246 /** Event emitted when the tab selection has changed. */
1247 this.selectedTabChange = new EventEmitter(true);
1248 this._groupId = nextId++;
1249 this.animationDuration =
1250 defaultConfig && defaultConfig.animationDuration ? defaultConfig.animationDuration : '500ms';
1251 this.disablePagination =
1252 defaultConfig && defaultConfig.disablePagination != null
1253 ? defaultConfig.disablePagination
1254 : false;
1255 this.dynamicHeight =
1256 defaultConfig && defaultConfig.dynamicHeight != null ? defaultConfig.dynamicHeight : false;
1257 this.contentTabIndex = defaultConfig?.contentTabIndex ?? null;
1258 this.preserveContent = !!defaultConfig?.preserveContent;
1259 }
1260 /** Whether the tab group should grow to the size of the active tab. */
1261 get dynamicHeight() {
1262 return this._dynamicHeight;
1263 }
1264 set dynamicHeight(value) {
1265 this._dynamicHeight = coerceBooleanProperty(value);
1266 }
1267 /** The index of the active tab. */
1268 get selectedIndex() {
1269 return this._selectedIndex;
1270 }
1271 set selectedIndex(value) {
1272 this._indexToSelect = coerceNumberProperty(value, null);
1273 }
1274 /** Duration for the tab animation. Will be normalized to milliseconds if no units are set. */
1275 get animationDuration() {
1276 return this._animationDuration;
1277 }
1278 set animationDuration(value) {
1279 this._animationDuration = /^\d+$/.test(value + '') ? value + 'ms' : value;
1280 }
1281 /**
1282 * `tabindex` to be set on the inner element that wraps the tab content. Can be used for improved
1283 * accessibility when the tab does not have focusable elements or if it has scrollable content.
1284 * The `tabindex` will be removed automatically for inactive tabs.
1285 * Read more at https://www.w3.org/TR/wai-aria-practices/examples/tabs/tabs-2/tabs.html
1286 */
1287 get contentTabIndex() {
1288 return this._contentTabIndex;
1289 }
1290 set contentTabIndex(value) {
1291 this._contentTabIndex = coerceNumberProperty(value, null);
1292 }
1293 /**
1294 * Whether pagination should be disabled. This can be used to avoid unnecessary
1295 * layout recalculations if it's known that pagination won't be required.
1296 */
1297 get disablePagination() {
1298 return this._disablePagination;
1299 }
1300 set disablePagination(value) {
1301 this._disablePagination = coerceBooleanProperty(value);
1302 }
1303 /**
1304 * By default tabs remove their content from the DOM while it's off-screen.
1305 * Setting this to `true` will keep it in the DOM which will prevent elements
1306 * like iframes and videos from reloading next time it comes back into the view.
1307 */
1308 get preserveContent() {
1309 return this._preserveContent;
1310 }
1311 set preserveContent(value) {
1312 this._preserveContent = coerceBooleanProperty(value);
1313 }
1314 /** Background color of the tab group. */
1315 get backgroundColor() {
1316 return this._backgroundColor;
1317 }
1318 set backgroundColor(value) {
1319 const nativeElement = this._elementRef.nativeElement;
1320 nativeElement.classList.remove(`mat-background-${this.backgroundColor}`);
1321 if (value) {
1322 nativeElement.classList.add(`mat-background-${value}`);
1323 }
1324 this._backgroundColor = value;
1325 }
1326 /**
1327 * After the content is checked, this component knows what tabs have been defined
1328 * and what the selected index should be. This is where we can know exactly what position
1329 * each tab should be in according to the new selected index, and additionally we know how
1330 * a new selected tab should transition in (from the left or right).
1331 */
1332 ngAfterContentChecked() {
1333 // Don't clamp the `indexToSelect` immediately in the setter because it can happen that
1334 // the amount of tabs changes before the actual change detection runs.
1335 const indexToSelect = (this._indexToSelect = this._clampTabIndex(this._indexToSelect));
1336 // If there is a change in selected index, emit a change event. Should not trigger if
1337 // the selected index has not yet been initialized.
1338 if (this._selectedIndex != indexToSelect) {
1339 const isFirstRun = this._selectedIndex == null;
1340 if (!isFirstRun) {
1341 this.selectedTabChange.emit(this._createChangeEvent(indexToSelect));
1342 // Preserve the height so page doesn't scroll up during tab change.
1343 // Fixes https://stackblitz.com/edit/mat-tabs-scroll-page-top-on-tab-change
1344 const wrapper = this._tabBodyWrapper.nativeElement;
1345 wrapper.style.minHeight = wrapper.clientHeight + 'px';
1346 }
1347 // Changing these values after change detection has run
1348 // since the checked content may contain references to them.
1349 Promise.resolve().then(() => {
1350 this._tabs.forEach((tab, index) => (tab.isActive = index === indexToSelect));
1351 if (!isFirstRun) {
1352 this.selectedIndexChange.emit(indexToSelect);
1353 // Clear the min-height, this was needed during tab change to avoid
1354 // unnecessary scrolling.
1355 this._tabBodyWrapper.nativeElement.style.minHeight = '';
1356 }
1357 });
1358 }
1359 // Setup the position for each tab and optionally setup an origin on the next selected tab.
1360 this._tabs.forEach((tab, index) => {
1361 tab.position = index - indexToSelect;
1362 // If there is already a selected tab, then set up an origin for the next selected tab
1363 // if it doesn't have one already.
1364 if (this._selectedIndex != null && tab.position == 0 && !tab.origin) {
1365 tab.origin = indexToSelect - this._selectedIndex;
1366 }
1367 });
1368 if (this._selectedIndex !== indexToSelect) {
1369 this._selectedIndex = indexToSelect;
1370 this._lastFocusedTabIndex = null;
1371 this._changeDetectorRef.markForCheck();
1372 }
1373 }
1374 ngAfterContentInit() {
1375 this._subscribeToAllTabChanges();
1376 this._subscribeToTabLabels();
1377 // Subscribe to changes in the amount of tabs, in order to be
1378 // able to re-render the content as new tabs are added or removed.
1379 this._tabsSubscription = this._tabs.changes.subscribe(() => {
1380 const indexToSelect = this._clampTabIndex(this._indexToSelect);
1381 // Maintain the previously-selected tab if a new tab is added or removed and there is no
1382 // explicit change that selects a different tab.
1383 if (indexToSelect === this._selectedIndex) {
1384 const tabs = this._tabs.toArray();
1385 let selectedTab;
1386 for (let i = 0; i < tabs.length; i++) {
1387 if (tabs[i].isActive) {
1388 // Assign both to the `_indexToSelect` and `_selectedIndex` so we don't fire a changed
1389 // event, otherwise the consumer may end up in an infinite loop in some edge cases like
1390 // adding a tab within the `selectedIndexChange` event.
1391 this._indexToSelect = this._selectedIndex = i;
1392 this._lastFocusedTabIndex = null;
1393 selectedTab = tabs[i];
1394 break;
1395 }
1396 }
1397 // If we haven't found an active tab and a tab exists at the selected index, it means
1398 // that the active tab was swapped out. Since this won't be picked up by the rendering
1399 // loop in `ngAfterContentChecked`, we need to sync it up manually.
1400 if (!selectedTab && tabs[indexToSelect]) {
1401 Promise.resolve().then(() => {
1402 tabs[indexToSelect].isActive = true;
1403 this.selectedTabChange.emit(this._createChangeEvent(indexToSelect));
1404 });
1405 }
1406 }
1407 this._changeDetectorRef.markForCheck();
1408 });
1409 }
1410 /** Listens to changes in all of the tabs. */
1411 _subscribeToAllTabChanges() {
1412 // Since we use a query with `descendants: true` to pick up the tabs, we may end up catching
1413 // some that are inside of nested tab groups. We filter them out manually by checking that
1414 // the closest group to the tab is the current one.
1415 this._allTabs.changes.pipe(startWith(this._allTabs)).subscribe((tabs) => {
1416 this._tabs.reset(tabs.filter(tab => {
1417 return tab._closestTabGroup === this || !tab._closestTabGroup;
1418 }));
1419 this._tabs.notifyOnChanges();
1420 });
1421 }
1422 ngOnDestroy() {
1423 this._tabs.destroy();
1424 this._tabsSubscription.unsubscribe();
1425 this._tabLabelSubscription.unsubscribe();
1426 }
1427 /** Re-aligns the ink bar to the selected tab element. */
1428 realignInkBar() {
1429 if (this._tabHeader) {
1430 this._tabHeader._alignInkBarToSelectedTab();
1431 }
1432 }
1433 /**
1434 * Recalculates the tab group's pagination dimensions.
1435 *
1436 * WARNING: Calling this method can be very costly in terms of performance. It should be called
1437 * as infrequently as possible from outside of the Tabs component as it causes a reflow of the
1438 * page.
1439 */
1440 updatePagination() {
1441 if (this._tabHeader) {
1442 this._tabHeader.updatePagination();
1443 }
1444 }
1445 /**
1446 * Sets focus to a particular tab.
1447 * @param index Index of the tab to be focused.
1448 */
1449 focusTab(index) {
1450 const header = this._tabHeader;
1451 if (header) {
1452 header.focusIndex = index;
1453 }
1454 }
1455 _focusChanged(index) {
1456 this._lastFocusedTabIndex = index;
1457 this.focusChange.emit(this._createChangeEvent(index));
1458 }
1459 _createChangeEvent(index) {
1460 const event = new MatTabChangeEvent();
1461 event.index = index;
1462 if (this._tabs && this._tabs.length) {
1463 event.tab = this._tabs.toArray()[index];
1464 }
1465 return event;
1466 }
1467 /**
1468 * Subscribes to changes in the tab labels. This is needed, because the @Input for the label is
1469 * on the MatTab component, whereas the data binding is inside the MatTabGroup. In order for the
1470 * binding to be updated, we need to subscribe to changes in it and trigger change detection
1471 * manually.
1472 */
1473 _subscribeToTabLabels() {
1474 if (this._tabLabelSubscription) {
1475 this._tabLabelSubscription.unsubscribe();
1476 }
1477 this._tabLabelSubscription = merge(...this._tabs.map(tab => tab._stateChanges)).subscribe(() => this._changeDetectorRef.markForCheck());
1478 }
1479 /** Clamps the given index to the bounds of 0 and the tabs length. */
1480 _clampTabIndex(index) {
1481 // Note the `|| 0`, which ensures that values like NaN can't get through
1482 // and which would otherwise throw the component into an infinite loop
1483 // (since Math.max(NaN, 0) === NaN).
1484 return Math.min(this._tabs.length - 1, Math.max(index || 0, 0));
1485 }
1486 /** Returns a unique id for each tab label element */
1487 _getTabLabelId(i) {
1488 return `mat-tab-label-${this._groupId}-${i}`;
1489 }
1490 /** Returns a unique id for each tab content element */
1491 _getTabContentId(i) {
1492 return `mat-tab-content-${this._groupId}-${i}`;
1493 }
1494 /**
1495 * Sets the height of the body wrapper to the height of the activating tab if dynamic
1496 * height property is true.
1497 */
1498 _setTabBodyWrapperHeight(tabHeight) {
1499 if (!this._dynamicHeight || !this._tabBodyWrapperHeight) {
1500 return;
1501 }
1502 const wrapper = this._tabBodyWrapper.nativeElement;
1503 wrapper.style.height = this._tabBodyWrapperHeight + 'px';
1504 // This conditional forces the browser to paint the height so that
1505 // the animation to the new height can have an origin.
1506 if (this._tabBodyWrapper.nativeElement.offsetHeight) {
1507 wrapper.style.height = tabHeight + 'px';
1508 }
1509 }
1510 /** Removes the height of the tab body wrapper. */
1511 _removeTabBodyWrapperHeight() {
1512 const wrapper = this._tabBodyWrapper.nativeElement;
1513 this._tabBodyWrapperHeight = wrapper.clientHeight;
1514 wrapper.style.height = '';
1515 this.animationDone.emit();
1516 }
1517 /** Handle click events, setting new selected index if appropriate. */
1518 _handleClick(tab, tabHeader, index) {
1519 if (!tab.disabled) {
1520 this.selectedIndex = tabHeader.focusIndex = index;
1521 }
1522 }
1523 /** Retrieves the tabindex for the tab. */
1524 _getTabIndex(tab, index) {
1525 if (tab.disabled) {
1526 return null;
1527 }
1528 const targetIndex = this._lastFocusedTabIndex ?? this.selectedIndex;
1529 return index === targetIndex ? 0 : -1;
1530 }
1531 /** Callback for when the focused state of a tab has changed. */
1532 _tabFocusChanged(focusOrigin, index) {
1533 // Mouse/touch focus happens during the `mousedown`/`touchstart` phase which
1534 // can cause the tab to be moved out from under the pointer, interrupting the
1535 // click sequence (see #21898). We don't need to scroll the tab into view for
1536 // such cases anyway, because it will be done when the tab becomes selected.
1537 if (focusOrigin && focusOrigin !== 'mouse' && focusOrigin !== 'touch') {
1538 this._tabHeader.focusIndex = index;
1539 }
1540 }
1541}
1542_MatTabGroupBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabGroupBase, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: MAT_TABS_CONFIG, optional: true }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1543_MatTabGroupBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: _MatTabGroupBase, inputs: { dynamicHeight: "dynamicHeight", selectedIndex: "selectedIndex", headerPosition: "headerPosition", animationDuration: "animationDuration", contentTabIndex: "contentTabIndex", disablePagination: "disablePagination", preserveContent: "preserveContent", backgroundColor: "backgroundColor" }, outputs: { selectedIndexChange: "selectedIndexChange", focusChange: "focusChange", animationDone: "animationDone", selectedTabChange: "selectedTabChange" }, usesInheritance: true, ngImport: i0 });
1544i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabGroupBase, decorators: [{
1545 type: Directive
1546 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
1547 type: Inject,
1548 args: [MAT_TABS_CONFIG]
1549 }, {
1550 type: Optional
1551 }] }, { type: undefined, decorators: [{
1552 type: Optional
1553 }, {
1554 type: Inject,
1555 args: [ANIMATION_MODULE_TYPE]
1556 }] }]; }, propDecorators: { dynamicHeight: [{
1557 type: Input
1558 }], selectedIndex: [{
1559 type: Input
1560 }], headerPosition: [{
1561 type: Input
1562 }], animationDuration: [{
1563 type: Input
1564 }], contentTabIndex: [{
1565 type: Input
1566 }], disablePagination: [{
1567 type: Input
1568 }], preserveContent: [{
1569 type: Input
1570 }], backgroundColor: [{
1571 type: Input
1572 }], selectedIndexChange: [{
1573 type: Output
1574 }], focusChange: [{
1575 type: Output
1576 }], animationDone: [{
1577 type: Output
1578 }], selectedTabChange: [{
1579 type: Output
1580 }] } });
1581/**
1582 * Material design tab-group component. Supports basic tab pairs (label + content) and includes
1583 * animated ink-bar, keyboard navigation, and screen reader.
1584 * See: https://material.io/design/components/tabs.html
1585 */
1586class MatTabGroup extends _MatTabGroupBase {
1587 constructor(elementRef, changeDetectorRef, defaultConfig, animationMode) {
1588 super(elementRef, changeDetectorRef, defaultConfig, animationMode);
1589 }
1590}
1591MatTabGroup.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabGroup, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: MAT_TABS_CONFIG, optional: true }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1592MatTabGroup.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatTabGroup, selector: "mat-tab-group", inputs: { color: "color", disableRipple: "disableRipple" }, host: { properties: { "class.mat-tab-group-dynamic-height": "dynamicHeight", "class.mat-tab-group-inverted-header": "headerPosition === \"below\"" }, classAttribute: "mat-tab-group" }, providers: [
1593 {
1594 provide: MAT_TAB_GROUP,
1595 useExisting: MatTabGroup,
1596 },
1597 ], queries: [{ propertyName: "_allTabs", predicate: MatTab, descendants: true }], viewQueries: [{ propertyName: "_tabBodyWrapper", first: true, predicate: ["tabBodyWrapper"], descendants: true }, { propertyName: "_tabHeader", first: true, predicate: ["tabHeader"], descendants: true }], exportAs: ["matTabGroup"], usesInheritance: true, ngImport: i0, template: "<mat-tab-header #tabHeader\n [selectedIndex]=\"selectedIndex || 0\"\n [disableRipple]=\"disableRipple\"\n [disablePagination]=\"disablePagination\"\n (indexFocused)=\"_focusChanged($event)\"\n (selectFocusedIndex)=\"selectedIndex = $event\">\n <div class=\"mat-tab-label mat-focus-indicator\" role=\"tab\" matTabLabelWrapper mat-ripple\n cdkMonitorElementFocus\n *ngFor=\"let tab of _tabs; let i = index\"\n [id]=\"_getTabLabelId(i)\"\n [attr.tabIndex]=\"_getTabIndex(tab, i)\"\n [attr.aria-posinset]=\"i + 1\"\n [attr.aria-setsize]=\"_tabs.length\"\n [attr.aria-controls]=\"_getTabContentId(i)\"\n [attr.aria-selected]=\"selectedIndex === i\"\n [attr.aria-label]=\"tab.ariaLabel || null\"\n [attr.aria-labelledby]=\"(!tab.ariaLabel && tab.ariaLabelledby) ? tab.ariaLabelledby : null\"\n [class.mat-tab-label-active]=\"selectedIndex === i\"\n [ngClass]=\"tab.labelClass\"\n [disabled]=\"tab.disabled\"\n [matRippleDisabled]=\"tab.disabled || disableRipple\"\n (click)=\"_handleClick(tab, tabHeader, i)\"\n (cdkFocusChange)=\"_tabFocusChanged($event, i)\">\n\n\n <div class=\"mat-tab-label-content\">\n <!-- If there is a label template, use it. -->\n <ng-template [ngIf]=\"tab.templateLabel\" [ngIfElse]=\"tabTextLabel\">\n <ng-template [cdkPortalOutlet]=\"tab.templateLabel\"></ng-template>\n </ng-template>\n\n <!-- If there is not a label template, fall back to the text label. -->\n <ng-template #tabTextLabel>{{tab.textLabel}}</ng-template>\n </div>\n </div>\n</mat-tab-header>\n\n<div\n class=\"mat-tab-body-wrapper\"\n [class._mat-animation-noopable]=\"_animationMode === 'NoopAnimations'\"\n #tabBodyWrapper>\n <mat-tab-body role=\"tabpanel\"\n *ngFor=\"let tab of _tabs; let i = index\"\n [id]=\"_getTabContentId(i)\"\n [attr.tabindex]=\"(contentTabIndex != null && selectedIndex === i) ? contentTabIndex : null\"\n [attr.aria-labelledby]=\"_getTabLabelId(i)\"\n [class.mat-tab-body-active]=\"selectedIndex === i\"\n [ngClass]=\"tab.bodyClass\"\n [content]=\"tab.content!\"\n [position]=\"tab.position!\"\n [origin]=\"tab.origin\"\n [animationDuration]=\"animationDuration\"\n [preserveContent]=\"preserveContent\"\n (_onCentered)=\"_removeTabBodyWrapperHeight()\"\n (_onCentering)=\"_setTabBodyWrapperHeight($event)\">\n </mat-tab-body>\n</div>\n", styles: [".mat-tab-group{display:flex;flex-direction:column;max-width:100%}.mat-tab-group.mat-tab-group-inverted-header{flex-direction:column-reverse}.mat-tab-label{height:48px;padding:0 24px;cursor:pointer;box-sizing:border-box;opacity:.6;min-width:160px;text-align:center;display:inline-flex;justify-content:center;align-items:center;white-space:nowrap;position:relative}.mat-tab-label:focus{outline:none}.mat-tab-label:focus:not(.mat-tab-disabled){opacity:1}.cdk-high-contrast-active .mat-tab-label:focus{outline:dotted 2px;outline-offset:-2px}.mat-tab-label.mat-tab-disabled{cursor:default}.cdk-high-contrast-active .mat-tab-label.mat-tab-disabled{opacity:.5}.mat-tab-label .mat-tab-label-content{display:inline-flex;justify-content:center;align-items:center;white-space:nowrap}.cdk-high-contrast-active .mat-tab-label{opacity:1}@media(max-width: 599px){.mat-tab-label{padding:0 12px}}@media(max-width: 959px){.mat-tab-label{padding:0 12px}}.mat-tab-group[mat-stretch-tabs]>.mat-tab-header .mat-tab-label{flex-basis:0;flex-grow:1}.mat-tab-body-wrapper{position:relative;overflow:hidden;display:flex;transition:height 500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-tab-body-wrapper._mat-animation-noopable{transition:none !important;animation:none !important}.mat-tab-body{top:0;left:0;right:0;bottom:0;position:absolute;display:block;overflow:hidden;outline:0;flex-basis:100%}.mat-tab-body.mat-tab-body-active{position:relative;overflow-x:hidden;overflow-y:auto;z-index:1;flex-grow:1}.mat-tab-group.mat-tab-group-dynamic-height .mat-tab-body.mat-tab-body-active{overflow-y:hidden}"], dependencies: [{ kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "directive", type: i4.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "directive", type: i7.CdkMonitorFocus, selector: "[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]", outputs: ["cdkFocusChange"] }, { kind: "directive", type: MatTabLabelWrapper, selector: "[matTabLabelWrapper]", inputs: ["disabled"] }, { kind: "component", type: MatTabBody, selector: "mat-tab-body" }, { kind: "component", type: MatTabHeader, selector: "mat-tab-header", inputs: ["selectedIndex"], outputs: ["selectFocusedIndex", "indexFocused"] }], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None });
1598i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabGroup, decorators: [{
1599 type: Component,
1600 args: [{ selector: 'mat-tab-group', exportAs: 'matTabGroup', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.Default, inputs: ['color', 'disableRipple'], providers: [
1601 {
1602 provide: MAT_TAB_GROUP,
1603 useExisting: MatTabGroup,
1604 },
1605 ], host: {
1606 'class': 'mat-tab-group',
1607 '[class.mat-tab-group-dynamic-height]': 'dynamicHeight',
1608 '[class.mat-tab-group-inverted-header]': 'headerPosition === "below"',
1609 }, template: "<mat-tab-header #tabHeader\n [selectedIndex]=\"selectedIndex || 0\"\n [disableRipple]=\"disableRipple\"\n [disablePagination]=\"disablePagination\"\n (indexFocused)=\"_focusChanged($event)\"\n (selectFocusedIndex)=\"selectedIndex = $event\">\n <div class=\"mat-tab-label mat-focus-indicator\" role=\"tab\" matTabLabelWrapper mat-ripple\n cdkMonitorElementFocus\n *ngFor=\"let tab of _tabs; let i = index\"\n [id]=\"_getTabLabelId(i)\"\n [attr.tabIndex]=\"_getTabIndex(tab, i)\"\n [attr.aria-posinset]=\"i + 1\"\n [attr.aria-setsize]=\"_tabs.length\"\n [attr.aria-controls]=\"_getTabContentId(i)\"\n [attr.aria-selected]=\"selectedIndex === i\"\n [attr.aria-label]=\"tab.ariaLabel || null\"\n [attr.aria-labelledby]=\"(!tab.ariaLabel && tab.ariaLabelledby) ? tab.ariaLabelledby : null\"\n [class.mat-tab-label-active]=\"selectedIndex === i\"\n [ngClass]=\"tab.labelClass\"\n [disabled]=\"tab.disabled\"\n [matRippleDisabled]=\"tab.disabled || disableRipple\"\n (click)=\"_handleClick(tab, tabHeader, i)\"\n (cdkFocusChange)=\"_tabFocusChanged($event, i)\">\n\n\n <div class=\"mat-tab-label-content\">\n <!-- If there is a label template, use it. -->\n <ng-template [ngIf]=\"tab.templateLabel\" [ngIfElse]=\"tabTextLabel\">\n <ng-template [cdkPortalOutlet]=\"tab.templateLabel\"></ng-template>\n </ng-template>\n\n <!-- If there is not a label template, fall back to the text label. -->\n <ng-template #tabTextLabel>{{tab.textLabel}}</ng-template>\n </div>\n </div>\n</mat-tab-header>\n\n<div\n class=\"mat-tab-body-wrapper\"\n [class._mat-animation-noopable]=\"_animationMode === 'NoopAnimations'\"\n #tabBodyWrapper>\n <mat-tab-body role=\"tabpanel\"\n *ngFor=\"let tab of _tabs; let i = index\"\n [id]=\"_getTabContentId(i)\"\n [attr.tabindex]=\"(contentTabIndex != null && selectedIndex === i) ? contentTabIndex : null\"\n [attr.aria-labelledby]=\"_getTabLabelId(i)\"\n [class.mat-tab-body-active]=\"selectedIndex === i\"\n [ngClass]=\"tab.bodyClass\"\n [content]=\"tab.content!\"\n [position]=\"tab.position!\"\n [origin]=\"tab.origin\"\n [animationDuration]=\"animationDuration\"\n [preserveContent]=\"preserveContent\"\n (_onCentered)=\"_removeTabBodyWrapperHeight()\"\n (_onCentering)=\"_setTabBodyWrapperHeight($event)\">\n </mat-tab-body>\n</div>\n", styles: [".mat-tab-group{display:flex;flex-direction:column;max-width:100%}.mat-tab-group.mat-tab-group-inverted-header{flex-direction:column-reverse}.mat-tab-label{height:48px;padding:0 24px;cursor:pointer;box-sizing:border-box;opacity:.6;min-width:160px;text-align:center;display:inline-flex;justify-content:center;align-items:center;white-space:nowrap;position:relative}.mat-tab-label:focus{outline:none}.mat-tab-label:focus:not(.mat-tab-disabled){opacity:1}.cdk-high-contrast-active .mat-tab-label:focus{outline:dotted 2px;outline-offset:-2px}.mat-tab-label.mat-tab-disabled{cursor:default}.cdk-high-contrast-active .mat-tab-label.mat-tab-disabled{opacity:.5}.mat-tab-label .mat-tab-label-content{display:inline-flex;justify-content:center;align-items:center;white-space:nowrap}.cdk-high-contrast-active .mat-tab-label{opacity:1}@media(max-width: 599px){.mat-tab-label{padding:0 12px}}@media(max-width: 959px){.mat-tab-label{padding:0 12px}}.mat-tab-group[mat-stretch-tabs]>.mat-tab-header .mat-tab-label{flex-basis:0;flex-grow:1}.mat-tab-body-wrapper{position:relative;overflow:hidden;display:flex;transition:height 500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-tab-body-wrapper._mat-animation-noopable{transition:none !important;animation:none !important}.mat-tab-body{top:0;left:0;right:0;bottom:0;position:absolute;display:block;overflow:hidden;outline:0;flex-basis:100%}.mat-tab-body.mat-tab-body-active{position:relative;overflow-x:hidden;overflow-y:auto;z-index:1;flex-grow:1}.mat-tab-group.mat-tab-group-dynamic-height .mat-tab-body.mat-tab-body-active{overflow-y:hidden}"] }]
1610 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
1611 type: Inject,
1612 args: [MAT_TABS_CONFIG]
1613 }, {
1614 type: Optional
1615 }] }, { type: undefined, decorators: [{
1616 type: Optional
1617 }, {
1618 type: Inject,
1619 args: [ANIMATION_MODULE_TYPE]
1620 }] }]; }, propDecorators: { _allTabs: [{
1621 type: ContentChildren,
1622 args: [MatTab, { descendants: true }]
1623 }], _tabBodyWrapper: [{
1624 type: ViewChild,
1625 args: ['tabBodyWrapper']
1626 }], _tabHeader: [{
1627 type: ViewChild,
1628 args: ['tabHeader']
1629 }] } });
1630
1631/**
1632 * @license
1633 * Copyright Google LLC All Rights Reserved.
1634 *
1635 * Use of this source code is governed by an MIT-style license that can be
1636 * found in the LICENSE file at https://angular.io/license
1637 */
1638// Increasing integer for generating unique ids for tab nav components.
1639let nextUniqueId = 0;
1640/**
1641 * Base class with all of the `MatTabNav` functionality.
1642 * @docs-private
1643 */
1644class _MatTabNavBase extends MatPaginatedTabHeader {
1645 constructor(elementRef, dir, ngZone, changeDetectorRef, viewportRuler, platform, animationMode) {
1646 super(elementRef, changeDetectorRef, viewportRuler, dir, ngZone, platform, animationMode);
1647 this._disableRipple = false;
1648 /** Theme color of the nav bar. */
1649 this.color = 'primary';
1650 }
1651 /** Background color of the tab nav. */
1652 get backgroundColor() {
1653 return this._backgroundColor;
1654 }
1655 set backgroundColor(value) {
1656 const classList = this._elementRef.nativeElement.classList;
1657 classList.remove(`mat-background-${this.backgroundColor}`);
1658 if (value) {
1659 classList.add(`mat-background-${value}`);
1660 }
1661 this._backgroundColor = value;
1662 }
1663 /** Whether the ripple effect is disabled or not. */
1664 get disableRipple() {
1665 return this._disableRipple;
1666 }
1667 set disableRipple(value) {
1668 this._disableRipple = coerceBooleanProperty(value);
1669 }
1670 _itemSelected() {
1671 // noop
1672 }
1673 ngAfterContentInit() {
1674 // We need this to run before the `changes` subscription in parent to ensure that the
1675 // selectedIndex is up-to-date by the time the super class starts looking for it.
1676 this._items.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => {
1677 this.updateActiveLink();
1678 });
1679 super.ngAfterContentInit();
1680 }
1681 /** Notifies the component that the active link has been changed. */
1682 updateActiveLink() {
1683 if (!this._items) {
1684 return;
1685 }
1686 const items = this._items.toArray();
1687 for (let i = 0; i < items.length; i++) {
1688 if (items[i].active) {
1689 this.selectedIndex = i;
1690 this._changeDetectorRef.markForCheck();
1691 if (this.tabPanel) {
1692 this.tabPanel._activeTabId = items[i].id;
1693 }
1694 return;
1695 }
1696 }
1697 // The ink bar should hide itself if no items are active.
1698 this.selectedIndex = -1;
1699 this._inkBar.hide();
1700 }
1701 _getRole() {
1702 return this.tabPanel ? 'tablist' : this._elementRef.nativeElement.getAttribute('role');
1703 }
1704}
1705_MatTabNavBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabNavBase, deps: [{ token: i0.ElementRef }, { token: i1.Directionality, optional: true }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: i1$1.ViewportRuler }, { token: i3.Platform }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1706_MatTabNavBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: _MatTabNavBase, inputs: { backgroundColor: "backgroundColor", disableRipple: "disableRipple", color: "color", tabPanel: "tabPanel" }, usesInheritance: true, ngImport: i0 });
1707i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabNavBase, decorators: [{
1708 type: Directive
1709 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.Directionality, decorators: [{
1710 type: Optional
1711 }] }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: i1$1.ViewportRuler }, { type: i3.Platform }, { type: undefined, decorators: [{
1712 type: Optional
1713 }, {
1714 type: Inject,
1715 args: [ANIMATION_MODULE_TYPE]
1716 }] }]; }, propDecorators: { backgroundColor: [{
1717 type: Input
1718 }], disableRipple: [{
1719 type: Input
1720 }], color: [{
1721 type: Input
1722 }], tabPanel: [{
1723 type: Input
1724 }] } });
1725/**
1726 * Navigation component matching the styles of the tab group header.
1727 * Provides anchored navigation with animated ink bar.
1728 */
1729class MatTabNav extends _MatTabNavBase {
1730 constructor(elementRef, dir, ngZone, changeDetectorRef, viewportRuler, platform, animationMode) {
1731 super(elementRef, dir, ngZone, changeDetectorRef, viewportRuler, platform, animationMode);
1732 }
1733}
1734MatTabNav.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabNav, deps: [{ token: i0.ElementRef }, { token: i1.Directionality, optional: true }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: i1$1.ViewportRuler }, { token: i3.Platform }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1735MatTabNav.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatTabNav, selector: "[mat-tab-nav-bar]", inputs: { color: "color" }, host: { properties: { "attr.role": "_getRole()", "class.mat-tab-header-pagination-controls-enabled": "_showPaginationControls", "class.mat-tab-header-rtl": "_getLayoutDirection() == 'rtl'", "class.mat-primary": "color !== \"warn\" && color !== \"accent\"", "class.mat-accent": "color === \"accent\"", "class.mat-warn": "color === \"warn\"" }, classAttribute: "mat-tab-nav-bar mat-tab-header" }, queries: [{ propertyName: "_items", predicate: i0.forwardRef(function () { return MatTabLink; }), descendants: true }], viewQueries: [{ propertyName: "_inkBar", first: true, predicate: MatInkBar, descendants: true, static: true }, { propertyName: "_tabListContainer", first: true, predicate: ["tabListContainer"], descendants: true, static: true }, { propertyName: "_tabList", first: true, predicate: ["tabList"], descendants: true, static: true }, { propertyName: "_tabListInner", first: true, predicate: ["tabListInner"], descendants: true, static: true }, { propertyName: "_nextPaginator", first: true, predicate: ["nextPaginator"], descendants: true }, { propertyName: "_previousPaginator", first: true, predicate: ["previousPaginator"], descendants: true }], exportAs: ["matTabNavBar", "matTabNav"], usesInheritance: true, ngImport: i0, template: "<button class=\"mat-tab-header-pagination mat-tab-header-pagination-before mat-elevation-z4\"\n #previousPaginator\n aria-hidden=\"true\"\n type=\"button\"\n mat-ripple\n tabindex=\"-1\"\n [matRippleDisabled]=\"_disableScrollBefore || disableRipple\"\n [class.mat-tab-header-pagination-disabled]=\"_disableScrollBefore\"\n [disabled]=\"_disableScrollBefore || null\"\n (click)=\"_handlePaginatorClick('before')\"\n (mousedown)=\"_handlePaginatorPress('before', $event)\"\n (touchend)=\"_stopInterval()\">\n <div class=\"mat-tab-header-pagination-chevron\"></div>\n</button>\n\n<div class=\"mat-tab-link-container\" #tabListContainer (keydown)=\"_handleKeydown($event)\">\n <div\n class=\"mat-tab-list\"\n [class._mat-animation-noopable]=\"_animationMode === 'NoopAnimations'\"\n #tabList\n (cdkObserveContent)=\"_onContentChanges()\">\n <div class=\"mat-tab-links\" #tabListInner>\n <ng-content></ng-content>\n </div>\n <mat-ink-bar></mat-ink-bar>\n </div>\n</div>\n\n<button class=\"mat-tab-header-pagination mat-tab-header-pagination-after mat-elevation-z4\"\n #nextPaginator\n aria-hidden=\"true\"\n type=\"button\"\n mat-ripple\n [matRippleDisabled]=\"_disableScrollAfter || disableRipple\"\n [class.mat-tab-header-pagination-disabled]=\"_disableScrollAfter\"\n [disabled]=\"_disableScrollAfter || null\"\n tabindex=\"-1\"\n (mousedown)=\"_handlePaginatorPress('after', $event)\"\n (click)=\"_handlePaginatorClick('after')\"\n (touchend)=\"_stopInterval()\">\n <div class=\"mat-tab-header-pagination-chevron\"></div>\n</button>\n", styles: [".mat-tab-header{display:flex;overflow:hidden;position:relative;flex-shrink:0}.mat-tab-header-pagination{-webkit-user-select:none;user-select:none;position:relative;display:none;justify-content:center;align-items:center;min-width:32px;cursor:pointer;z-index:2;-webkit-tap-highlight-color:rgba(0,0,0,0);touch-action:none;box-sizing:content-box;background:none;border:none;outline:0;padding:0}.mat-tab-header-pagination::-moz-focus-inner{border:0}.mat-tab-header-pagination-controls-enabled .mat-tab-header-pagination{display:flex}.mat-tab-header-pagination-before,.mat-tab-header-rtl .mat-tab-header-pagination-after{padding-left:4px}.mat-tab-header-pagination-before .mat-tab-header-pagination-chevron,.mat-tab-header-rtl .mat-tab-header-pagination-after .mat-tab-header-pagination-chevron{transform:rotate(-135deg)}.mat-tab-header-rtl .mat-tab-header-pagination-before,.mat-tab-header-pagination-after{padding-right:4px}.mat-tab-header-rtl .mat-tab-header-pagination-before .mat-tab-header-pagination-chevron,.mat-tab-header-pagination-after .mat-tab-header-pagination-chevron{transform:rotate(45deg)}.mat-tab-header-pagination-chevron{border-style:solid;border-width:2px 2px 0 0;height:8px;width:8px}.mat-tab-header-pagination-disabled{box-shadow:none;cursor:default}.mat-tab-list{flex-grow:1;position:relative;transition:transform 500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-tab-links{display:flex}[mat-align-tabs=center]>.mat-tab-link-container .mat-tab-links{justify-content:center}[mat-align-tabs=end]>.mat-tab-link-container .mat-tab-links{justify-content:flex-end}.mat-ink-bar{position:absolute;bottom:0;height:2px;transition:500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-ink-bar._mat-animation-noopable{transition:none !important;animation:none !important}.mat-tab-group-inverted-header .mat-ink-bar{bottom:auto;top:0}.cdk-high-contrast-active .mat-ink-bar{outline:solid 2px;height:0}.mat-tab-link-container{display:flex;flex-grow:1;overflow:hidden;z-index:1}.mat-tab-link{height:48px;padding:0 24px;cursor:pointer;box-sizing:border-box;opacity:.6;min-width:160px;text-align:center;display:inline-flex;justify-content:center;align-items:center;white-space:nowrap;vertical-align:top;text-decoration:none;position:relative;overflow:hidden;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mat-tab-link:focus{outline:none}.mat-tab-link:focus:not(.mat-tab-disabled){opacity:1}.cdk-high-contrast-active .mat-tab-link:focus{outline:dotted 2px;outline-offset:-2px}.mat-tab-link.mat-tab-disabled{cursor:default}.cdk-high-contrast-active .mat-tab-link.mat-tab-disabled{opacity:.5}.mat-tab-link .mat-tab-label-content{display:inline-flex;justify-content:center;align-items:center;white-space:nowrap}.cdk-high-contrast-active .mat-tab-link{opacity:1}[mat-stretch-tabs] .mat-tab-link{flex-basis:0;flex-grow:1}.mat-tab-link.mat-tab-disabled{pointer-events:none}@media(max-width: 599px){.mat-tab-link{min-width:72px}}"], dependencies: [{ kind: "directive", type: i4.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "directive", type: i5.CdkObserveContent, selector: "[cdkObserveContent]", inputs: ["cdkObserveContentDisabled", "debounce"], outputs: ["cdkObserveContent"], exportAs: ["cdkObserveContent"] }, { kind: "directive", type: MatInkBar, selector: "mat-ink-bar" }], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None });
1736i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabNav, decorators: [{
1737 type: Component,
1738 args: [{ selector: '[mat-tab-nav-bar]', exportAs: 'matTabNavBar, matTabNav', inputs: ['color'], host: {
1739 '[attr.role]': '_getRole()',
1740 'class': 'mat-tab-nav-bar mat-tab-header',
1741 '[class.mat-tab-header-pagination-controls-enabled]': '_showPaginationControls',
1742 '[class.mat-tab-header-rtl]': "_getLayoutDirection() == 'rtl'",
1743 '[class.mat-primary]': 'color !== "warn" && color !== "accent"',
1744 '[class.mat-accent]': 'color === "accent"',
1745 '[class.mat-warn]': 'color === "warn"',
1746 }, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.Default, template: "<button class=\"mat-tab-header-pagination mat-tab-header-pagination-before mat-elevation-z4\"\n #previousPaginator\n aria-hidden=\"true\"\n type=\"button\"\n mat-ripple\n tabindex=\"-1\"\n [matRippleDisabled]=\"_disableScrollBefore || disableRipple\"\n [class.mat-tab-header-pagination-disabled]=\"_disableScrollBefore\"\n [disabled]=\"_disableScrollBefore || null\"\n (click)=\"_handlePaginatorClick('before')\"\n (mousedown)=\"_handlePaginatorPress('before', $event)\"\n (touchend)=\"_stopInterval()\">\n <div class=\"mat-tab-header-pagination-chevron\"></div>\n</button>\n\n<div class=\"mat-tab-link-container\" #tabListContainer (keydown)=\"_handleKeydown($event)\">\n <div\n class=\"mat-tab-list\"\n [class._mat-animation-noopable]=\"_animationMode === 'NoopAnimations'\"\n #tabList\n (cdkObserveContent)=\"_onContentChanges()\">\n <div class=\"mat-tab-links\" #tabListInner>\n <ng-content></ng-content>\n </div>\n <mat-ink-bar></mat-ink-bar>\n </div>\n</div>\n\n<button class=\"mat-tab-header-pagination mat-tab-header-pagination-after mat-elevation-z4\"\n #nextPaginator\n aria-hidden=\"true\"\n type=\"button\"\n mat-ripple\n [matRippleDisabled]=\"_disableScrollAfter || disableRipple\"\n [class.mat-tab-header-pagination-disabled]=\"_disableScrollAfter\"\n [disabled]=\"_disableScrollAfter || null\"\n tabindex=\"-1\"\n (mousedown)=\"_handlePaginatorPress('after', $event)\"\n (click)=\"_handlePaginatorClick('after')\"\n (touchend)=\"_stopInterval()\">\n <div class=\"mat-tab-header-pagination-chevron\"></div>\n</button>\n", styles: [".mat-tab-header{display:flex;overflow:hidden;position:relative;flex-shrink:0}.mat-tab-header-pagination{-webkit-user-select:none;user-select:none;position:relative;display:none;justify-content:center;align-items:center;min-width:32px;cursor:pointer;z-index:2;-webkit-tap-highlight-color:rgba(0,0,0,0);touch-action:none;box-sizing:content-box;background:none;border:none;outline:0;padding:0}.mat-tab-header-pagination::-moz-focus-inner{border:0}.mat-tab-header-pagination-controls-enabled .mat-tab-header-pagination{display:flex}.mat-tab-header-pagination-before,.mat-tab-header-rtl .mat-tab-header-pagination-after{padding-left:4px}.mat-tab-header-pagination-before .mat-tab-header-pagination-chevron,.mat-tab-header-rtl .mat-tab-header-pagination-after .mat-tab-header-pagination-chevron{transform:rotate(-135deg)}.mat-tab-header-rtl .mat-tab-header-pagination-before,.mat-tab-header-pagination-after{padding-right:4px}.mat-tab-header-rtl .mat-tab-header-pagination-before .mat-tab-header-pagination-chevron,.mat-tab-header-pagination-after .mat-tab-header-pagination-chevron{transform:rotate(45deg)}.mat-tab-header-pagination-chevron{border-style:solid;border-width:2px 2px 0 0;height:8px;width:8px}.mat-tab-header-pagination-disabled{box-shadow:none;cursor:default}.mat-tab-list{flex-grow:1;position:relative;transition:transform 500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-tab-links{display:flex}[mat-align-tabs=center]>.mat-tab-link-container .mat-tab-links{justify-content:center}[mat-align-tabs=end]>.mat-tab-link-container .mat-tab-links{justify-content:flex-end}.mat-ink-bar{position:absolute;bottom:0;height:2px;transition:500ms cubic-bezier(0.35, 0, 0.25, 1)}.mat-ink-bar._mat-animation-noopable{transition:none !important;animation:none !important}.mat-tab-group-inverted-header .mat-ink-bar{bottom:auto;top:0}.cdk-high-contrast-active .mat-ink-bar{outline:solid 2px;height:0}.mat-tab-link-container{display:flex;flex-grow:1;overflow:hidden;z-index:1}.mat-tab-link{height:48px;padding:0 24px;cursor:pointer;box-sizing:border-box;opacity:.6;min-width:160px;text-align:center;display:inline-flex;justify-content:center;align-items:center;white-space:nowrap;vertical-align:top;text-decoration:none;position:relative;overflow:hidden;-webkit-tap-highlight-color:rgba(0,0,0,0)}.mat-tab-link:focus{outline:none}.mat-tab-link:focus:not(.mat-tab-disabled){opacity:1}.cdk-high-contrast-active .mat-tab-link:focus{outline:dotted 2px;outline-offset:-2px}.mat-tab-link.mat-tab-disabled{cursor:default}.cdk-high-contrast-active .mat-tab-link.mat-tab-disabled{opacity:.5}.mat-tab-link .mat-tab-label-content{display:inline-flex;justify-content:center;align-items:center;white-space:nowrap}.cdk-high-contrast-active .mat-tab-link{opacity:1}[mat-stretch-tabs] .mat-tab-link{flex-basis:0;flex-grow:1}.mat-tab-link.mat-tab-disabled{pointer-events:none}@media(max-width: 599px){.mat-tab-link{min-width:72px}}"] }]
1747 }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.Directionality, decorators: [{
1748 type: Optional
1749 }] }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: i1$1.ViewportRuler }, { type: i3.Platform }, { type: undefined, decorators: [{
1750 type: Optional
1751 }, {
1752 type: Inject,
1753 args: [ANIMATION_MODULE_TYPE]
1754 }] }]; }, propDecorators: { _items: [{
1755 type: ContentChildren,
1756 args: [forwardRef(() => MatTabLink), { descendants: true }]
1757 }], _inkBar: [{
1758 type: ViewChild,
1759 args: [MatInkBar, { static: true }]
1760 }], _tabListContainer: [{
1761 type: ViewChild,
1762 args: ['tabListContainer', { static: true }]
1763 }], _tabList: [{
1764 type: ViewChild,
1765 args: ['tabList', { static: true }]
1766 }], _tabListInner: [{
1767 type: ViewChild,
1768 args: ['tabListInner', { static: true }]
1769 }], _nextPaginator: [{
1770 type: ViewChild,
1771 args: ['nextPaginator']
1772 }], _previousPaginator: [{
1773 type: ViewChild,
1774 args: ['previousPaginator']
1775 }] } });
1776// Boilerplate for applying mixins to MatTabLink.
1777const _MatTabLinkMixinBase = mixinTabIndex(mixinDisableRipple(mixinDisabled(class {
1778})));
1779/** Base class with all of the `MatTabLink` functionality. */
1780class _MatTabLinkBase extends _MatTabLinkMixinBase {
1781 constructor(_tabNavBar,
1782 /** @docs-private */ elementRef, globalRippleOptions, tabIndex, _focusMonitor, animationMode) {
1783 super();
1784 this._tabNavBar = _tabNavBar;
1785 this.elementRef = elementRef;
1786 this._focusMonitor = _focusMonitor;
1787 /** Whether the tab link is active or not. */
1788 this._isActive = false;
1789 /** Unique id for the tab. */
1790 this.id = `mat-tab-link-${nextUniqueId++}`;
1791 this.rippleConfig = globalRippleOptions || {};
1792 this.tabIndex = parseInt(tabIndex) || 0;
1793 if (animationMode === 'NoopAnimations') {
1794 this.rippleConfig.animation = { enterDuration: 0, exitDuration: 0 };
1795 }
1796 }
1797 /** Whether the link is active. */
1798 get active() {
1799 return this._isActive;
1800 }
1801 set active(value) {
1802 const newValue = coerceBooleanProperty(value);
1803 if (newValue !== this._isActive) {
1804 this._isActive = newValue;
1805 this._tabNavBar.updateActiveLink();
1806 }
1807 }
1808 /**
1809 * Whether ripples are disabled on interaction.
1810 * @docs-private
1811 */
1812 get rippleDisabled() {
1813 return (this.disabled ||
1814 this.disableRipple ||
1815 this._tabNavBar.disableRipple ||
1816 !!this.rippleConfig.disabled);
1817 }
1818 /** Focuses the tab link. */
1819 focus() {
1820 this.elementRef.nativeElement.focus();
1821 }
1822 ngAfterViewInit() {
1823 this._focusMonitor.monitor(this.elementRef);
1824 }
1825 ngOnDestroy() {
1826 this._focusMonitor.stopMonitoring(this.elementRef);
1827 }
1828 _handleFocus() {
1829 // Since we allow navigation through tabbing in the nav bar, we
1830 // have to update the focused index whenever the link receives focus.
1831 this._tabNavBar.focusIndex = this._tabNavBar._items.toArray().indexOf(this);
1832 }
1833 _handleKeydown(event) {
1834 if (this._tabNavBar.tabPanel && event.keyCode === SPACE) {
1835 this.elementRef.nativeElement.click();
1836 }
1837 }
1838 _getAriaControls() {
1839 return this._tabNavBar.tabPanel
1840 ? this._tabNavBar.tabPanel?.id
1841 : this.elementRef.nativeElement.getAttribute('aria-controls');
1842 }
1843 _getAriaSelected() {
1844 if (this._tabNavBar.tabPanel) {
1845 return this.active ? 'true' : 'false';
1846 }
1847 else {
1848 return this.elementRef.nativeElement.getAttribute('aria-selected');
1849 }
1850 }
1851 _getAriaCurrent() {
1852 return this.active && !this._tabNavBar.tabPanel ? 'page' : null;
1853 }
1854 _getRole() {
1855 return this._tabNavBar.tabPanel ? 'tab' : this.elementRef.nativeElement.getAttribute('role');
1856 }
1857 _getTabIndex() {
1858 if (this._tabNavBar.tabPanel) {
1859 return this._isActive && !this.disabled ? 0 : -1;
1860 }
1861 else {
1862 return this.tabIndex;
1863 }
1864 }
1865}
1866_MatTabLinkBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabLinkBase, deps: [{ token: _MatTabNavBase }, { token: i0.ElementRef }, { token: MAT_RIPPLE_GLOBAL_OPTIONS, optional: true }, { token: 'tabindex', attribute: true }, { token: i7.FocusMonitor }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1867_MatTabLinkBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: _MatTabLinkBase, inputs: { active: "active", id: "id" }, usesInheritance: true, ngImport: i0 });
1868i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: _MatTabLinkBase, decorators: [{
1869 type: Directive
1870 }], ctorParameters: function () { return [{ type: _MatTabNavBase }, { type: i0.ElementRef }, { type: undefined, decorators: [{
1871 type: Optional
1872 }, {
1873 type: Inject,
1874 args: [MAT_RIPPLE_GLOBAL_OPTIONS]
1875 }] }, { type: undefined, decorators: [{
1876 type: Attribute,
1877 args: ['tabindex']
1878 }] }, { type: i7.FocusMonitor }, { type: undefined, decorators: [{
1879 type: Optional
1880 }, {
1881 type: Inject,
1882 args: [ANIMATION_MODULE_TYPE]
1883 }] }]; }, propDecorators: { active: [{
1884 type: Input
1885 }], id: [{
1886 type: Input
1887 }] } });
1888/**
1889 * Link inside of a `mat-tab-nav-bar`.
1890 */
1891class MatTabLink extends _MatTabLinkBase {
1892 constructor(tabNavBar, elementRef, ngZone, platform, globalRippleOptions, tabIndex, focusMonitor, animationMode) {
1893 super(tabNavBar, elementRef, globalRippleOptions, tabIndex, focusMonitor, animationMode);
1894 this._tabLinkRipple = new RippleRenderer(this, ngZone, elementRef, platform);
1895 this._tabLinkRipple.setupTriggerEvents(elementRef.nativeElement);
1896 }
1897 ngOnDestroy() {
1898 super.ngOnDestroy();
1899 this._tabLinkRipple._removeTriggerEvents();
1900 }
1901}
1902MatTabLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabLink, deps: [{ token: MatTabNav }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i3.Platform }, { token: MAT_RIPPLE_GLOBAL_OPTIONS, optional: true }, { token: 'tabindex', attribute: true }, { token: i7.FocusMonitor }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
1903MatTabLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.1", type: MatTabLink, selector: "[mat-tab-link], [matTabLink]", inputs: { disabled: "disabled", disableRipple: "disableRipple", tabIndex: "tabIndex" }, host: { listeners: { "focus": "_handleFocus()", "keydown": "_handleKeydown($event)" }, properties: { "attr.aria-controls": "_getAriaControls()", "attr.aria-current": "_getAriaCurrent()", "attr.aria-disabled": "disabled", "attr.aria-selected": "_getAriaSelected()", "attr.id": "id", "attr.tabIndex": "_getTabIndex()", "attr.role": "_getRole()", "class.mat-tab-disabled": "disabled", "class.mat-tab-label-active": "active" }, classAttribute: "mat-tab-link mat-focus-indicator" }, exportAs: ["matTabLink"], usesInheritance: true, ngImport: i0 });
1904i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabLink, decorators: [{
1905 type: Directive,
1906 args: [{
1907 selector: '[mat-tab-link], [matTabLink]',
1908 exportAs: 'matTabLink',
1909 inputs: ['disabled', 'disableRipple', 'tabIndex'],
1910 host: {
1911 'class': 'mat-tab-link mat-focus-indicator',
1912 '[attr.aria-controls]': '_getAriaControls()',
1913 '[attr.aria-current]': '_getAriaCurrent()',
1914 '[attr.aria-disabled]': 'disabled',
1915 '[attr.aria-selected]': '_getAriaSelected()',
1916 '[attr.id]': 'id',
1917 '[attr.tabIndex]': '_getTabIndex()',
1918 '[attr.role]': '_getRole()',
1919 '[class.mat-tab-disabled]': 'disabled',
1920 '[class.mat-tab-label-active]': 'active',
1921 '(focus)': '_handleFocus()',
1922 '(keydown)': '_handleKeydown($event)',
1923 },
1924 }]
1925 }], ctorParameters: function () { return [{ type: MatTabNav }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i3.Platform }, { type: undefined, decorators: [{
1926 type: Optional
1927 }, {
1928 type: Inject,
1929 args: [MAT_RIPPLE_GLOBAL_OPTIONS]
1930 }] }, { type: undefined, decorators: [{
1931 type: Attribute,
1932 args: ['tabindex']
1933 }] }, { type: i7.FocusMonitor }, { type: undefined, decorators: [{
1934 type: Optional
1935 }, {
1936 type: Inject,
1937 args: [ANIMATION_MODULE_TYPE]
1938 }] }]; } });
1939/**
1940 * Tab panel component associated with MatTabNav.
1941 */
1942class MatTabNavPanel {
1943 constructor() {
1944 /** Unique id for the tab panel. */
1945 this.id = `mat-tab-nav-panel-${nextUniqueId++}`;
1946 }
1947}
1948MatTabNavPanel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabNavPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
1949MatTabNavPanel.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.1", type: MatTabNavPanel, selector: "mat-tab-nav-panel", inputs: { id: "id" }, host: { attributes: { "role": "tabpanel" }, properties: { "attr.aria-labelledby": "_activeTabId", "attr.id": "id" }, classAttribute: "mat-tab-nav-panel" }, exportAs: ["matTabNavPanel"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1950i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabNavPanel, decorators: [{
1951 type: Component,
1952 args: [{
1953 selector: 'mat-tab-nav-panel',
1954 exportAs: 'matTabNavPanel',
1955 template: '<ng-content></ng-content>',
1956 host: {
1957 '[attr.aria-labelledby]': '_activeTabId',
1958 '[attr.id]': 'id',
1959 'class': 'mat-tab-nav-panel',
1960 'role': 'tabpanel',
1961 },
1962 encapsulation: ViewEncapsulation.None,
1963 changeDetection: ChangeDetectionStrategy.OnPush,
1964 }]
1965 }], propDecorators: { id: [{
1966 type: Input
1967 }] } });
1968
1969/**
1970 * @license
1971 * Copyright Google LLC All Rights Reserved.
1972 *
1973 * Use of this source code is governed by an MIT-style license that can be
1974 * found in the LICENSE file at https://angular.io/license
1975 */
1976class MatTabsModule {
1977}
1978MatTabsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1979MatTabsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.1", ngImport: i0, type: MatTabsModule, declarations: [MatTabGroup,
1980 MatTabLabel,
1981 MatTab,
1982 MatInkBar,
1983 MatTabLabelWrapper,
1984 MatTabNav,
1985 MatTabNavPanel,
1986 MatTabLink,
1987 MatTabBody,
1988 MatTabBodyPortal,
1989 MatTabHeader,
1990 MatTabContent], imports: [CommonModule,
1991 MatCommonModule,
1992 PortalModule,
1993 MatRippleModule,
1994 ObserversModule,
1995 A11yModule], exports: [MatCommonModule,
1996 MatTabGroup,
1997 MatTabLabel,
1998 MatTab,
1999 MatTabNav,
2000 MatTabNavPanel,
2001 MatTabLink,
2002 MatTabContent] });
2003MatTabsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabsModule, imports: [CommonModule,
2004 MatCommonModule,
2005 PortalModule,
2006 MatRippleModule,
2007 ObserversModule,
2008 A11yModule, MatCommonModule] });
2009i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: MatTabsModule, decorators: [{
2010 type: NgModule,
2011 args: [{
2012 imports: [
2013 CommonModule,
2014 MatCommonModule,
2015 PortalModule,
2016 MatRippleModule,
2017 ObserversModule,
2018 A11yModule,
2019 ],
2020 // Don't export all components because some are only to be used internally.
2021 exports: [
2022 MatCommonModule,
2023 MatTabGroup,
2024 MatTabLabel,
2025 MatTab,
2026 MatTabNav,
2027 MatTabNavPanel,
2028 MatTabLink,
2029 MatTabContent,
2030 ],
2031 declarations: [
2032 MatTabGroup,
2033 MatTabLabel,
2034 MatTab,
2035 MatInkBar,
2036 MatTabLabelWrapper,
2037 MatTabNav,
2038 MatTabNavPanel,
2039 MatTabLink,
2040 MatTabBody,
2041 MatTabBodyPortal,
2042 MatTabHeader,
2043 MatTabContent,
2044 ],
2045 }]
2046 }] });
2047
2048/**
2049 * @license
2050 * Copyright Google LLC All Rights Reserved.
2051 *
2052 * Use of this source code is governed by an MIT-style license that can be
2053 * found in the LICENSE file at https://angular.io/license
2054 */
2055
2056/**
2057 * @license
2058 * Copyright Google LLC All Rights Reserved.
2059 *
2060 * Use of this source code is governed by an MIT-style license that can be
2061 * found in the LICENSE file at https://angular.io/license
2062 */
2063
2064/**
2065 * @license
2066 * Copyright Google LLC All Rights Reserved.
2067 *
2068 * Use of this source code is governed by an MIT-style license that can be
2069 * found in the LICENSE file at https://angular.io/license
2070 */
2071
2072/**
2073 * Generated bundle index. Do not edit.
2074 */
2075
2076export { MAT_TAB, MAT_TABS_CONFIG, MAT_TAB_GROUP, MatInkBar, MatTab, MatTabBody, MatTabBodyPortal, MatTabChangeEvent, MatTabContent, MatTabGroup, MatTabHeader, MatTabLabel, MatTabLabelWrapper, MatTabLink, MatTabNav, MatTabNavPanel, MatTabsModule, _MAT_INK_BAR_POSITIONER, _MatTabBodyBase, _MatTabGroupBase, _MatTabHeaderBase, _MatTabLinkBase, _MatTabNavBase, matTabsAnimations };
2077//# sourceMappingURL=tabs.mjs.map