Skip to content

Commit 266db1f

Browse files
committed
refactor(aria/toolbar): remove selection behavior
1 parent de579cc commit 266db1f

29 files changed

Lines changed: 686 additions & 604 deletions

goldens/aria/private/index.api.md

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -642,85 +642,80 @@ export class TabPattern {
642642
}
643643

644644
// @public
645-
export type ToolbarInputs<V> = Omit<ListInputs<ToolbarWidgetPattern<V>, V>, 'multi' | 'typeaheadDelay' | 'selectionMode' | 'focusMode'> & {
646-
getItem: (e: Element) => ToolbarWidgetPattern<V> | undefined;
645+
export type ToolbarInputs = {
646+
element: SignalLike<HTMLElement | undefined>;
647+
activeItem: WritableSignalLike<ToolbarWidgetPattern | undefined>;
648+
items: SignalLike<ToolbarWidgetPattern[]>;
649+
softDisabled: SignalLike<boolean>;
650+
disabled: SignalLike<boolean>;
651+
orientation: SignalLike<'vertical' | 'horizontal'>;
652+
textDirection: SignalLike<'rtl' | 'ltr'>;
653+
wrap: SignalLike<boolean>;
654+
getItem: (e: Element) => ToolbarWidgetPattern | undefined;
647655
};
648656

649657
// @public
650-
export class ToolbarPattern<V> {
651-
constructor(inputs: ToolbarInputs<V>);
658+
export class ToolbarPattern {
659+
constructor(inputs: ToolbarInputs);
652660
readonly activeDescendant: SignalLike<string | undefined>;
653-
readonly activeItem: () => ToolbarWidgetPattern<V> | undefined;
661+
readonly activeItem: () => ToolbarWidgetPattern | undefined;
654662
readonly disabled: SignalLike<boolean>;
663+
readonly focusManager: ListFocus<ToolbarWidgetPattern>;
655664
readonly hasBeenInteracted: WritableSignalLike<boolean>;
656665
// (undocumented)
657-
readonly inputs: ToolbarInputs<V>;
658-
readonly listBehavior: List<ToolbarWidgetPattern<V>, V>;
666+
readonly inputs: ToolbarInputs;
667+
readonly navigationBehavior: ListNavigation<ToolbarWidgetPattern>;
659668
onClick(event: MouseEvent): void;
660669
// (undocumented)
661670
onFocusIn(): void;
662671
onKeydown(event: KeyboardEvent): void;
663672
// (undocumented)
664673
onPointerdown(event: PointerEvent): void;
665674
readonly orientation: SignalLike<'vertical' | 'horizontal'>;
666-
// (undocumented)
667-
select(): void;
668675
setDefaultState(): void;
669676
setDefaultStateEffect(): void;
670677
readonly softDisabled: SignalLike<boolean>;
671678
readonly tabIndex: SignalLike<-1 | 0>;
672-
validate(): string[];
673679
}
674680

675681
// @public
676-
export interface ToolbarWidgetGroupInputs<T extends ListItem<V>, V> {
682+
export interface ToolbarWidgetGroupInputs<T = ToolbarWidgetPattern> {
677683
disabled: SignalLike<boolean>;
678684
items: SignalLike<T[]>;
679-
multi: SignalLike<boolean>;
680-
toolbar: SignalLike<ToolbarPattern<V> | undefined>;
685+
toolbar: SignalLike<ToolbarPattern | undefined>;
681686
}
682687

683688
// @public
684-
export class ToolbarWidgetGroupPattern<T extends ListItem<V>, V> {
685-
constructor(inputs: ToolbarWidgetGroupInputs<T, V>);
689+
export class ToolbarWidgetGroupPattern<T = ToolbarWidgetPattern> {
690+
constructor(inputs: ToolbarWidgetGroupInputs<T>);
686691
readonly disabled: () => boolean;
687692
// (undocumented)
688-
readonly element: () => undefined;
689-
// (undocumented)
690-
readonly inputs: ToolbarWidgetGroupInputs<T, V>;
691-
readonly multi: () => boolean;
692-
// (undocumented)
693-
readonly searchTerm: () => string;
694-
// (undocumented)
695-
readonly selectable: () => boolean;
696-
readonly toolbar: () => ToolbarPattern<V> | undefined;
697-
// (undocumented)
698-
readonly value: () => V;
693+
readonly inputs: ToolbarWidgetGroupInputs<T>;
694+
readonly toolbar: () => ToolbarPattern | undefined;
699695
}
700696

701697
// @public
702-
export interface ToolbarWidgetInputs<V> extends Omit<ListItem<V>, 'searchTerm' | 'index' | 'selectable'> {
703-
group: SignalLike<ToolbarWidgetGroupPattern<ToolbarWidgetPattern<V>, V> | undefined>;
704-
toolbar: SignalLike<ToolbarPattern<V>>;
698+
export interface ToolbarWidgetInputs {
699+
disabled: SignalLike<boolean>;
700+
element: SignalLike<HTMLElement | undefined>;
701+
group: SignalLike<ToolbarWidgetGroupPattern | undefined>;
702+
id: SignalLike<string>;
703+
toolbar: SignalLike<ToolbarPattern>;
705704
}
706705

707706
// @public (undocumented)
708-
export class ToolbarWidgetPattern<V> implements ListItem<V> {
709-
constructor(inputs: ToolbarWidgetInputs<V>);
707+
export class ToolbarWidgetPattern implements ListFocusItem, ListNavigationItem {
708+
constructor(inputs: ToolbarWidgetInputs);
710709
readonly active: SignalLike<boolean>;
711710
readonly disabled: () => boolean;
712711
readonly element: () => HTMLElement | undefined;
713-
readonly group: () => ToolbarWidgetGroupPattern<ToolbarWidgetPattern<V>, V> | undefined;
712+
readonly group: () => ToolbarWidgetGroupPattern<ToolbarWidgetPattern> | undefined;
714713
readonly id: () => string;
715714
readonly index: SignalLike<number>;
716715
// (undocumented)
717-
readonly inputs: ToolbarWidgetInputs<V>;
718-
readonly searchTerm: () => string;
719-
readonly selectable: () => boolean;
720-
readonly selected: SignalLike<boolean>;
716+
readonly inputs: ToolbarWidgetInputs;
721717
readonly tabIndex: SignalLike<-1 | 0>;
722-
readonly toolbar: () => ToolbarPattern<V>;
723-
readonly value: () => V;
718+
readonly toolbar: () => ToolbarPattern;
724719
}
725720

726721
// @public

goldens/aria/toolbar/index.api.md

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,62 +12,58 @@ import { OnInit } from '@angular/core';
1212
import { Signal } from '@angular/core';
1313

1414
// @public
15-
export class Toolbar<V> implements OnDestroy {
15+
export class Toolbar implements OnDestroy {
1616
constructor();
17-
readonly _collection: SortedCollection<ToolbarWidget<V>>;
17+
readonly _collection: SortedCollection<ToolbarWidget>;
1818
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
1919
readonly element: HTMLElement;
20-
readonly _itemPatterns: _angular_core.Signal<ToolbarWidgetPattern<V>[]>;
20+
readonly _itemPatterns: _angular_core.Signal<ToolbarWidgetPattern[]>;
2121
// (undocumented)
2222
ngOnDestroy(): void;
2323
readonly orientation: _angular_core.InputSignal<"horizontal" | "vertical">;
24-
readonly _pattern: ToolbarPattern<V>;
24+
readonly _pattern: ToolbarPattern;
2525
readonly softDisabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
2626
readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>;
27-
readonly value: _angular_core.ModelSignal<V[]>;
2827
readonly wrap: _angular_core.InputSignalWithTransform<boolean, unknown>;
2928
// (undocumented)
30-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<Toolbar<any>, "[ngToolbar]", ["ngToolbar"], { "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>;
29+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<Toolbar, "[ngToolbar]", ["ngToolbar"], { "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
3130
// (undocumented)
32-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Toolbar<any>, never>;
31+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Toolbar, never>;
3332
}
3433

3534
// @public
36-
export const TOOLBAR_WIDGET_GROUP: InjectionToken<ToolbarWidgetGroup<unknown>>;
35+
export const TOOLBAR_WIDGET_GROUP: InjectionToken<ToolbarWidgetGroup>;
3736

3837
// @public
39-
export class ToolbarWidget<V> implements OnInit, OnDestroy {
38+
export class ToolbarWidget implements OnInit, OnDestroy {
4039
readonly active: _angular_core.Signal<boolean>;
4140
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
4241
readonly element: HTMLElement;
43-
readonly _group: ToolbarWidgetGroup<V> | null;
42+
readonly _group: ToolbarWidgetGroup | null;
4443
readonly hardDisabled: _angular_core.Signal<boolean>;
4544
readonly id: _angular_core.InputSignal<string>;
4645
// (undocumented)
4746
ngOnDestroy(): void;
4847
// (undocumented)
4948
ngOnInit(): void;
50-
readonly _pattern: ToolbarWidgetPattern<V>;
51-
readonly selected: () => boolean;
52-
readonly _toolbarPattern: _angular_core.Signal<ToolbarPattern<V>>;
53-
readonly value: _angular_core.InputSignal<V>;
49+
readonly _pattern: ToolbarWidgetPattern;
50+
readonly _toolbarPattern: _angular_core.Signal<ToolbarPattern>;
5451
// (undocumented)
55-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ToolbarWidget<any>, "[ngToolbarWidget]", ["ngToolbarWidget"], { "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>;
52+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ToolbarWidget, "[ngToolbarWidget]", ["ngToolbarWidget"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
5653
// (undocumented)
57-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ToolbarWidget<any>, never>;
54+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ToolbarWidget, never>;
5855
}
5956

6057
// @public
61-
export class ToolbarWidgetGroup<V> {
58+
export class ToolbarWidgetGroup {
6259
constructor();
6360
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
6461
readonly element: HTMLElement;
65-
readonly multi: _angular_core.InputSignalWithTransform<boolean, unknown>;
66-
readonly _pattern: ToolbarWidgetGroupPattern<ToolbarWidgetPattern<V>, V>;
62+
readonly _pattern: ToolbarWidgetGroupPattern<ToolbarWidgetPattern>;
6763
// (undocumented)
68-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ToolbarWidgetGroup<any>, "[ngToolbarWidgetGroup]", ["ngToolbarWidgetGroup"], { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "multi": { "alias": "multi"; "required": false; "isSignal": true; }; }, {}, ["_widgets"], never, true, never>;
64+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<ToolbarWidgetGroup, "[ngToolbarWidgetGroup]", ["ngToolbarWidgetGroup"], { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, ["_widgets"], never, true, never>;
6965
// (undocumented)
70-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ToolbarWidgetGroup<any>, never>;
66+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ToolbarWidgetGroup, never>;
7167
}
7268

7369
// (No @packageDocumentation comment for this package)

src/aria/private/toolbar/BUILD.bazel

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ ts_project(
1212
deps = [
1313
"//:node_modules/@angular/core",
1414
"//src/aria/private/behaviors/event-manager",
15-
"//src/aria/private/behaviors/list",
15+
"//src/aria/private/behaviors/list-focus",
16+
"//src/aria/private/behaviors/list-navigation",
1617
"//src/aria/private/behaviors/signal-like",
1718
"//src/cdk/platform",
1819
],

src/aria/private/toolbar/toolbar-widget-group.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,29 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {ListItem} from '../behaviors/list/list';
109
import {SignalLike} from '../behaviors/signal-like/signal-like';
1110
import type {ToolbarPattern} from './toolbar';
11+
import type {ToolbarWidgetPattern} from './toolbar-widget';
1212

1313
/** Represents the required inputs for a toolbar widget group. */
14-
export interface ToolbarWidgetGroupInputs<T extends ListItem<V>, V> {
14+
export interface ToolbarWidgetGroupInputs<T = ToolbarWidgetPattern> {
1515
/** A reference to the parent toolbar. */
16-
toolbar: SignalLike<ToolbarPattern<V> | undefined>;
16+
toolbar: SignalLike<ToolbarPattern | undefined>;
1717

1818
/** Whether the widget group is disabled. */
1919
disabled: SignalLike<boolean>;
2020

2121
/** The list of items within the widget group. */
2222
items: SignalLike<T[]>;
23-
24-
/** Whether the group allows multiple widgets to be selected. */
25-
multi: SignalLike<boolean>;
2623
}
2724

2825
/** A group of widgets within a toolbar that provides nested navigation. */
29-
export class ToolbarWidgetGroupPattern<T extends ListItem<V>, V> {
26+
export class ToolbarWidgetGroupPattern<T = ToolbarWidgetPattern> {
3027
/** Whether the widget is disabled. */
3128
readonly disabled = () => this.inputs.disabled();
3229

3330
/** A reference to the parent toolbar. */
3431
readonly toolbar = () => this.inputs.toolbar();
3532

36-
/** Whether the group allows multiple widgets to be selected. */
37-
readonly multi = () => this.inputs.multi();
38-
39-
readonly searchTerm = () => ''; // Unused because toolbar does not support typeahead.
40-
readonly value = () => '' as V; // Unused because toolbar does not support selection.
41-
readonly selectable = () => true; // Unused because toolbar does not support selection.
42-
readonly element = () => undefined; // Unused because toolbar does not focus the group element.
43-
44-
constructor(readonly inputs: ToolbarWidgetGroupInputs<T, V>) {}
33+
constructor(readonly inputs: ToolbarWidgetGroupInputs<T>) {}
4534
}

src/aria/private/toolbar/toolbar-widget.ts

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,30 @@
77
*/
88

99
import {SignalLike, computed} from '../behaviors/signal-like/signal-like';
10-
import {ListItem} from '../behaviors/list/list';
10+
import {ListFocusItem} from '../behaviors/list-focus/list-focus';
11+
import {ListNavigationItem} from '../behaviors/list-navigation/list-navigation';
1112
import type {ToolbarPattern} from './toolbar';
1213
import {ToolbarWidgetGroupPattern} from './toolbar-widget-group';
1314

1415
/** Represents the required inputs for a toolbar widget in a toolbar. */
15-
export interface ToolbarWidgetInputs<V> extends Omit<
16-
ListItem<V>,
17-
'searchTerm' | 'index' | 'selectable'
18-
> {
16+
export interface ToolbarWidgetInputs {
17+
/** A unique identifier for the widget. */
18+
id: SignalLike<string>;
19+
20+
/** The html element that should receive focus. */
21+
element: SignalLike<HTMLElement | undefined>;
22+
23+
/** Whether the widget is disabled. */
24+
disabled: SignalLike<boolean>;
25+
1926
/** A reference to the parent toolbar. */
20-
toolbar: SignalLike<ToolbarPattern<V>>;
27+
toolbar: SignalLike<ToolbarPattern>;
2128

2229
/** A reference to the parent widget group. */
23-
group: SignalLike<ToolbarWidgetGroupPattern<ToolbarWidgetPattern<V>, V> | undefined>;
30+
group: SignalLike<ToolbarWidgetGroupPattern | undefined>;
2431
}
2532

26-
export class ToolbarWidgetPattern<V> implements ListItem<V> {
33+
export class ToolbarWidgetPattern implements ListFocusItem, ListNavigationItem {
2734
/** A unique identifier for the widget. */
2835
readonly id = () => this.inputs.id();
2936

@@ -40,27 +47,13 @@ export class ToolbarWidgetPattern<V> implements ListItem<V> {
4047
readonly toolbar = () => this.inputs.toolbar();
4148

4249
/** The tabindex of the widget. */
43-
readonly tabIndex = computed(() => this.toolbar().listBehavior.getItemTabindex(this));
44-
45-
/** The text used by the typeahead search. */
46-
readonly searchTerm = () => ''; // Unused because toolbar does not support typeahead.
47-
48-
/** The value associated with the widget. */
49-
readonly value = () => this.inputs.value();
50-
51-
/** Whether the widget is selectable. */
52-
readonly selectable = () => true; // Unused because toolbar does not support selection.
50+
readonly tabIndex = computed(() => this.toolbar().focusManager.getItemTabIndex(this));
5351

5452
/** The position of the widget within the toolbar. */
5553
readonly index = computed(() => this.toolbar().inputs.items().indexOf(this) ?? -1);
5654

57-
/** Whether the widget is selected (only relevant in a selection group). */
58-
readonly selected = computed(() =>
59-
this.toolbar().listBehavior.inputs.value().includes(this.value()),
60-
);
61-
6255
/** Whether the widget is currently the active one (focused). */
6356
readonly active: SignalLike<boolean> = computed(() => this.toolbar().activeItem() === this);
6457

65-
constructor(readonly inputs: ToolbarWidgetInputs<V>) {}
58+
constructor(readonly inputs: ToolbarWidgetInputs) {}
6659
}

0 commit comments

Comments
 (0)