Skip to content

Commit a7a805e

Browse files
committed
refactor(multiple): add types for string-based enum inputs
1 parent 03b0def commit a7a805e

File tree

32 files changed

+176
-87
lines changed

32 files changed

+176
-87
lines changed

src/aria/combobox/combobox.spec.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import {Component, computed, DebugElement, signal} from '@angular/core';
22
import {ComponentFixture, TestBed} from '@angular/core/testing';
33
import {By} from '@angular/platform-browser';
4-
import {Combobox, ComboboxInput, ComboboxPopup, ComboboxPopupContainer} from '../combobox';
4+
import {
5+
Combobox,
6+
ComboboxInput,
7+
ComboboxPopup,
8+
ComboboxFilterMode,
9+
ComboboxPopupContainer,
10+
} from '../combobox';
511
import {Listbox, Option} from '../listbox';
612
import {runAccessibilityChecks} from '@angular/cdk/testing/private';
713
import {Tree, TreeItem, TreeItemGroup} from '../tree';
@@ -52,9 +58,7 @@ describe('Combobox', () => {
5258
const enter = (modifierKeys?: {}) => keydown('Enter', modifierKeys);
5359
const escape = (modifierKeys?: {}) => keydown('Escape', modifierKeys);
5460

55-
function setupCombobox(
56-
opts: {readonly?: boolean; filterMode?: 'manual' | 'auto-select' | 'highlight'} = {},
57-
) {
61+
function setupCombobox(opts: {readonly?: boolean; filterMode?: ComboboxFilterMode} = {}) {
5862
TestBed.configureTestingModule({});
5963
fixture = TestBed.createComponent(ComboboxListboxExample);
6064
const testComponent = fixture.componentInstance;
@@ -605,9 +609,7 @@ describe('Combobox', () => {
605609
const enter = (modifierKeys?: {}) => keydown('Enter', modifierKeys);
606610
const escape = (modifierKeys?: {}) => keydown('Escape', modifierKeys);
607611

608-
function setupCombobox(
609-
opts: {readonly?: boolean; filterMode?: 'manual' | 'auto-select' | 'highlight'} = {},
610-
) {
612+
function setupCombobox(opts: {readonly?: boolean; filterMode?: ComboboxFilterMode} = {}) {
611613
TestBed.configureTestingModule({});
612614
fixture = TestBed.createComponent(ComboboxTreeExample);
613615
const testComponent = fixture.componentInstance;
@@ -1126,7 +1128,7 @@ class ComboboxListboxExample {
11261128
readonly = signal(false);
11271129
searchString = signal('');
11281130
values = signal<string[]>([]);
1129-
filterMode = signal<'manual' | 'auto-select' | 'highlight'>('manual');
1131+
filterMode = signal<ComboboxFilterMode>('manual');
11301132

11311133
options = computed(() =>
11321134
states.filter(state => state.toLowerCase().startsWith(this.searchString().toLowerCase())),
@@ -1197,7 +1199,7 @@ class ComboboxTreeExample {
11971199
searchString = signal('');
11981200
values = signal<string[]>([]);
11991201
nodes = computed(() => this.filterTreeNodes(TREE_NODES));
1200-
filterMode = signal<'manual' | 'auto-select' | 'highlight'>('manual');
1202+
filterMode = signal<ComboboxFilterMode>('manual');
12011203

12021204
firstMatch = computed<string | undefined>(() => {
12031205
const flatNodes = this.flattenTreeNodes(this.nodes());

src/aria/combobox/combobox.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ import {
2727
ComboboxListboxControls,
2828
ComboboxTreeControls,
2929
ComboboxDialogPattern,
30+
ComboboxFilterMode,
3031
} from '@angular/aria/private';
3132
import {Directionality} from '@angular/cdk/bidi';
3233
import {toSignal} from '@angular/core/rxjs-interop';
3334

35+
export {ComboboxFilterMode};
36+
3437
/**
3538
* @developerPreview 21.0
3639
*/
@@ -71,7 +74,7 @@ export class Combobox<V> {
7174
readonly popup = contentChild<ComboboxPopup<V>>(ComboboxPopup);
7275

7376
/** The filter mode for the combobox. */
74-
filterMode = input<'manual' | 'auto-select' | 'highlight'>('manual');
77+
filterMode = input<ComboboxFilterMode>('manual');
7578

7679
/** Whether the combobox is disabled. */
7780
readonly disabled = input(false, {transform: booleanAttribute});

src/aria/combobox/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ export {
1212
ComboboxInput,
1313
ComboboxPopup,
1414
ComboboxPopupContainer,
15+
ComboboxFilterMode,
1516
} from './combobox';

src/aria/grid/grid.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,17 @@ import {
2121
Signal,
2222
} from '@angular/core';
2323
import {Directionality} from '@angular/cdk/bidi';
24-
import {GridPattern, GridRowPattern, GridCellPattern, GridCellWidgetPattern} from '../private';
24+
import {
25+
GridPattern,
26+
GridRowPattern,
27+
GridCellPattern,
28+
GridCellWidgetPattern,
29+
GridFocusMode,
30+
GridWrapStrategy,
31+
GridSelectionMode,
32+
} from '../private';
33+
34+
export {GridFocusMode, GridWrapStrategy, GridSelectionMode};
2535

2636
/**
2737
* A directive that provides grid-based navigation and selection behavior.
@@ -73,19 +83,19 @@ export class Grid {
7383
readonly softDisabled = input(true, {transform: booleanAttribute});
7484

7585
/** The focus strategy used by the grid. */
76-
readonly focusMode = input<'roving' | 'activedescendant'>('roving');
86+
readonly focusMode = input<GridFocusMode>('roving');
7787

7888
/** The wrapping behavior for keyboard navigation along the row axis. */
79-
readonly rowWrap = input<'continuous' | 'loop' | 'nowrap'>('loop');
89+
readonly rowWrap = input<GridWrapStrategy>('loop');
8090

8191
/** The wrapping behavior for keyboard navigation along the column axis. */
82-
readonly colWrap = input<'continuous' | 'loop' | 'nowrap'>('loop');
92+
readonly colWrap = input<GridWrapStrategy>('loop');
8393

8494
/** Whether multiple cells in the grid can be selected. */
8595
readonly multi = input(false, {transform: booleanAttribute});
8696

8797
/** The selection strategy used by the grid. */
88-
readonly selectionMode = input<'follow' | 'explicit'>('follow');
98+
readonly selectionMode = input<GridSelectionMode>('follow');
8999

90100
/** Whether enable range selections (with modifier keys or dragging). */
91101
readonly enableRangeSelection = input(false, {transform: booleanAttribute});
@@ -123,6 +133,8 @@ export class Grid {
123133
}
124134
}
125135

136+
export type GridRowRole = 'row' | 'rowheader';
137+
126138
/**
127139
* A directive that represents a row in a grid.
128140
*
@@ -158,7 +170,7 @@ export class GridRow {
158170
readonly element = computed(() => this._elementRef.nativeElement);
159171

160172
/** The ARIA role for the row. */
161-
readonly role = input<'row' | 'rowheader'>('row');
173+
readonly role = input<GridRowRole>('row');
162174

163175
/** The index of this row within the grid. */
164176
readonly rowIndex = input<number>();
@@ -170,6 +182,8 @@ export class GridRow {
170182
});
171183
}
172184

185+
export type GridCellRole = 'gridcell' | 'columnheader';
186+
173187
/**
174188
* A directive that represents a cell in a grid.
175189
*
@@ -217,7 +231,7 @@ export class GridCell {
217231
readonly element = computed(() => this._elementRef.nativeElement);
218232

219233
/** The ARIA role for the cell. */
220-
readonly role = input<'gridcell' | 'columnheader'>('gridcell');
234+
readonly role = input<GridCellRole>('gridcell');
221235

222236
/** The number of rows the cell should span. */
223237
readonly rowSpan = input<number>(1);

src/aria/listbox/listbox.spec.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Component, DebugElement, signal} from '@angular/core';
2-
import {Listbox, Option} from './listbox';
2+
import {Listbox, Option, ListOrientation, ListSelectionMode, ListFocusMode} from './listbox';
33
import {ComponentFixture, TestBed} from '@angular/core/testing';
44
import {By} from '@angular/platform-browser';
55
import {Direction} from '@angular/cdk/bidi';
@@ -49,15 +49,15 @@ describe('Listbox', () => {
4949
const type = (char: string) => keydown(char);
5050

5151
function setupListbox(opts?: {
52-
orientation?: 'horizontal' | 'vertical';
52+
orientation?: ListOrientation;
5353
disabled?: boolean;
5454
readonly?: boolean;
5555
values?: number[];
5656
softDisabled?: boolean;
57-
focusMode?: 'roving' | 'activedescendant';
57+
focusMode?: ListFocusMode;
5858
multi?: boolean;
5959
wrap?: boolean;
60-
selectionMode?: 'follow' | 'explicit';
60+
selectionMode?: ListSelectionMode;
6161
typeaheadDelay?: number;
6262
disabledOptions?: number[];
6363
options?: TestOption[];
@@ -573,10 +573,7 @@ describe('Listbox', () => {
573573
});
574574
});
575575

576-
function runNavigationTests(
577-
focusMode: 'roving' | 'activedescendant',
578-
isFocused: (index: number) => boolean,
579-
) {
576+
function runNavigationTests(focusMode: ListFocusMode, isFocused: (index: number) => boolean) {
580577
describe(`keyboard navigation (focusMode="${focusMode}")`, () => {
581578
it('should move focus to the last focusable option on End', () => {
582579
setupListbox({focusMode, disabledOptions: [4]});
@@ -812,11 +809,11 @@ class ListboxExample {
812809
disabled = false;
813810
readonly = false;
814811
softDisabled = true;
815-
focusMode: 'roving' | 'activedescendant' = 'roving';
816-
orientation: 'vertical' | 'horizontal' = 'vertical';
812+
focusMode: ListFocusMode = 'roving';
813+
orientation: ListOrientation = 'vertical';
817814
multi = false;
818815
wrap = true;
819-
selectionMode: 'follow' | 'explicit' = 'explicit';
816+
selectionMode: ListSelectionMode = 'explicit';
820817
typeaheadDelay = 0.5;
821818
}
822819

src/aria/listbox/listbox.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,21 @@ import {
1919
signal,
2020
untracked,
2121
} from '@angular/core';
22-
import {ComboboxListboxPattern, ListboxPattern, OptionPattern} from '@angular/aria/private';
22+
import {
23+
ComboboxListboxPattern,
24+
ListOrientation,
25+
ListboxPattern,
26+
OptionPattern,
27+
ListSelectionMode,
28+
ListFocusMode,
29+
} from '@angular/aria/private';
2330
import {Directionality} from '@angular/cdk/bidi';
2431
import {toSignal} from '@angular/core/rxjs-interop';
2532
import {_IdGenerator} from '@angular/cdk/a11y';
2633
import {ComboboxPopup} from '../combobox';
2734

35+
export {ListOrientation, ListFocusMode, ListSelectionMode};
36+
2837
/**
2938
* A listbox container.
3039
*
@@ -91,7 +100,7 @@ export class Listbox<V> {
91100
protected items = computed(() => this._options().map(option => option._pattern));
92101

93102
/** Whether the list is vertically or horizontally oriented. */
94-
orientation = input<'vertical' | 'horizontal'>('vertical');
103+
orientation = input<ListOrientation>('vertical');
95104

96105
/** Whether multiple items in the list can be selected at once. */
97106
multi = input(false, {transform: booleanAttribute});
@@ -103,10 +112,10 @@ export class Listbox<V> {
103112
softDisabled = input(true, {transform: booleanAttribute});
104113

105114
/** The focus strategy used by the list. */
106-
focusMode = input<'roving' | 'activedescendant'>('roving');
115+
focusMode = input<ListFocusMode>('roving');
107116

108117
/** The selection strategy used by the list. */
109-
selectionMode = input<'follow' | 'explicit'>('follow');
118+
selectionMode = input<ListSelectionMode>('follow');
110119

111120
/** The amount of time before the typeahead search is reset. */
112121
typeaheadDelay = input<number>(0.5); // Picked arbitrarily.

src/aria/private/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ ts_project(
1111
deps = [
1212
"//:node_modules/@angular/core",
1313
"//src/aria/private/accordion",
14+
"//src/aria/private/behaviors/grid",
15+
"//src/aria/private/behaviors/list-focus",
16+
"//src/aria/private/behaviors/list-navigation",
17+
"//src/aria/private/behaviors/list-selection",
1418
"//src/aria/private/behaviors/signal-like",
1519
"//src/aria/private/combobox",
1620
"//src/aria/private/deferred-content",

src/aria/private/behaviors/grid/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ts_project(
1010
),
1111
deps = [
1212
"//:node_modules/@angular/core",
13+
"//src/aria/private/behaviors/grid-focus",
1314
"//src/aria/private/behaviors/signal-like",
1415
],
1516
)

src/aria/private/behaviors/grid/grid-focus.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {computed, signal} from '@angular/core';
1010
import {SignalLike} from '../signal-like/signal-like';
1111
import type {GridData, BaseGridCell, RowCol} from './grid-data';
1212

13+
export type GridFocusMode = 'roving' | 'activedescendant';
14+
1315
/** Represents an cell in a grid, such as a grid cell, that may receive focus. */
1416
export interface GridFocusCell extends BaseGridCell {
1517
/** A unique identifier for the cell. */
@@ -25,7 +27,7 @@ export interface GridFocusCell extends BaseGridCell {
2527
/** Represents the required inputs for a grid that contains focusable cells. */
2628
export interface GridFocusInputs {
2729
/** The focus strategy used by the grid. */
28-
focusMode: SignalLike<'roving' | 'activedescendant'>;
30+
focusMode: SignalLike<GridFocusMode>;
2931

3032
/** Whether the grid is disabled. */
3133
disabled: SignalLike<boolean>;

src/aria/private/behaviors/grid/grid-navigation.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
TestBaseGridCell,
1919
} from './grid-data.spec';
2020
import {GridFocus, GridFocusInputs} from './grid-focus';
21-
import {direction, GridNavigation, GridNavigationInputs, WrapStrategy} from './grid-navigation';
21+
import {direction, GridNavigation, GridNavigationInputs, GridWrapStrategy} from './grid-navigation';
2222

2323
export interface TestGridNavigationCell extends TestBaseGridCell {
2424
element: WritableSignal<HTMLElement>;
@@ -62,8 +62,8 @@ function setupGridNavigation(
6262
const gridNav = new GridNavigation({
6363
grid: gridData,
6464
gridFocus: gridFocus,
65-
rowWrap: signal<WrapStrategy>('loop'),
66-
colWrap: signal<WrapStrategy>('loop'),
65+
rowWrap: signal<GridWrapStrategy>('loop'),
66+
colWrap: signal<GridWrapStrategy>('loop'),
6767
...gridFocusInputs,
6868
...inputs,
6969
});

0 commit comments

Comments
 (0)