Skip to content

Commit 63433c4

Browse files
fix(aria/menu): accept a bare disabled attribute on MenuItem
MenuItem.disabled was declared as input<boolean>(false), so <div ngMenuItem disabled> failed strict template type-checking and was not disabled in JIT. Use booleanAttribute, like the disabled inputs on the other aria directives. Fixes #33964
1 parent 7360f0b commit 63433c4

3 files changed

Lines changed: 33 additions & 2 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class MenuItem<V> implements OnInit, OnDestroy {
7878
constructor();
7979
readonly active: _angular_core.Signal<boolean>;
8080
close(): void;
81-
readonly disabled: _angular_core.InputSignal<boolean>;
81+
readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
8282
readonly element: HTMLElement;
8383
readonly expanded: _angular_core.Signal<boolean | null>;
8484
readonly hasPopup: _angular_core.Signal<boolean>;

‎src/aria/menu/menu-item.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import {
10+
booleanAttribute,
1011
computed,
1112
Directive,
1213
effect,
@@ -68,7 +69,7 @@ export class MenuItem<V> implements OnInit, OnDestroy {
6869
readonly value = input<V | undefined>(undefined);
6970

7071
/** Whether the menu item is disabled. */
71-
readonly disabled = input<boolean>(false);
72+
readonly disabled = input(false, {transform: booleanAttribute});
7273

7374
/** The search term associated with the menu item. */
7475
readonly searchTerm = model<string>('');

‎src/aria/menu/menu.spec.ts‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,24 @@ describe('Standalone Menu Pattern', () => {
556556
});
557557
});
558558

559+
describe('disabled attribute', () => {
560+
it('should treat a bare disabled attribute as disabled', () => {
561+
TestBed.resetTestingModule();
562+
TestBed.configureTestingModule({
563+
imports: [MenuItemDisabledAttributeExample],
564+
});
565+
const disabledFixture = TestBed.createComponent(MenuItemDisabledAttributeExample);
566+
disabledFixture.detectChanges();
567+
568+
const items = disabledFixture.debugElement
569+
.queryAll(By.directive(MenuItem))
570+
.map(debugEl => debugEl.nativeElement as HTMLElement);
571+
572+
expect(items[0].getAttribute('aria-disabled')).toBe('false');
573+
expect(items[1].getAttribute('aria-disabled')).toBe('true');
574+
});
575+
});
576+
559577
describe('structural validations', () => {
560578
let consoleSpy: jasmine.Spy;
561579

@@ -1486,3 +1504,15 @@ class CdkOverlayMenuExample {
14861504
class MenuItemRoleOverrideExample {
14871505
customRole = signal<'menuitem' | 'menuitemradio' | 'menuitemcheckbox'>('menuitemcheckbox');
14881506
}
1507+
1508+
@Component({
1509+
template: `
1510+
<div ngMenu>
1511+
<div ngMenuItem value="item0">Item 0</div>
1512+
<div ngMenuItem value="item1" disabled>Item 1</div>
1513+
</div>
1514+
`,
1515+
imports: [Menu, MenuItem],
1516+
changeDetection: ChangeDetectionStrategy.Eager,
1517+
})
1518+
class MenuItemDisabledAttributeExample {}

0 commit comments

Comments
 (0)