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
3 changes: 2 additions & 1 deletion goldens/aria/menu/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ export class Menu<V> implements OnDestroy {
ngOnDestroy(): void;
readonly parent: _angular_core.WritableSignal<MenuTrigger<V> | MenuItem<V> | undefined>;
readonly _pattern: MenuPattern<V>;
readonly softDisabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
readonly tabIndex: Signal<0 | -1>;
readonly textDirection: _angular_core.WritableSignal<_angular_cdk_bidi.Direction>;
readonly typeaheadDelay: _angular_core.InputSignal<number>;
readonly visible: Signal<boolean>;
readonly wrap: _angular_core.InputSignalWithTransform<boolean, unknown>;
// (undocumented)
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<Menu<any>, "[ngMenu]", ["ngMenu"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "typeaheadDelay": { "alias": "typeaheadDelay"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "expansionDelay": { "alias": "expansionDelay"; "required": false; "isSignal": true; }; }, { "itemSelected": "itemSelected"; }, never, never, true, [{ directive: typeof DeferredContentAware; inputs: { "preserveContent": "preserveContent"; }; outputs: {}; }]>;
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<Menu<any>, "[ngMenu]", ["ngMenu"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; "typeaheadDelay": { "alias": "typeaheadDelay"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "softDisabled": { "alias": "softDisabled"; "required": false; "isSignal": true; }; "expansionDelay": { "alias": "expansionDelay"; "required": false; "isSignal": true; }; }, { "itemSelected": "itemSelected"; }, never, never, true, [{ directive: typeof DeferredContentAware; inputs: { "preserveContent": "preserveContent"; }; outputs: {}; }]>;
// (undocumented)
static ɵfac: _angular_core.ɵɵFactoryDeclaration<Menu<any>, never>;
}
Expand Down
1 change: 0 additions & 1 deletion src/aria/menu/menu-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ export class MenuBar<V> implements OnDestroy {
...this,
items: this._itemPatterns,
multi: () => false,
softDisabled: () => true,
focusMode: () => 'roving',
orientation: () => 'horizontal',
selectionMode: () => 'explicit',
Expand Down
29 changes: 28 additions & 1 deletion src/aria/menu/menu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,32 @@ describe('Standalone Menu Pattern', () => {
expect(item?.getAttribute('aria-label')).toBe('Apple item label');
});

describe('softDisabled', () => {
it('should skip disabled items during navigation when softDisabled is false', () => {
setupMenu();
fixture.componentInstance.softDisabled.set(false);
fixture.detectChanges();

const apple = getItem('Apple')!;
const berries = getItem('Berries');

keydown(apple, 'ArrowUp');
expect(document.activeElement).toBe(berries);
});

it('should focus disabled items during navigation when softDisabled is true', () => {
setupMenu();
fixture.componentInstance.softDisabled.set(true);
fixture.detectChanges();

const apple = getItem('Apple')!;
const cherry = getItem('Cherry');

keydown(apple!, 'ArrowUp');
expect(document.activeElement).toBe(cherry);
});
});

describe('structural validations', () => {
let consoleSpy: jasmine.Spy;

Expand Down Expand Up @@ -1077,7 +1103,7 @@ describe('Menu Bar Pattern', () => {

@Component({
template: `
<div ngMenu [expansionDelay]="0" (itemSelected)="itemSelected($event)">
<div ngMenu [softDisabled]="softDisabled()" [expansionDelay]="0" (itemSelected)="itemSelected($event)">
<ng-template ngMenuContent>
<div
ngMenuItem
Expand All @@ -1104,6 +1130,7 @@ describe('Menu Bar Pattern', () => {
})
class StandaloneMenuExample {
firstItemAriaLabel = signal<string | null>(null);
softDisabled = signal(true);

itemSelected(value: string) {}
}
Expand Down
4 changes: 3 additions & 1 deletion src/aria/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ export class Menu<V> implements OnDestroy {
/** A reference to the parent menu item or menu trigger. */
readonly parent = signal<MenuTrigger<V> | MenuItem<V> | undefined>(undefined);

/** Whether the menu is soft disabled. */
readonly softDisabled = input(true, {transform: booleanAttribute});

/** The menu ui pattern instance. */
readonly _pattern: MenuPattern<V>;

Expand Down Expand Up @@ -152,7 +155,6 @@ export class Menu<V> implements OnDestroy {
parent: computed(() => this.parent()?._pattern),
items: this._itemPatterns,
multi: () => false,
softDisabled: () => true,
focusMode: () => 'roving',
orientation: () => 'vertical',
selectionMode: () => 'explicit',
Expand Down
Loading