77 */
88
99import { KeyboardEventManager , PointerEventManager } from '../behaviors/event-manager' ;
10- import { ExpansionItem , ListExpansionInputs , ListExpansion } from '../behaviors/expansion/expansion' ;
10+ import { ExpansionItem , ListExpansion , ListExpansionInputs } from '../behaviors/expansion/expansion' ;
1111import {
1212 SignalLike ,
13- computed ,
14- signal ,
1513 WritableSignalLike ,
14+ computed ,
15+ linkedSignal ,
1616} from '../behaviors/signal-like/signal-like' ;
1717import { LabelControl , LabelControlOptionalInputs } from '../behaviors/label/label' ;
1818import { ListFocus } from '../behaviors/list-focus/list-focus' ;
1919import {
20- ListNavigationItem ,
2120 ListNavigation ,
2221 ListNavigationInputs ,
22+ ListNavigationItem ,
2323} from '../behaviors/list-navigation/list-navigation' ;
2424
2525/** The required inputs to tabs. */
2626export interface TabInputs
27- extends Omit < ListNavigationItem , 'index' > , Omit < ExpansionItem , 'expandable' > {
27+ extends Omit < ListNavigationItem , 'index' > , Omit < ExpansionItem , 'expandable' | 'expanded' > {
2828 /** The parent tablist that controls the tab. */
2929 tablist : SignalLike < TabListPattern > ;
3030
3131 /** The remote tabpanel controlled by the tab. */
3232 tabpanel : SignalLike < TabPanelPattern | undefined > ;
33-
34- /** The remote tabpanel unique identifier. */
35- value : SignalLike < string > ;
3633}
3734
3835/** A tab in a tablist. */
@@ -43,9 +40,6 @@ export class TabPattern {
4340 /** The index of the tab. */
4441 readonly index = computed ( ( ) => this . inputs . tablist ( ) . inputs . items ( ) . indexOf ( this ) ) ;
4542
46- /** The remote tabpanel unique identifier. */
47- readonly value : SignalLike < string > = ( ) => this . inputs . value ( ) ;
48-
4943 /** Whether the tab is disabled. */
5044 readonly disabled : SignalLike < boolean > = ( ) => this . inputs . disabled ( ) ;
5145
@@ -55,8 +49,15 @@ export class TabPattern {
5549 /** Whether this tab has expandable panel. */
5650 readonly expandable : SignalLike < boolean > = ( ) => true ;
5751
58- /** Whether the tab panel is expanded. */
59- readonly expanded : WritableSignalLike < boolean > ;
52+ /*
53+ * Whether the tab panel is expanded.
54+ * Primarily controlled by the behavior, which will read/write this value.
55+ * The consumer of this pattern will instead only use the selectedTab input.
56+ * The pattern will be responsible for synchronizing their state.
57+ */
58+ readonly expanded : WritableSignalLike < boolean > = linkedSignal (
59+ ( ) => this . inputs . tablist ( ) . selectedTab ( ) === this ,
60+ ) ;
6061
6162 /** Whether the tab is active. */
6263 readonly active = computed ( ( ) => this . inputs . tablist ( ) . inputs . activeItem ( ) === this ) ;
@@ -70,9 +71,7 @@ export class TabPattern {
7071 /** The id of the tabpanel associated with the tab. */
7172 readonly controls = computed ( ( ) => this . inputs . tabpanel ( ) ?. id ( ) ) ;
7273
73- constructor ( readonly inputs : TabInputs ) {
74- this . expanded = inputs . expanded ;
75- }
74+ constructor ( readonly inputs : TabInputs ) { }
7675
7776 /** Opens the tab. */
7877 open ( ) : boolean {
@@ -87,19 +86,13 @@ export interface TabPanelInputs extends LabelControlOptionalInputs {
8786
8887 /** The tab that controls this tabpanel. */
8988 tab : SignalLike < TabPattern | undefined > ;
90-
91- /** A local unique identifier for the tabpanel. */
92- value : SignalLike < string > ;
9389}
9490
9591/** A tabpanel associated with a tab. */
9692export class TabPanelPattern {
9793 /** A global unique identifier for the tabpanel. */
9894 readonly id : SignalLike < string > = ( ) => this . inputs . id ( ) ;
9995
100- /** A local unique identifier for the tabpanel. */
101- readonly value : SignalLike < string > = ( ) => this . inputs . value ( ) ;
102-
10396 /** Controls label for this tabpanel. */
10497 readonly labelManager : LabelControl ;
10598
@@ -131,6 +124,9 @@ export interface TabListInputs
131124 Omit < ListExpansionInputs , 'multiExpandable' | 'items' > {
132125 /** The selection strategy used by the tablist. */
133126 selectionMode : SignalLike < 'follow' | 'explicit' > ;
127+
128+ /** The currently selected tab. */
129+ selectedTab : WritableSignalLike < TabPattern | undefined > ;
134130}
135131
136132/** Controls the state of a tablist. */
@@ -148,7 +144,7 @@ export class TabListPattern {
148144 readonly activeTab : SignalLike < TabPattern | undefined > = ( ) => this . inputs . activeItem ( ) ;
149145
150146 /** The currently selected tab. */
151- readonly selectedTab : WritableSignalLike < TabPattern | undefined > = signal ( undefined ) ;
147+ readonly selectedTab : WritableSignalLike < TabPattern | undefined > ;
152148
153149 /** Whether the tablist is vertically or horizontally oriented. */
154150 readonly orientation : SignalLike < 'vertical' | 'horizontal' > = ( ) => this . inputs . orientation ( ) ;
@@ -208,6 +204,8 @@ export class TabListPattern {
208204 } ) ;
209205
210206 constructor ( readonly inputs : TabListInputs ) {
207+ this . selectedTab = inputs . selectedTab ;
208+
211209 this . focusBehavior = new ListFocus ( inputs ) ;
212210
213211 this . navigationBehavior = new ListNavigation ( {
@@ -263,19 +261,11 @@ export class TabListPattern {
263261 }
264262 }
265263
266- /** Opens the tab by given value. */
267- open ( value : string ) : boolean ;
268-
269264 /** Opens the given tab or the current active tab. */
270265 open ( tab ?: TabPattern ) : boolean ;
271-
272- open ( tab : TabPattern | string | undefined ) : boolean {
266+ open ( tab : TabPattern | undefined ) : boolean {
273267 tab ??= this . activeTab ( ) ;
274268
275- if ( typeof tab === 'string' ) {
276- tab = this . inputs . items ( ) . find ( t => t . value ( ) === tab ) ;
277- }
278-
279269 if ( tab === undefined ) return false ;
280270
281271 const success = this . expansionBehavior . open ( tab ) ;
0 commit comments