Skip to content

Commit b914539

Browse files
committed
refactor(aria/tabs): associate tab to panel via id
1 parent 6179d7a commit b914539

File tree

9 files changed

+27
-31
lines changed

9 files changed

+27
-31
lines changed

goldens/aria/tabs/index.api.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ export class Tab implements HasElement, OnInit, OnDestroy {
2222
ngOnInit(): void;
2323
open(): void;
2424
readonly panel: _angular_core.Signal<TabPanel | undefined>;
25+
readonly panelRef: _angular_core.InputSignal<string | TabPanel>;
2526
readonly _pattern: TabPattern;
2627
readonly selected: _angular_core.Signal<boolean>;
27-
readonly value: _angular_core.InputSignal<string>;
2828
// (undocumented)
29-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<Tab, "[ngTab]", ["ngTab"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
29+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<Tab, "[ngTab]", ["ngTab"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "panelRef": { "alias": "panel"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
3030
// (undocumented)
3131
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Tab, never>;
3232
}
@@ -45,13 +45,13 @@ export class TabList implements OnInit, OnDestroy {
4545
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
4646
readonly element: HTMLElement;
4747
// (undocumented)
48-
findTab(value?: string): Tab | undefined;
48+
findTab(panelId?: string): Tab | undefined;
4949
readonly focusMode: _angular_core.InputSignal<"roving" | "activedescendant">;
5050
// (undocumented)
5151
ngOnDestroy(): void;
5252
// (undocumented)
5353
ngOnInit(): void;
54-
open(value: string): boolean;
54+
open(panelId: string): boolean;
5555
readonly orientation: _angular_core.InputSignal<"vertical" | "horizontal">;
5656
readonly _pattern: TabListPattern;
5757
// (undocumented)
@@ -81,10 +81,9 @@ export class TabPanel implements OnInit, OnDestroy {
8181
ngOnInit(): void;
8282
readonly _pattern: TabPanelPattern;
8383
readonly _tabPattern: WritableSignal<TabPattern | undefined>;
84-
readonly value: _angular_core.InputSignal<string>;
8584
readonly visible: _angular_core.Signal<boolean>;
8685
// (undocumented)
87-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TabPanel, "[ngTabPanel]", ["ngTabPanel"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": true; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof DeferredContentAware; inputs: { "preserveContent": "preserveContent"; }; outputs: {}; }]>;
86+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TabPanel, "[ngTabPanel]", ["ngTabPanel"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof DeferredContentAware; inputs: { "preserveContent": "preserveContent"; }; outputs: {}; }]>;
8887
// (undocumented)
8988
static ɵfac: _angular_core.ɵɵFactoryDeclaration<TabPanel, never>;
9089
}
@@ -94,7 +93,7 @@ export class Tabs {
9493
constructor();
9594
readonly element: HTMLElement;
9695
// (undocumented)
97-
findTabPanel(value?: string): TabPanel | undefined;
96+
findTabPanel(id?: string): TabPanel | undefined;
9897
// (undocumented)
9998
_registerList(list: TabList): void;
10099
// (undocumented)

src/aria/tabs/tab-list.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class TabList implements OnInit, OnDestroy {
135135
const pattern = this._selectedTabPattern();
136136
const tab = this._sortedTabs().find(tab => tab._pattern == pattern);
137137

138-
this.selectedTab.set(tab?.value());
138+
this.selectedTab.set(tab?.panel()?.id());
139139
});
140140

141141
afterRenderEffect(() => {
@@ -161,12 +161,12 @@ export class TabList implements OnInit, OnDestroy {
161161
this._tabs.set(new Set(this._tabs()));
162162
}
163163

164-
/** Opens the tab panel with the specified value. */
165-
open(value: string): boolean {
166-
return this._pattern.open(this.findTab(value)?._pattern);
164+
/** Opens the tab panel with the specified id. */
165+
open(panelId: string): boolean {
166+
return this._pattern.open(this.findTab(panelId)?._pattern);
167167
}
168168

169-
findTab(value?: string) {
170-
return value ? this._sortedTabs().find(tab => tab.value() === value) : undefined;
169+
findTab(panelId?: string) {
170+
return panelId ? this._sortedTabs().find(tab => tab.panel()?.id() === panelId) : undefined;
171171
}
172172
}

src/aria/tabs/tab-panel.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ export class TabPanel implements OnInit, OnDestroy {
7777
/** The Tab UIPattern associated with the tabpanel */
7878
readonly _tabPattern: WritableSignal<TabPattern | undefined> = signal(undefined);
7979

80-
/** A local unique identifier for the tabpanel. */
81-
readonly value = input<string>();
82-
8380
/** Whether the tab panel is visible. */
8481
readonly visible = computed(() => !this._pattern.hidden());
8582

src/aria/tabs/tab.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,19 @@ export class Tab implements HasElement, OnInit, OnDestroy {
6666
/** A unique identifier for the widget. */
6767
readonly id = input(inject(_IdGenerator).getId('ng-tab-', true));
6868

69-
/** Direct reference to panel associated with this tab. */
70-
readonly panelRef = input<TabPanel>(undefined, {alias: 'panel'});
69+
/** Direct reference to or id of panel associated with this tab. */
70+
readonly panelRef = input.required<TabPanel | string>({alias: 'panel'});
7171

7272
/** The panel associated with this tab. */
73-
readonly panel = computed(() => this.panelRef() ?? this._tabsWrapper.findTabPanel(this.value()));
73+
readonly panel = computed(() => {
74+
const ref = this.panelRef();
75+
76+
return ref instanceof TabPanel ? ref : this._tabsWrapper.findTabPanel(ref);
77+
});
7478

7579
/** Whether a tab is disabled. */
7680
readonly disabled = input(false, {transform: booleanAttribute});
7781

78-
/** The remote tabpanel unique identifier. */
79-
readonly value = input<string>();
80-
8182
/** Whether the tab is active. */
8283
readonly active = computed(() => this._pattern.active());
8384

src/aria/tabs/tabs.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -722,12 +722,12 @@ describe('Tabs', () => {
722722
[focusMode]="focusMode()"
723723
[selectionMode]="selectionMode()">
724724
@for (tabDef of tabsData(); track tabDef.value) {
725-
<li ngTab [value]="tabDef.value" [disabled]="!!tabDef.disabled">{{ tabDef.label }}</li>
725+
<li ngTab [panel]="tabDef.value" [disabled]="!!tabDef.disabled">{{ tabDef.label }}</li>
726726
}
727727
</ul>
728728
729729
@for (tabDef of tabsData(); track tabDef.value) {
730-
<div ngTabPanel [value]="tabDef.value">
730+
<div ngTabPanel [id]="tabDef.value">
731731
<ng-template ngTabContent>{{ tabDef.content }}</ng-template>
732732
</div>
733733
}

src/aria/tabs/tabs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export class Tabs {
9595
this._tabPanels.set(new Set(this._tabPanels()));
9696
}
9797

98-
findTabPanel(value?: string) {
99-
return value ? this._tabPanelsList().find(panel => panel.value() === value) : undefined;
98+
findTabPanel(id?: string) {
99+
return id ? this._tabPanelsList().find(panel => panel.id() === id) : undefined;
100100
}
101101
}

src/components-examples/aria/tabs/rtl/tabs-rtl-example.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {afterRenderEffect, Component, viewChildren} from '@angular/core';
2-
import {Dir} from '@angular/cdk/bidi';
32
import {Tabs, Tab, TabList, TabPanel, TabContent} from '@angular/aria/tabs';
43

54
/** * @title RTL */

src/components-examples/aria/tabs/scrollable/tabs-scrollable-example.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<div ngTabs>
22
<div ngTabList aria-label="Scrollable tabs" selectedTab="tab1">
33
@for (i of tabsList; track i) {
4-
<div ngTab [value]="'tab' + i">Tab {{i}}</div>
4+
<div ngTab [panel]="'tab' + i">Tab {{i}}</div>
55
}
66
</div>
77

88
@for (i of tabsList; track i) {
9-
<div ngTabPanel [value]="'tab' + i">
9+
<div ngTabPanel [id]="'tab' + i">
1010
<ng-template ngTabContent>Content for Tab {{i}}</ng-template>
1111
</div>
1212
}

src/components-examples/aria/tabs/tabs-configurable/tabs-configurable-example.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@
4949
selectionMode="explicit"
5050
>
5151
@for (tabDef of tabsData; track tabDef.value) {
52-
<div ngTab [value]="tabDef.value">{{ tabDef.label }}</div>
52+
<div ngTab [panel]="tabDef.value">{{ tabDef.label }}</div>
5353
}
5454
</div>
5555

5656
@for (tabDef of tabsData; track tabDef.value) {
57-
<div ngTabPanel [value]="tabDef.value">
57+
<div ngTabPanel [id]="tabDef.value">
5858
<ng-template ngTabContent>{{ tabDef.label }}</ng-template>
5959
</div>
6060
}

0 commit comments

Comments
 (0)