/
githubmirror
/
components
Обзор
Документация
Войти
/
githubmirror
/
components
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/aria/tabs/tab-panel.ts
130 строк
4 KB
Andrey Dolgachev
test(multiple): check for incorrect usage of Angular Aria directives and log violations (#33195)
12 май 2026, 23:40
Не верифицирован
12 май 2026, 23:40
33593e7
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import {_IdGenerator} from '@angular/cdk/a11y'; import { computed, Directive, ElementRef, inject, input, afterRenderEffect, contentChild, OnInit, OnDestroy, } from '@angular/core'; import {TabPanelPattern, DeferredContentAware, reportViolations} from '../private'; import {TABS} from './tab-tokens'; import {TabContent} from './tab-content'; /** * A TabPanel container for the resources of layered content associated with a tab. * * The `ngTabPanel` directive holds the content for a specific tab. It is linked to an * `ngTab` by a matching `value`. If a tab panel is hidden, the `inert` attribute will be * applied to remove it from the accessibility tree. Proper styling is required for visual hiding. * * ```html * <div ngTabPanel value="myTabId"> * <ng-template ngTabContent> * <!-- Content for the tab panel --> * </ng-template> * </div> * ``` * * @see [Tabs](guide/aria/tabs) */ @Directive({ selector: '[ngTabPanel]', exportAs: 'ngTabPanel', host: { 'role': 'tabpanel', '[attr.id]': '_pattern.id()', '[attr.tabindex]': '_pattern.tabIndex()', '[attr.inert]': '!visible() ? true : null', '[attr.aria-labelledby]': '_pattern.labelledBy()', }, hostDirectives: [ { directive: DeferredContentAware, inputs: ['preserveContent'], }, ], }) export class TabPanel implements OnInit, OnDestroy { /** A reference to the host element. */ private readonly _elementRef = inject(ElementRef); /** A reference to the host element. */ readonly element = this._elementRef.nativeElement as HTMLElement; /** The DeferredContentAware host directive. */ private readonly _deferredContentAware = inject(DeferredContentAware); /** The parent Tabs. */ private readonly _tabs = inject(TABS); /** A global unique identifier for the tab. */ readonly id = input(inject(_IdGenerator).getId('ng-tabpanel-', true)); /** The Tab UIPattern associated with the tabpanel */ private readonly _tabPattern = computed(() => { return this._tabs._tabMap().get(this.value()); }); /** A local unique identifier for the tabpanel. */ readonly value = input.required<string>(); /** Whether the tab panel is visible. */ readonly visible = computed(() => !this._pattern.hidden()); /** The TabPanel UIPattern. */ readonly _pattern: TabPanelPattern = new TabPanelPattern({ ...this, tab: this._tabPattern, }); private readonly _tabContent = contentChild(TabContent); constructor() { // Connect the panel's hidden state to the DeferredContentAware's visibility. afterRenderEffect({ write: () => { this._deferredContentAware.contentVisible.set(this.visible()); }, }); // Check for any violations after the DOM has been updated. if (typeof ngDevMode === 'undefined' || ngDevMode) { afterRenderEffect({ read: () => { const violations: string[] = []; if (!this._tabContent()) { violations.push('ngTabPanel must have an ngTabContent structural directive to render.'); } if (!this._tabs._tabMap().has(this.value())) { violations.push( `ngTabPanel with value '${this.value()}' does not have a corresponding ngTab.`, ); } reportViolations(violations, this.element); }, }); } } ngOnInit() { this._tabs._collection.register(this); } ngOnDestroy() { this._tabs._collection.unregister(this); } }