Skip to content

Commit efdfef9

Browse files
authored
refactor(aria/tabs): Clean up tab selection and linking to panels (#32859)
1 parent b916ef9 commit efdfef9

10 files changed

Lines changed: 205 additions & 197 deletions

File tree

goldens/aria/private/index.api.md

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -660,14 +660,14 @@ export type SignalLike<T> = () => T;
660660
export function sortDirectives(a: HasElement, b: HasElement): 1 | -1;
661661

662662
// @public
663-
export interface TabInputs extends Omit<ListNavigationItem, 'index'>, Omit<ExpansionItem, 'expandable'> {
664-
tablist: SignalLike<TabListPattern>;
665-
tabpanel: SignalLike<TabPanelPattern | undefined>;
666-
value: SignalLike<string>;
663+
export interface TabInputs extends Omit<ListNavigationItem, 'index'>, Omit<ExpansionItem, 'expandable' | 'expanded'> {
664+
tabList: SignalLike<TabListPattern>;
665+
tabPanel: SignalLike<TabPanelPattern | undefined>;
667666
}
668667

669668
// @public
670669
export interface TabListInputs extends Omit<ListNavigationInputs<TabPattern>, 'multi'>, Omit<ListExpansionInputs, 'multiExpandable' | 'items'> {
670+
selectedTab: WritableSignalLike<TabPattern | undefined>;
671671
selectionMode: SignalLike<'follow' | 'explicit'>;
672672
}
673673

@@ -690,7 +690,6 @@ export class TabListPattern {
690690
onClick(event: PointerEvent): void;
691691
onFocusIn(): void;
692692
onKeydown(event: KeyboardEvent): void;
693-
open(value: string): boolean;
694693
open(tab?: TabPattern): boolean;
695694
readonly orientation: SignalLike<'vertical' | 'horizontal'>;
696695
readonly prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">;
@@ -703,8 +702,7 @@ export class TabListPattern {
703702
// @public
704703
export interface TabPanelInputs extends LabelControlOptionalInputs {
705704
id: SignalLike<string>;
706-
tab: SignalLike<TabPattern | undefined>;
707-
value: SignalLike<string>;
705+
readonly tab: SignalLike<TabPattern | undefined>;
708706
}
709707

710708
// @public
@@ -717,7 +715,6 @@ export class TabPanelPattern {
717715
readonly labelledBy: SignalLike<string | undefined>;
718716
readonly labelManager: LabelControl;
719717
readonly tabIndex: SignalLike<-1 | 0>;
720-
readonly value: SignalLike<string>;
721718
}
722719

723720
// @public
@@ -728,15 +725,14 @@ export class TabPattern {
728725
readonly disabled: SignalLike<boolean>;
729726
readonly element: SignalLike<HTMLElement>;
730727
readonly expandable: SignalLike<boolean>;
728+
// (undocumented)
731729
readonly expanded: WritableSignalLike<boolean>;
732730
readonly id: SignalLike<string>;
733-
readonly index: SignalLike<number>;
734731
// (undocumented)
735732
readonly inputs: TabInputs;
736733
open(): boolean;
737734
readonly selected: SignalLike<boolean>;
738735
readonly tabIndex: SignalLike<0 | -1>;
739-
readonly value: SignalLike<string>;
740736
}
741737

742738
// @public

goldens/aria/tabs/index.api.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as _angular_cdk_bidi from '@angular/cdk/bidi';
88
import * as _angular_core from '@angular/core';
99
import { OnDestroy } from '@angular/core';
1010
import { OnInit } from '@angular/core';
11+
import { WritableSignal } from '@angular/core';
1112

1213
// @public
1314
export class Tab implements HasElement, OnInit, OnDestroy {
@@ -20,6 +21,7 @@ export class Tab implements HasElement, OnInit, OnDestroy {
2021
// (undocumented)
2122
ngOnInit(): void;
2223
open(): void;
24+
readonly panel: _angular_core.Signal<TabPanel | undefined>;
2325
readonly _pattern: TabPattern;
2426
readonly selected: _angular_core.Signal<boolean>;
2527
readonly value: _angular_core.InputSignal<string>;
@@ -42,6 +44,8 @@ export class TabList implements OnInit, OnDestroy {
4244
constructor();
4345
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
4446
readonly element: HTMLElement;
47+
// (undocumented)
48+
findTab(value?: string): Tab | undefined;
4549
readonly focusMode: _angular_core.InputSignal<"roving" | "activedescendant">;
4650
// (undocumented)
4751
ngOnDestroy(): void;
@@ -51,14 +55,14 @@ export class TabList implements OnInit, OnDestroy {
5155
readonly orientation: _angular_core.InputSignal<"vertical" | "horizontal">;
5256
readonly _pattern: TabListPattern;
5357
// (undocumented)
54-
_register(child: Tab): void;
58+
_registerTab(child: Tab): void;
5559
readonly selectedTab: _angular_core.ModelSignal<string | undefined>;
5660
readonly selectionMode: _angular_core.InputSignal<"follow" | "explicit">;
5761
readonly softDisabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
58-
readonly _tabPatterns: _angular_core.Signal<TabPattern[]>;
59-
readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>;
62+
readonly _sortedTabs: _angular_core.Signal<Tab[]>;
63+
readonly textDirection: WritableSignal<_angular_cdk_bidi.Direction>;
6064
// (undocumented)
61-
_unregister(child: Tab): void;
65+
_unregisterTab(child: Tab): void;
6266
readonly wrap: _angular_core.InputSignalWithTransform<boolean, unknown>;
6367
// (undocumented)
6468
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TabList, "[ngTabList]", ["ngTabList"], { "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; "focusMode": { "alias": "focusMode"; "required": false; "isSignal": true; }; "selectionMode": { "alias": "selectionMode"; "required": false; "isSignal": true; }; "selectedTab": { "alias": "selectedTab"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "selectedTab": "selectedTabChange"; }, never, never, true, never>;
@@ -76,6 +80,7 @@ export class TabPanel implements OnInit, OnDestroy {
7680
// (undocumented)
7781
ngOnInit(): void;
7882
readonly _pattern: TabPanelPattern;
83+
readonly _tabPattern: WritableSignal<TabPattern | undefined>;
7984
readonly value: _angular_core.InputSignal<string>;
8085
readonly visible: _angular_core.Signal<boolean>;
8186
// (undocumented)
@@ -86,13 +91,18 @@ export class TabPanel implements OnInit, OnDestroy {
8691

8792
// @public
8893
export class Tabs {
94+
constructor();
8995
readonly element: HTMLElement;
9096
// (undocumented)
91-
_register(child: TabList | TabPanel): void;
92-
readonly _tabPatterns: _angular_core.Signal<TabPattern[] | undefined>;
93-
readonly _unorderedTabpanelPatterns: _angular_core.Signal<TabPanelPattern[]>;
97+
findTabPanel(value?: string): TabPanel | undefined;
98+
// (undocumented)
99+
_registerList(list: TabList): void;
100+
// (undocumented)
101+
_registerPanel(panel: TabPanel): void;
102+
// (undocumented)
103+
_unregisterList(list: TabList): void;
94104
// (undocumented)
95-
_unregister(child: TabList | TabPanel): void;
105+
_unregisterPanel(panel: TabPanel): void;
96106
// (undocumented)
97107
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<Tabs, "[ngTabs]", ["ngTabs"], {}, {}, never, never, true, never>;
98108
// (undocumented)

src/aria/private/tabs/tabs.spec.ts

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -65,37 +65,32 @@ describe('Tabs Pattern', () => {
6565
softDisabled: signal(true),
6666
items: signal([]),
6767
element: signal(document.createElement('div')),
68+
selectedTab: signal(undefined),
6869
};
6970
tabListPattern = new TabListPattern(tabListInputs);
7071

7172
// Initiate a list of TabPatterns.
7273
tabInputs = [
7374
{
74-
tablist: signal(tabListPattern),
75-
tabpanel: signal(undefined),
75+
tabList: signal(tabListPattern),
76+
tabPanel: signal(undefined),
7677
id: signal('tab-1-id'),
7778
element: signal(createTabElement()),
7879
disabled: signal(false),
79-
value: signal('tab-1'),
80-
expanded: signal(false),
8180
},
8281
{
83-
tablist: signal(tabListPattern),
84-
tabpanel: signal(undefined),
82+
tabList: signal(tabListPattern),
83+
tabPanel: signal(undefined),
8584
id: signal('tab-2-id'),
8685
element: signal(createTabElement()),
8786
disabled: signal(false),
88-
value: signal('tab-2'),
89-
expanded: signal(false),
9087
},
9188
{
92-
tablist: signal(tabListPattern),
93-
tabpanel: signal(undefined),
89+
tabList: signal(tabListPattern),
90+
tabPanel: signal(undefined),
9491
id: signal('tab-3-id'),
9592
element: signal(createTabElement()),
9693
disabled: signal(false),
97-
value: signal('tab-3'),
98-
expanded: signal(false),
9994
},
10095
];
10196
tabPatterns = [
@@ -109,17 +104,14 @@ describe('Tabs Pattern', () => {
109104
{
110105
id: signal('tabpanel-1-id'),
111106
tab: signal(undefined),
112-
value: signal('tab-1'),
113107
},
114108
{
115109
id: signal('tabpanel-2-id'),
116110
tab: signal(undefined),
117-
value: signal('tab-2'),
118111
},
119112
{
120113
id: signal('tabpanel-3-id'),
121114
tab: signal(undefined),
122-
value: signal('tab-3'),
123115
},
124116
];
125117
tabPanelPatterns = [
@@ -129,9 +121,9 @@ describe('Tabs Pattern', () => {
129121
];
130122

131123
// Binding between tabs and tabpanels.
132-
tabInputs[0].tabpanel.set(tabPanelPatterns[0]);
133-
tabInputs[1].tabpanel.set(tabPanelPatterns[1]);
134-
tabInputs[2].tabpanel.set(tabPanelPatterns[2]);
124+
tabInputs[0].tabPanel.set(tabPanelPatterns[0]);
125+
tabInputs[1].tabPanel.set(tabPanelPatterns[1]);
126+
tabInputs[2].tabPanel.set(tabPanelPatterns[2]);
135127
tabPanelInputs[0].tab.set(tabPatterns[0]);
136128
tabPanelInputs[1].tab.set(tabPatterns[1]);
137129
tabPanelInputs[2].tab.set(tabPatterns[2]);
@@ -143,8 +135,8 @@ describe('Tabs Pattern', () => {
143135
describe('#open', () => {
144136
it('should open a tab with value', () => {
145137
expect(tabListPattern.selectedTab()).toBeUndefined();
146-
tabListPattern.open('tab-1');
147-
expect(tabListPattern.selectedTab()!.value()).toBe('tab-1');
138+
tabListPattern.open(tabPatterns[0]);
139+
expect(tabListPattern.selectedTab()!).toBe(tabPatterns[0]);
148140
});
149141

150142
it('should open a tab with tab pattern instance', () => {

0 commit comments

Comments
 (0)