Skip to content

Commit 0b81ad7

Browse files
authored
refactor(aria/toolbar): remove selection behavior (#33747)
1 parent ab16b1f commit 0b81ad7

30 files changed

Lines changed: 688 additions & 607 deletions

‎goldens/aria/private/index.api.md‎

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -641,85 +641,80 @@ export class TabPattern {
641641
}
642642

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

648656
// @public
649-
export class ToolbarPattern<V> {
650-
constructor(inputs: ToolbarInputs<V>);
657+
export class ToolbarPattern {
658+
constructor(inputs: ToolbarInputs);
651659
readonly activeDescendant: SignalLike<string | undefined>;
652-
readonly activeItem: () => ToolbarWidgetPattern<V> | undefined;
660+
readonly activeItem: () => ToolbarWidgetPattern | undefined;
653661
readonly disabled: SignalLike<boolean>;
662+
readonly focusManager: ListFocus<ToolbarWidgetPattern>;
654663
readonly hasBeenInteracted: WritableSignalLike<boolean>;
655664
// (undocumented)
656-
readonly inputs: ToolbarInputs<V>;
657-
readonly listBehavior: List<ToolbarWidgetPattern<V>, V>;
665+
readonly inputs: ToolbarInputs;
666+
readonly navigationBehavior: ListNavigation<ToolbarWidgetPattern>;
658667
onClick(event: MouseEvent): void;
659668
// (undocumented)
660669
onFocusIn(): void;
661670
onKeydown(event: KeyboardEvent): void;
662671
// (undocumented)
663672
onPointerdown(event: PointerEvent): void;
664673
readonly orientation: SignalLike<'vertical' | 'horizontal'>;
665-
// (undocumented)
666-
select(): void;
667674
setDefaultState(): void;
668675
setDefaultStateEffect(): void;
669676
readonly softDisabled: SignalLike<boolean>;
670677
readonly tabIndex: SignalLike<-1 | 0>;
671-
validate(): string[];
672678
}
673679

674680
// @public
675-
export interface ToolbarWidgetGroupInputs<T extends ListItem<V>, V> {
681+
export interface ToolbarWidgetGroupInputs {
676682
disabled: SignalLike<boolean>;
677-
items: SignalLike<T[]>;
678-
multi: SignalLike<boolean>;
679-
toolbar: SignalLike<ToolbarPattern<V> | undefined>;
683+
items: SignalLike<ToolbarWidgetPattern[]>;
684+
toolbar: SignalLike<ToolbarPattern | undefined>;
680685
}
681686

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

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

706705
// @public (undocumented)
707-
export class ToolbarWidgetPattern<V> implements ListItem<V> {
708-
constructor(inputs: ToolbarWidgetInputs<V>);
706+
export class ToolbarWidgetPattern implements ListFocusItem, ListNavigationItem {
707+
constructor(inputs: ToolbarWidgetInputs);
709708
readonly active: SignalLike<boolean>;
710709
readonly disabled: () => boolean;
711710
readonly element: () => HTMLElement | undefined;
712-
readonly group: () => ToolbarWidgetGroupPattern<ToolbarWidgetPattern<V>, V> | undefined;
711+
readonly group: () => ToolbarWidgetGroupPattern | undefined;
713712
readonly id: () => string;
714713
readonly index: SignalLike<number>;
715714
// (undocumented)
716-
readonly inputs: ToolbarWidgetInputs<V>;
717-
readonly searchTerm: () => string;
718-
readonly selectable: () => boolean;
719-
readonly selected: SignalLike<boolean>;
715+
readonly inputs: ToolbarWidgetInputs;
720716
readonly tabIndex: SignalLike<-1 | 0>;
721-
readonly toolbar: () => ToolbarPattern<V>;
722-
readonly value: () => V;
717+
readonly toolbar: () => ToolbarPattern;
723718
}
724719

725720
// @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;
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/public-api.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ export * from './toolbar/toolbar';
1515
export * from './toolbar/toolbar-widget';
1616
export * from './toolbar/toolbar-widget-group';
1717
export * from './accordion/accordion';
18-
export * from './toolbar/toolbar';
1918
export * from './tree/tree';
2019
export * from './grid/grid';
2120
export * from './grid/row';

‎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: 6 additions & 17 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 {
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. */
22-
items: SignalLike<T[]>;
23-
24-
/** Whether the group allows multiple widgets to be selected. */
25-
multi: SignalLike<boolean>;
22+
items: SignalLike<ToolbarWidgetPattern[]>;
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 {
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) {}
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)