Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/cdk-experimental/accordion/accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ export class CdkAccordionTrigger {
},
})
export class CdkAccordionGroup {
/** A reference to the group element. */
private readonly _elementRef = inject(ElementRef);

/** The CdkAccordionTriggers nested inside this group. */
protected readonly _triggers = contentChildren(CdkAccordionTrigger, {descendants: true});

Expand Down Expand Up @@ -184,6 +187,7 @@ export class CdkAccordionGroup {
expandedIds: this.value,
// TODO(ok7sai): Investigate whether an accordion should support horizontal mode.
orientation: () => 'vertical',
element: () => this._elementRef.nativeElement,
});

constructor() {
Expand Down
4 changes: 4 additions & 0 deletions src/cdk-experimental/listbox/listbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ import {_IdGenerator} from '@angular/cdk/a11y';
},
})
export class CdkListbox<V> {
/** A reference to the listbox element. */
private readonly _elementRef = inject(ElementRef);

/** The directionality (LTR / RTL) context for the application (or a subtree of it). */
private readonly _directionality = inject(Directionality);

Expand Down Expand Up @@ -105,6 +108,7 @@ export class CdkListbox<V> {
items: this.items,
activeItem: signal(undefined),
textDirection: this.textDirection,
element: () => this._elementRef.nativeElement,
});

/** Whether the listbox has received focus yet. */
Expand Down
4 changes: 4 additions & 0 deletions src/cdk-experimental/radio-group/radio-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ export function mapSignal<T, V>(
},
})
export class CdkRadioGroup<V> {
/** A reference to the radio group element. */
private readonly _elementRef = inject(ElementRef);

/** The CdkRadioButtons nested inside of the CdkRadioGroup. */
private readonly _cdkRadioButtons = contentChildren(CdkRadioButton, {descendants: true});

Expand Down Expand Up @@ -140,6 +143,7 @@ export class CdkRadioGroup<V> {
activeItem: signal(undefined),
textDirection: this.textDirection,
toolbar: this._toolbarPattern,
element: () => this._elementRef.nativeElement,
focusMode: this._toolbarPattern()?.inputs.focusMode ?? this.focusMode,
skipDisabled: this._toolbarPattern()?.inputs.skipDisabled ?? this.skipDisabled,
});
Expand Down
4 changes: 4 additions & 0 deletions src/cdk-experimental/tabs/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ export class CdkTabs {
},
})
export class CdkTabList implements OnInit, OnDestroy {
/** A reference to the tab list element. */
private readonly _elementRef = inject(ElementRef);

/** The parent CdkTabs. */
private readonly _cdkTabs = inject(CdkTabs);

Expand Down Expand Up @@ -174,6 +177,7 @@ export class CdkTabList implements OnInit, OnDestroy {
items: this.tabs,
value: this._selection,
activeItem: signal(undefined),
element: () => this._elementRef.nativeElement,
});

/** Whether the tree has received focus yet. */
Expand Down
4 changes: 4 additions & 0 deletions src/cdk-experimental/toolbar/toolbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ function sortDirectives(a: HasElement, b: HasElement) {
},
})
export class CdkToolbar<V> {
/** A reference to the toolbar element. */
private readonly _elementRef = inject(ElementRef);

/** The CdkTabList nested inside of the container. */
private readonly _cdkWidgets = signal(new Set<CdkRadioButtonInterface<V> | CdkToolbarWidget>());

Expand Down Expand Up @@ -109,6 +112,7 @@ export class CdkToolbar<V> {
activeItem: signal(undefined),
textDirection: this.textDirection,
focusMode: signal('roving'),
element: () => this._elementRef.nativeElement,
});

/** Whether the toolbar has received focus yet. */
Expand Down
4 changes: 4 additions & 0 deletions src/cdk-experimental/tree/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ function sortDirectives(a: HasElement, b: HasElement) {
},
})
export class CdkTree<V> {
/** A reference to the tree element. */
private readonly _elementRef = inject(ElementRef);

/** All CdkTreeItem instances within this tree. */
private readonly _unorderedItems = signal(new Set<CdkTreeItem<V>>());

Expand Down Expand Up @@ -124,6 +127,7 @@ export class CdkTree<V> {
[...this._unorderedItems()].sort(sortDirectives).map(item => item.pattern),
),
activeItem: signal(undefined),
element: () => this._elementRef.nativeElement,
});

/** Whether the tree has received focus yet. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ describe('Accordion Pattern', () => {
expandedIds: signal<string[]>([]),
skipDisabled: signal(true),
wrap: signal(true),
element: signal(document.createElement('div')),
};
groupPattern = new AccordionGroupPattern(groupInputs);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function getListFocus(inputs: TestInputs = {}): ListFocus<ListFocusItem>
disabled: signal(false),
skipDisabled: signal(false),
focusMode: signal('roving'),
element: signal({focus: () => {}} as HTMLElement),
items: items,
...inputs,
});
Expand Down Expand Up @@ -98,6 +99,12 @@ describe('List Focus', () => {
focusManager.inputs.activeItem.set(focusManager.inputs.items()[1]);
expect(focusManager.getActiveDescendant()).toBe(focusManager.inputs.items()[1].id());
});

it('should focus the list element when focusing an item', () => {
const focusSpy = spyOn(focusManager.inputs.element()!, 'focus');
focusManager.focus(focusManager.inputs.items()[1]);
expect(focusSpy).toHaveBeenCalled();
});
});

describe('#isFocusable', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export interface ListFocusInputs<T extends ListFocusItem> {

/** Whether disabled items in the list should be skipped when navigating. */
skipDisabled: SignalLike<boolean>;

element: SignalLike<HTMLElement | undefined>;
}

/** Controls focus for a list of items. */
Expand Down Expand Up @@ -103,9 +105,7 @@ export class ListFocus<T extends ListFocusItem> {
this.prevActiveItem.set(this.inputs.activeItem());
this.inputs.activeItem.set(item);

if (this.inputs.focusMode() === 'roving') {
item.element().focus();
}
this.inputs.focusMode() === 'roving' ? item.element().focus() : this.inputs.element()?.focus();

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('List Behavior', () => {
multi: inputs.multi ?? signal(false),
textDirection: inputs.textDirection ?? signal('ltr'),
orientation: inputs.orientation ?? signal('vertical'),
element: signal({focus: () => {}} as HTMLElement),
focusMode: inputs.focusMode ?? signal('roving'),
skipDisabled: inputs.skipDisabled ?? signal(true),
selectionMode: signal('explicit'),
Expand Down
1 change: 1 addition & 0 deletions src/cdk-experimental/ui-patterns/listbox/listbox.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe('Listbox Pattern', () => {
textDirection: inputs.textDirection ?? signal('ltr'),
orientation: inputs.orientation ?? signal('vertical'),
selectionMode: inputs.selectionMode ?? signal('explicit'),
element: signal(document.createElement('div')),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ describe('RadioGroup Pattern', () => {
items: inputs.items,
value: inputs.value ?? signal([]),
activeItem: signal(undefined),
element: signal(document.createElement('div')),
readonly: inputs.readonly ?? signal(false),
disabled: inputs.disabled ?? signal(false),
skipDisabled: inputs.skipDisabled ?? signal(true),
Expand Down
1 change: 1 addition & 0 deletions src/cdk-experimental/ui-patterns/tabs/tabs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ describe('Tabs Pattern', () => {
skipDisabled: signal(true),
items: signal([]),
value: signal(['tab-1']),
element: signal(document.createElement('div')),
};
tabListPattern = new TabListPattern(tabListInputs);

Expand Down
2 changes: 2 additions & 0 deletions src/cdk-experimental/ui-patterns/toolbar/toolbar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ describe('Toolbar Pattern', () => {
textDirection: inputs.textDirection ?? signal('ltr'),
orientation: inputs.orientation ?? signal('vertical'),
toolbar: inputs.toolbar ?? signal(undefined),
element: signal(document.createElement('div')),
});
}

Expand Down Expand Up @@ -92,6 +93,7 @@ describe('Toolbar Pattern', () => {
textDirection: inputs.textDirection ?? signal('ltr'),
orientation: inputs.orientation ?? signal('horizontal'),
wrap: inputs.wrap ?? signal(false),
element: signal(document.createElement('div')),
});
}

Expand Down
13 changes: 13 additions & 0 deletions src/cdk-experimental/ui-patterns/tree/tree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -201,6 +202,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(true),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -246,6 +248,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -430,6 +433,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -488,6 +492,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -552,6 +557,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -710,6 +716,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -860,6 +867,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -900,6 +908,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -944,6 +953,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -992,6 +1002,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -1074,6 +1085,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down Expand Up @@ -1236,6 +1248,7 @@ describe('Tree Pattern', () => {
wrap: signal(false),
nav: signal(false),
currentType: signal('page'),
element: signal(document.createElement('div')),
};
});

Expand Down
11 changes: 11 additions & 0 deletions src/dev-app/common-classes.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@
border-radius: var(--mat-sys-corner-extra-small);
}

[aria-disabled='true']:focus-within,
[aria-activedescendant]:focus-within {
outline: var(--mat-sys-primary) solid 1px;
}

[aria-disabled='true'] .example-selectable:focus-within,
[aria-activedescendant] .example-selectable:focus-within {
outline-color: transparent;
border-radius: 0;
}

[aria-disabled='true'] .example-selectable[aria-selected='true'],
.example-selectable[aria-disabled='true'][aria-selected='true'],
[aria-disabled='true'] .example-selectable[aria-checked='true'],
Expand Down
Loading