@@ -26,7 +26,6 @@ import {
26
26
Input ,
27
27
NgZone ,
28
28
OnDestroy ,
29
- OnInit ,
30
29
Optional ,
31
30
QueryList ,
32
31
ViewChild ,
@@ -51,6 +50,9 @@ import {startWith, takeUntil} from 'rxjs/operators';
51
50
import { MatInkBar } from '../ink-bar' ;
52
51
import { MatPaginatedTabHeader , MatPaginatedTabHeaderItem } from '../paginated-tab-header' ;
53
52
53
+ // Increasing integer for generating unique ids for tab nav components.
54
+ let nextUniqueId = 0 ;
55
+
54
56
/**
55
57
* Base class with all of the `MatTabNav` functionality.
56
58
* @docs -private
@@ -61,7 +63,9 @@ export abstract class _MatTabNavBase
61
63
implements AfterContentChecked , AfterContentInit , OnDestroy
62
64
{
63
65
/** Query list of all tab links of the tab navigation. */
64
- abstract override _items : QueryList < MatPaginatedTabHeaderItem & { active : boolean , _uniqueId : string } > ;
66
+ abstract override _items : QueryList <
67
+ MatPaginatedTabHeaderItem & { active : boolean ; _uniqueId : string }
68
+ > ;
65
69
66
70
/** Background color of the tab nav. */
67
71
@Input ( )
@@ -93,13 +97,12 @@ export abstract class _MatTabNavBase
93
97
/** Theme color of the nav bar. */
94
98
@Input ( ) color: ThemePalette = 'primary' ;
95
99
96
- /** Associated outlet controlled by the nav bar. */
97
- @Input ( ) outlet ?: MatTabNavOutlet ;
98
-
99
- /** Returns whether the nav bar should follow the ARIA tab design pattern. */
100
- get _isTabDesignPattern ( ) {
101
- return ! ! this . outlet ;
102
- }
100
+ /**
101
+ * Associated tab panel controlled by the nav bar. If not provided, then the nav bar
102
+ * follows the ARIA link / navigation landmark pattern. If provided, it follows the
103
+ * ARIA tabs design pattern.
104
+ */
105
+ @Input ( ) panel ?: MatTabNavPanel ;
103
106
104
107
constructor (
105
108
elementRef : ElementRef ,
@@ -140,9 +143,9 @@ export abstract class _MatTabNavBase
140
143
this . selectedIndex = i ;
141
144
this . _changeDetectorRef . markForCheck ( ) ;
142
145
143
- if ( this . _isTabDesignPattern ) {
144
- this . outlet ! . _activeTabId = items [ i ] . _uniqueId ;
145
- this . outlet ! . _cdr . markForCheck ( ) ;
146
+ if ( this . panel ) {
147
+ this . panel . _activeTabId = items [ i ] . _uniqueId ;
148
+ this . panel . _cdr . markForCheck ( ) ;
146
149
}
147
150
148
151
return ;
@@ -172,7 +175,7 @@ export abstract class _MatTabNavBase
172
175
'[class.mat-primary]' : 'color !== "warn" && color !== "accent"' ,
173
176
'[class.mat-accent]' : 'color === "accent"' ,
174
177
'[class.mat-warn]' : 'color === "warn"' ,
175
- '[attr.role]' : '_isTabDesignPattern ? "tablist" : null'
178
+ '[attr.role]' : 'panel ? "tablist" : null' ,
176
179
} ,
177
180
encapsulation : ViewEncapsulation . None ,
178
181
// tslint:disable-next-line:validate-decorators
@@ -202,9 +205,6 @@ export class MatTabNav extends _MatTabNavBase {
202
205
static ngAcceptInputType_disableRipple : BooleanInput ;
203
206
}
204
207
205
- // Increasing integer for generating unique ids for tab link components.
206
- let nextUniqueTabLinkId = 0 ;
207
-
208
208
// Boilerplate for applying mixins to MatTabLink.
209
209
const _MatTabLinkMixinBase = mixinTabIndex ( mixinDisableRipple ( mixinDisabled ( class { } ) ) ) ;
210
210
@@ -259,12 +259,8 @@ export class _MatTabLinkBase
259
259
) ;
260
260
}
261
261
262
- get _index ( ) : number {
263
- return this . _tabNavBar . _items . toArray ( ) . indexOf ( this ) ;
264
- }
265
-
266
262
/** Unique id for the component referenced in ARIA attributes. */
267
- _uniqueId = `mat-tab-link-${ nextUniqueTabLinkId ++ } ` ;
263
+ _uniqueId = `mat-tab-link-${ nextUniqueId ++ } ` ;
268
264
269
265
constructor (
270
266
private _tabNavBar : _MatTabNavBase ,
@@ -300,21 +296,30 @@ export class _MatTabLinkBase
300
296
_handleFocus ( ) {
301
297
// Since we allow navigation through tabbing in the nav bar, we
302
298
// have to update the focused index whenever the link receives focus.
303
- this . _tabNavBar . focusIndex = this . _index ;
299
+ this . _tabNavBar . focusIndex = this . _getIndex ( ) ;
304
300
}
305
301
306
302
_handleSpace ( ) {
307
- if ( this . _tabNavBar . _isTabDesignPattern ) {
303
+ if ( this . _tabNavBar . panel ) {
308
304
this . elementRef . nativeElement . click ( ) ;
309
305
}
310
306
}
311
307
312
308
_getTabIndex ( ) {
309
+ if ( ! this . _tabNavBar . panel ) {
310
+ return this . tabIndex ;
311
+ }
312
+
313
313
if ( ! this . _tabNavBar . _items ) {
314
314
return this . _isActive ? '0' : '-1' ;
315
315
}
316
316
317
- return ( this . _tabNavBar . focusIndex === this . _index ) ? '0' : '-1' ;
317
+ return this . _tabNavBar . focusIndex === this . _getIndex ( ) ? '0' : '-1' ;
318
+ }
319
+
320
+ /** Returns this item's index in the nav bar. */
321
+ _getIndex ( ) : number {
322
+ return this . _tabNavBar . _items . toArray ( ) . indexOf ( this ) ;
318
323
}
319
324
320
325
static ngAcceptInputType_active : BooleanInput ;
@@ -332,16 +337,16 @@ export class _MatTabLinkBase
332
337
inputs : [ 'disabled' , 'disableRipple' , 'tabIndex' ] ,
333
338
host : {
334
339
'class' : 'mat-tab-link mat-focus-indicator' ,
335
- '[attr.aria-controls]' : '_tabNavBar._isTabDesignPattern ? _tabNavBar.outlet ._uniqueId : null' ,
336
- '[attr.aria-current]' : 'active && !_tabNavBar._isTabDesignPattern ? "page" : null' ,
340
+ '[attr.aria-controls]' : '_tabNavBar.panel ? _tabNavBar.panel ._uniqueId : null' ,
341
+ '[attr.aria-current]' : 'active && !_tabNavBar.panel ? "page" : null' ,
337
342
'[attr.aria-disabled]' : 'disabled' ,
338
- '[attr.aria-selected]' : '_tabNavBar._isTabDesignPattern ? (active ? "true" : "false") : null' ,
339
- '[attr.tabIndex]' : '_tabNavBar._isTabDesignPattern ? _getTabIndex() : tabIndex ' ,
340
- '[attr.role]' : '_tabNavBar._isTabDesignPattern ? "tab" : null' ,
343
+ '[attr.aria-selected]' : '_tabNavBar.panel ? (active ? "true" : "false") : null' ,
344
+ '[attr.tabIndex]' : '_getTabIndex()' ,
345
+ '[attr.role]' : '_tabNavBar.panel ? "tab" : null' ,
341
346
'[class.mat-tab-disabled]' : 'disabled' ,
342
347
'[class.mat-tab-label-active]' : 'active' ,
343
348
'(focus)' : '_handleFocus()' ,
344
- '(keydown.space)' : '_handleSpace()'
349
+ '(keydown.space)' : '_handleSpace()' ,
345
350
} ,
346
351
} )
347
352
export class MatTabLink extends _MatTabLinkBase implements OnDestroy {
@@ -369,23 +374,27 @@ export class MatTabLink extends _MatTabLinkBase implements OnDestroy {
369
374
}
370
375
}
371
376
372
- // Increasing integer for generating unique ids for tab nav outlet components.
373
- let nextUniqueTabNavOutletId = 0 ;
374
-
377
+ /**
378
+ * Tab panel component associated with MatTabNav.
379
+ */
375
380
@Component ( {
376
- selector : 'mat-tab-nav-outlet ' ,
377
- exportAs : 'matTabNavOutlet ' ,
381
+ selector : 'mat-tab-nav-panel ' ,
382
+ exportAs : 'matTabNavPanel ' ,
378
383
template : '<ng-content select="router-outlet"></ng-content>' ,
379
384
host : {
380
385
'[attr.aria-labelledby]' : '_activeTabId || null' ,
381
386
'role' : 'tabpanel' ,
382
387
} ,
388
+ encapsulation : ViewEncapsulation . None ,
389
+ // tslint:disable-next-line:validate-decorators
390
+ changeDetection : ChangeDetectionStrategy . Default ,
383
391
} )
384
- export class MatTabNavOutlet {
392
+ export class MatTabNavPanel {
393
+ /** Id of the active tab in the nav bar. */
385
394
_activeTabId ?: string ;
386
395
387
396
/** Unique id for the component referenced in ARIA attributes. */
388
- _uniqueId = `mat-tab-nav-outlet -${ nextUniqueTabNavOutletId ++ } ` ;
397
+ _uniqueId = `mat-tab-nav-panel -${ nextUniqueId ++ } ` ;
389
398
390
399
constructor ( readonly _cdr : ChangeDetectorRef ) { }
391
400
}
0 commit comments