Skip to content

Commit 513ea21

Browse files
committed
refactor(aria/grid): simplify Grid cell to only support single widget
Too much overhead to support multi widgets in a cell, and it's not a common use case. If a cell with multi widgets is desired, developers should leverage the compelx widget type to support in cell widget navigation.
1 parent ad5fba3 commit 513ea21

File tree

8 files changed

+83
-409
lines changed

8 files changed

+83
-409
lines changed

goldens/aria/grid/index.api.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export class GridCell {
3939
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
4040
readonly element: HTMLElement;
4141
readonly id: _angular_core.InputSignal<string>;
42-
readonly orientation: _angular_core.InputSignal<"vertical" | "horizontal">;
4342
readonly _pattern: GridCellPattern;
4443
readonly role: _angular_core.InputSignal<"gridcell" | "columnheader" | "rowheader">;
4544
readonly rowIndex: _angular_core.InputSignal<number | undefined>;
@@ -49,9 +48,8 @@ export class GridCell {
4948
protected readonly _tabIndex: Signal<number>;
5049
readonly tabindex: _angular_core.InputSignal<number | undefined>;
5150
readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>;
52-
readonly wrap: _angular_core.InputSignalWithTransform<boolean, unknown>;
5351
// (undocumented)
54-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<GridCell, "[ngGridCell]", ["ngGridCell"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "role": { "alias": "role"; "required": false; "isSignal": true; }; "rowSpan": { "alias": "rowSpan"; "required": false; "isSignal": true; }; "colSpan": { "alias": "colSpan"; "required": false; "isSignal": true; }; "rowIndex": { "alias": "rowIndex"; "required": false; "isSignal": true; }; "colIndex": { "alias": "colIndex"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "selected": { "alias": "selected"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "orientation": { "alias": "orientation"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "tabindex": { "alias": "tabindex"; "required": false; "isSignal": true; }; }, { "selected": "selectedChange"; }, ["_widgets"], never, true, never>;
52+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<GridCell, "[ngGridCell]", ["ngGridCell"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "role": { "alias": "role"; "required": false; "isSignal": true; }; "rowSpan": { "alias": "rowSpan"; "required": false; "isSignal": true; }; "colSpan": { "alias": "colSpan"; "required": false; "isSignal": true; }; "rowIndex": { "alias": "rowIndex"; "required": false; "isSignal": true; }; "colIndex": { "alias": "colIndex"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "selected": { "alias": "selected"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "tabindex": { "alias": "tabindex"; "required": false; "isSignal": true; }; }, { "selected": "selectedChange"; }, ["_widget"], never, true, never>;
5553
// (undocumented)
5654
static ɵfac: _angular_core.ɵɵFactoryDeclaration<GridCell, never>;
5755
}

goldens/aria/private/index.api.md

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -292,20 +292,19 @@ export class DeferredContentAware {
292292
}
293293

294294
// @public
295-
export interface GridCellInputs extends GridCell, Omit<ListNavigationInputs<GridCellWidgetPattern>, 'focusMode' | 'items' | 'activeItem' | 'softDisabled' | 'element'> {
295+
export interface GridCellInputs extends GridCell {
296296
colIndex: SignalLike<number | undefined>;
297297
getWidget: (e: Element | null) => GridCellWidgetPattern | undefined;
298298
grid: SignalLike<GridPattern>;
299299
row: SignalLike<GridRowPattern>;
300300
rowIndex: SignalLike<number | undefined>;
301-
widgets: SignalLike<GridCellWidgetPattern[]>;
301+
widget: SignalLike<GridCellWidgetPattern | undefined>;
302302
}
303303

304304
// @public
305305
export class GridCellPattern implements GridCell {
306306
constructor(inputs: GridCellInputs);
307307
readonly active: SignalLike<boolean>;
308-
readonly activeWidget: WritableSignalLike<GridCellWidgetPattern | undefined>;
309308
readonly anchor: SignalLike<true | undefined>;
310309
readonly ariaColIndex: SignalLike<number | undefined>;
311310
readonly ariaRowIndex: SignalLike<number | undefined>;
@@ -314,52 +313,40 @@ export class GridCellPattern implements GridCell {
314313
readonly disabled: SignalLike<boolean>;
315314
readonly element: SignalLike<HTMLElement>;
316315
focus(): void;
317-
readonly focusBehavior: ListFocus<GridCellWidgetPattern>;
318316
readonly id: SignalLike<string>;
319317
// (undocumented)
320318
readonly inputs: GridCellInputs;
321319
readonly isActivated: SignalLike<boolean>;
322320
readonly isFocused: WritableSignalLike<boolean>;
323-
readonly keydown: SignalLike<KeyboardEventManager<KeyboardEvent>>;
324-
readonly multiWidgetMode: SignalLike<boolean>;
325-
readonly navigationActivated: WritableSignalLike<boolean>;
326-
readonly navigationBehavior: ListNavigation<GridCellWidgetPattern>;
327-
readonly navigationDisabled: SignalLike<boolean>;
328-
readonly nextKey: SignalLike<"ArrowRight" | "ArrowLeft" | "ArrowDown">;
329321
onFocusIn(event: FocusEvent): void;
330322
onFocusOut(event: FocusEvent): void;
331323
onKeydown(event: KeyboardEvent): void;
332-
readonly prevKey: SignalLike<"ArrowUp" | "ArrowRight" | "ArrowLeft">;
333324
readonly rowSpan: SignalLike<number>;
334325
readonly selectable: SignalLike<boolean>;
335326
readonly selected: WritableSignalLike<boolean>;
336-
readonly singleWidgetMode: SignalLike<boolean>;
337-
startNavigation(): void;
338-
stopNavigation(): void;
339327
readonly tabIndex: SignalLike<-1 | 0>;
340-
readonly widgetActivated: SignalLike<boolean>;
328+
readonly widget: SignalLike<GridCellWidgetPattern | undefined>;
341329
widgetTabIndex(): -1 | 0;
342330
}
343331

344332
// @public
345-
export interface GridCellWidgetInputs extends Omit<ListNavigationItem, 'index'> {
333+
export interface GridCellWidgetInputs {
346334
cell: SignalLike<GridCellPattern>;
335+
disabled: SignalLike<boolean>;
347336
element: SignalLike<HTMLElement>;
348337
focusTarget: SignalLike<HTMLElement | undefined>;
349338
widgetType: SignalLike<'simple' | 'complex' | 'editable'>;
350339
}
351340

352341
// @public
353-
export class GridCellWidgetPattern implements ListNavigationItem {
342+
export class GridCellWidgetPattern {
354343
constructor(inputs: GridCellWidgetInputs);
355344
activate(event?: KeyboardEvent | FocusEvent): void;
356345
readonly active: SignalLike<boolean>;
357346
deactivate(event?: KeyboardEvent | FocusEvent): void;
358347
readonly disabled: SignalLike<boolean>;
359348
readonly element: SignalLike<HTMLElement>;
360349
focus(): void;
361-
readonly id: SignalLike<string>;
362-
readonly index: SignalLike<number>;
363350
// (undocumented)
364351
readonly inputs: GridCellWidgetInputs;
365352
readonly isActivated: WritableSignalLike<boolean>;

src/aria/grid/grid-cell.ts

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
afterRenderEffect,
1212
booleanAttribute,
1313
computed,
14-
contentChildren,
14+
contentChild,
1515
Directive,
1616
ElementRef,
1717
inject,
@@ -21,7 +21,7 @@ import {
2121
Renderer2,
2222
} from '@angular/core';
2323
import {Directionality} from '@angular/cdk/bidi';
24-
import {GridCellPattern} from '../private';
24+
import {GridCellPattern, GridCellWidgetPattern} from '../private';
2525
import {GridCellWidget} from './grid-cell-widget';
2626
import {GRID_CELL, GRID_ROW} from './grid-tokens';
2727

@@ -55,12 +55,12 @@ export class GridCell {
5555
/** Whether the cell is currently active (focused). */
5656
readonly active = computed(() => this._pattern.active());
5757

58-
/** The widgets contained within this cell, if any. */
59-
private readonly _widgets = contentChildren(GridCellWidget, {descendants: true});
58+
/** The widget contained within this cell, if any. */
59+
private readonly _widget = contentChild(GridCellWidget, {descendants: true});
6060

6161
/** The UI pattern for the widget in this cell. */
62-
private readonly _widgetPatterns: Signal<any[]> = computed(() =>
63-
this._widgets().map(w => w._pattern),
62+
private readonly _widgetPattern: Signal<GridCellWidgetPattern | undefined> = computed(
63+
() => this._widget()?._pattern,
6464
);
6565

6666
/** The parent row. */
@@ -96,12 +96,6 @@ export class GridCell {
9696
/** Whether the cell is selectable. */
9797
readonly selectable = input<boolean>(true);
9898

99-
/** Orientation of the widgets in the cell. */
100-
readonly orientation = input<'vertical' | 'horizontal'>('horizontal');
101-
102-
/** Whether widgets navigation wraps. */
103-
readonly wrap = input(true, {transform: booleanAttribute});
104-
10599
/** The tabindex override. */
106100
readonly tabindex = input<number | undefined>();
107101

@@ -118,7 +112,7 @@ export class GridCell {
118112
...this,
119113
grid: this._row._gridPattern,
120114
row: () => this._row._pattern,
121-
widgets: this._widgetPatterns,
115+
widget: this._widgetPattern,
122116
getWidget: e => this._getWidget(e),
123117
element: () => this.element,
124118
});
@@ -160,11 +154,13 @@ export class GridCell {
160154
/** Gets the cell widget pattern for a given element. */
161155
private _getWidget(element: Element | null | undefined): any | undefined {
162156
let target = element;
157+
const widget = this._widgetPattern();
158+
159+
if (!widget) return undefined;
163160

164161
while (target) {
165-
const pattern = this._widgetPatterns().find(w => w.element() === target);
166-
if (pattern) {
167-
return pattern;
162+
if (widget.element() === target) {
163+
return widget;
168164
}
169165

170166
target = target.parentElement?.closest('[ngGridCellWidget]');

0 commit comments

Comments
 (0)