From c526dc6ec843bbe6dbbf8176f4fb76e933c2d7e4 Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Tue, 28 Oct 2025 11:57:15 -0400 Subject: [PATCH 1/7] fix(aria/menu): remove onSubmit from MenuTrigger --- src/aria/menu/menu.ts | 3 +-- src/aria/private/menu/menu.ts | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index 882206b6d8d6..d6c7c58a5447 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -66,8 +66,7 @@ export class MenuTrigger { onSubmit = output(); /** The menu trigger ui pattern instance. */ - readonly _pattern: MenuTriggerPattern = new MenuTriggerPattern({ - onSubmit: (value: V) => this.onSubmit.emit(value), + _pattern: MenuTriggerPattern = new MenuTriggerPattern({ element: computed(() => this._elementRef.nativeElement), submenu: computed(() => this.submenu()?._pattern), }); diff --git a/src/aria/private/menu/menu.ts b/src/aria/private/menu/menu.ts index 08f2e96167de..49f8177acaf9 100644 --- a/src/aria/private/menu/menu.ts +++ b/src/aria/private/menu/menu.ts @@ -43,9 +43,6 @@ export interface MenuTriggerInputs { /** A reference to the submenu associated with the menu trigger. */ submenu: SignalLike | undefined>; - - /** Callback function triggered when a menu item is selected. */ - onSubmit?: (value: V) => void; } /** The inputs for the MenuItemPattern class. */ @@ -308,8 +305,12 @@ export class MenuPattern { const isMenuBar = root instanceof MenuBarPattern; const isMenuTrigger = root instanceof MenuTriggerPattern; - if (!item.submenu() && (isMenuTrigger || isMenuBar)) { + if (!item.submenu() && isMenuTrigger) { root.close({refocus: true}); + } + + if (!item.submenu() && isMenuBar) { + root.close(); root?.inputs.onSubmit?.(item.value()); } From 14da1e6b2def8cdbc4c02ad892329fded9f1ecaa Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Tue, 28 Oct 2025 12:03:22 -0400 Subject: [PATCH 2/7] refactor(aria/menu): rename submenu to menu for MenuTrigger --- src/aria/menu/menu.spec.ts | 2 +- src/aria/menu/menu.ts | 8 +- src/aria/private/menu/menu.spec.ts | 8 +- src/aria/private/menu/menu.ts | 22 +- .../aria/menu/menu-bar/menu-bar-example.html | 352 +++++++++--------- .../menu-context/menu-context-example.html | 40 +- .../menu-standalone-example.html | 58 +-- .../menu-trigger/menu-trigger-example.html | 62 +-- .../aria/menu/simple-menu.ts | 14 +- 9 files changed, 285 insertions(+), 281 deletions(-) diff --git a/src/aria/menu/menu.spec.ts b/src/aria/menu/menu.spec.ts index 9ed1e34e958f..103216db1ed8 100644 --- a/src/aria/menu/menu.spec.ts +++ b/src/aria/menu/menu.spec.ts @@ -899,7 +899,7 @@ class StandaloneMenuExample { @Component({ template: ` - +
Apple
diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index d6c7c58a5447..e8b919cf7d22 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -44,7 +44,7 @@ import {Directionality} from '@angular/cdk/bidi'; '[attr.tabindex]': '_pattern.tabindex()', '[attr.aria-haspopup]': '_pattern.hasPopup()', '[attr.aria-expanded]': '_pattern.expanded()', - '[attr.aria-controls]': '_pattern.submenu()?.id()', + '[attr.aria-controls]': '_pattern.menu()?.id()', '(click)': '_pattern.onClick()', '(keydown)': '_pattern.onKeydown($event)', '(focusout)': '_pattern.onFocusOut($event)', @@ -59,8 +59,8 @@ export class MenuTrigger { // TODO(wagnermaciel): See we can remove the need to pass in a submenu. - /** The submenu associated with the menu trigger. */ - submenu = input | undefined>(undefined); + /** The menu associated with the trigger. */ + menu = input | undefined>(undefined); /** A callback function triggered when a menu item is selected. */ onSubmit = output(); @@ -68,7 +68,7 @@ export class MenuTrigger { /** The menu trigger ui pattern instance. */ _pattern: MenuTriggerPattern = new MenuTriggerPattern({ element: computed(() => this._elementRef.nativeElement), - submenu: computed(() => this.submenu()?._pattern), + menu: computed(() => this.menu()?._pattern), }); } diff --git a/src/aria/private/menu/menu.spec.ts b/src/aria/private/menu/menu.spec.ts index 689af41216f0..50dad6b65de4 100644 --- a/src/aria/private/menu/menu.spec.ts +++ b/src/aria/private/menu/menu.spec.ts @@ -42,7 +42,7 @@ function getMenuTriggerPattern() { const submenu = signal | undefined>(undefined); const trigger = new MenuTriggerPattern({ element, - submenu, + menu: submenu, }); return trigger; } @@ -123,10 +123,14 @@ function getMenuPattern( }), ); - if (parent) { + if (parent instanceof MenuTriggerPattern) { + (parent.menu as WritableSignal>).set(menu); + parent.inputs.element()?.appendChild(menu.inputs.element()!); + } else if (parent instanceof MenuItemPattern) { (parent.submenu as WritableSignal>).set(menu); parent.inputs.element()?.appendChild(menu.inputs.element()!); } + menu.inputs.activeItem.set(items()[0]); return menu; } diff --git a/src/aria/private/menu/menu.ts b/src/aria/private/menu/menu.ts index 49f8177acaf9..fcd05d71395a 100644 --- a/src/aria/private/menu/menu.ts +++ b/src/aria/private/menu/menu.ts @@ -41,8 +41,8 @@ export interface MenuTriggerInputs { /** A reference to the menu trigger element. */ element: SignalLike; - /** A reference to the submenu associated with the menu trigger. */ - submenu: SignalLike | undefined>; + /** A reference to the menu associated with the trigger. */ + menu: SignalLike | undefined>; } /** The inputs for the MenuItemPattern class. */ @@ -512,11 +512,11 @@ export class MenuTriggerPattern { /** Whether the menu trigger has a popup. */ hasPopup = () => true; - /** The submenu associated with the trigger. */ - submenu: SignalLike | undefined>; + /** The menu associated with the trigger. */ + menu: SignalLike | undefined>; /** The tabindex of the menu trigger. */ - tabindex = computed(() => (this.expanded() && this.submenu()?.inputs.activeItem() ? -1 : 0)); + tabindex = computed(() => (this.expanded() && this.menu()?.inputs.activeItem() ? -1 : 0)); /** Handles keyboard events for the menu trigger. */ keydownManager = computed(() => { @@ -529,7 +529,7 @@ export class MenuTriggerPattern { }); constructor(readonly inputs: MenuTriggerInputs) { - this.submenu = this.inputs.submenu; + this.menu = this.inputs.menu; } /** Handles keyboard events for the menu trigger. */ @@ -550,7 +550,7 @@ export class MenuTriggerPattern { if ( this.expanded() && !element?.contains(relatedTarget) && - !this.inputs.submenu()?.inputs.element()?.contains(relatedTarget) + !this.inputs.menu()?.inputs.element()?.contains(relatedTarget) ) { this.close(); } @@ -561,22 +561,22 @@ export class MenuTriggerPattern { this.expanded.set(true); if (opts?.first) { - this.inputs.submenu()?.first(); + this.inputs.menu()?.first(); } else if (opts?.last) { - this.inputs.submenu()?.last(); + this.inputs.menu()?.last(); } } /** Closes the menu. */ close(opts: {refocus?: boolean} = {}) { this.expanded.set(false); - this.submenu()?.listBehavior.unfocus(); + this.menu()?.listBehavior.unfocus(); if (opts.refocus) { this.inputs.element()?.focus(); } - let menuitems = this.inputs.submenu()?.inputs.items() ?? []; + let menuitems = this.inputs.menu()?.inputs.items() ?? []; while (menuitems.length) { const menuitem = menuitems.pop(); diff --git a/src/components-examples/aria/menu/menu-bar/menu-bar-example.html b/src/components-examples/aria/menu/menu-bar/menu-bar-example.html index 5b772ddf3e91..21a6f8f9b2b1 100644 --- a/src/components-examples/aria/menu/menu-bar/menu-bar-example.html +++ b/src/components-examples/aria/menu/menu-bar/menu-bar-example.html @@ -1,299 +1,299 @@ -
-
File
+
+
File
-
-
- article - New - ⌘N +
+
+ article + New + ⌘N
-
- folder - Open - ⌘O +
+ folder + Open + ⌘O
-
- file_copy - Make a copy +
+ file_copy + Make a copy
-
- person_add - Share - arrow_right +
+ person_add + Share + arrow_right
-
-
- person_add - Share with others +
+
+ person_add + Share with others
-
- public - Publish to web +
+ public + Publish to web
-
- download - Download +
+ download + Download
-
- print - Print +
+ print + Print
-
- edit - Rename +
+ edit + Rename
-
- delete - Move to trash +
+ delete + Move to trash
-
Edit
+
Edit
-
-
- undo - Undo - ⌘Z +
+
+ undo + Undo + ⌘Z
-
- redo - Redo - ⌘Y +
+ redo + Redo + ⌘Y
-
- content_cut - Cut - ⌘X +
+ content_cut + Cut + ⌘X
-
- content_copy - Copy - ⌘C +
+ content_copy + Copy + ⌘C
-
- content_paste - Paste - ⌘V +
+ content_paste + Paste + ⌘V
-
- find_replace - Find and replace - ⇧⌘H +
+ find_replace + Find and replace + ⇧⌘H
-
View
+
View
-
-
- check - Show print layout +
+
+ check + Show print layout
-
- check - Show ruler +
+ check + Show ruler
-
- Zoom in - ⌘+ +
+ Zoom in + ⌘+
-
- Zoom out - ⌘- +
+ Zoom out + ⌘-
-
- Full screen +
+ Full screen
-
Insert
+
Insert
-
-
- image - Image - arrow_right +
+
+ image + Image + arrow_right
-
-
- upload - Upload from computer +
+
+ upload + Upload from computer
-
- search - Search the web +
+ search + Search the web
-
- link - By URL +
+ link + By URL
-
- table_chart - Table +
+ table_chart + Table
-
- insert_chart - Chart - arrow_right +
+ insert_chart + Chart + arrow_right
-
-
- bar_chart - Bar +
+
+ bar_chart + Bar
-
- insert_chart - Column +
+ insert_chart + Column
-
- show_chart - Line +
+ show_chart + Line
-
- pie_chart - Pie +
+ pie_chart + Pie
-
- horizontal_rule - Horizontal line +
+ horizontal_rule + Horizontal line
-
Format
+
Format
-
-
- format_bold - Text - arrow_right +
+
+ format_bold + Text + arrow_right
-
-
- format_bold - Bold - ⌘B +
+
+ format_bold + Bold + ⌘B
-
- format_italic - Italic - ⌘I +
+ format_italic + Italic + ⌘I
-
- format_underlined - Underline - ⌘U +
+ format_underlined + Underline + ⌘U
-
- strikethrough_s - Strikethrough - ⇧⌘X +
+ strikethrough_s + Strikethrough + ⇧⌘X
-
- Size - arrow_right +
+ Size + arrow_right
-
-
- Increase font size - ⇧⌘. +
+
+ Increase font size + ⇧⌘.
-
- Decrease font size - ⇧⌘, +
+ Decrease font size + ⇧⌘,
-
- format_align_justify - Paragraph styles - arrow_right +
+ format_align_justify + Paragraph styles + arrow_right
-
-
Normal text
-
Heading 1
-
Heading 2
+
+
Normal text
+
Heading 1
+
Heading 2
-
- format_indent_increase - Align & indent - arrow_right +
+ format_indent_increase + Align & indent + arrow_right
-
-
- format_align_left - Align left +
+
+ format_align_left + Align left
-
- format_align_center - Align center +
+ format_align_center + Align center
-
- format_align_right - Align right +
+ format_align_right + Align right
-
- format_align_justify - Justify +
+ format_align_justify + Justify
diff --git a/src/components-examples/aria/menu/menu-context/menu-context-example.html b/src/components-examples/aria/menu/menu-context/menu-context-example.html index 7505025ffd42..ed2ab74c5787 100644 --- a/src/components-examples/aria/menu/menu-context/menu-context-example.html +++ b/src/components-examples/aria/menu/menu-context/menu-context-example.html @@ -3,39 +3,39 @@
-
- content_cut - Cut - ⌘X +
+ content_cut + Cut + ⌘X
-
- content_copy - Copy - ⌘C +
+ content_copy + Copy + ⌘C
-
- content_paste - Paste - arrow_right +
+ content_paste + Paste + arrow_right
-
-
- Paste as plain text - ⌘⇧V +
+
+ Paste as plain text + ⌘⇧V
-
- Paste without formatting - ⌘⇧V +
+ Paste without formatting + ⌘⇧V
diff --git a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html index 6a3419830193..ebafb8976e97 100644 --- a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html +++ b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html @@ -2,36 +2,36 @@ SECURITY
-
- lock_open - Change password +
+ lock_open + Change password
-
- security_key - Two-factor authentication +
+ security_key + Two-factor authentication
-
- refresh - Reset - arrow_right +
+ refresh + Reset + arrow_right
-
-
- email - Email address +
+
+ email + Email address
-
- phone - Phone number +
+ phone + Phone number
-
- vpn_key - Password +
+ vpn_key + Password
@@ -41,21 +41,21 @@ HELP
-
- help - Support +
+ help + Support
-
- feedback - Feedback +
+ feedback + Feedback
-
- logout - Logout +
+ logout + Logout
diff --git a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html index 4c857c37e6ca..41efd1f92bc7 100644 --- a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html +++ b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html @@ -1,6 +1,6 @@ -
-
- mark_email_read - Mark as read +
+
+ mark_email_read + Mark as read
-
- snooze - Snooze +
+ snooze + Snooze
-
- category - Categorize - arrow_right +
+ category + Categorize + arrow_right
-
-
- label_important - Mark as important +
+
+ label_important + Mark as important
-
- star - Star +
+ star + Star
-
- label - Label +
+ label + Label
-
- archive - Archive +
+ archive + Archive
-
- report - Report spam +
+ report + Report spam
-
- delete - Delete +
+ delete + Delete
diff --git a/src/components-examples/aria/menu/simple-menu.ts b/src/components-examples/aria/menu/simple-menu.ts index 17af13190dfc..9eb9c5b2decd 100644 --- a/src/components-examples/aria/menu/simple-menu.ts +++ b/src/components-examples/aria/menu/simple-menu.ts @@ -2,7 +2,7 @@ import {Menu, MenuBar, MenuItem, MenuTrigger} from '@angular/aria/menu'; import {afterRenderEffect, Directive, effect, inject} from '@angular/core'; @Directive({ - selector: '[menu]', + selector: '[ng-menu]', hostDirectives: [{directive: Menu, inputs: ['parent']}], host: { class: 'example-menu', @@ -49,14 +49,14 @@ export class SimpleMenu { } @Directive({ - selector: '[menu-bar]', + selector: '[ng-menu-bar]', hostDirectives: [{directive: MenuBar}], host: {class: 'example-menu-bar'}, }) export class SimpleMenuBar {} @Directive({ - selector: '[menu-bar-item]', + selector: '[ng-menu-bar-item]', hostDirectives: [{directive: MenuItem, inputs: ['value', 'submenu']}], host: {class: 'example-menu-bar-item'}, }) @@ -69,7 +69,7 @@ export class SimpleMenuBarItem { } @Directive({ - selector: '[menu-item]', + selector: '[ng-menu-item]', hostDirectives: [{directive: MenuItem, inputs: ['value', 'disabled', 'submenu']}], host: {class: 'example-menu-item'}, }) @@ -82,7 +82,7 @@ export class SimpleMenuItem { } @Directive({ - selector: '[menu-item-icon]', + selector: '[ng-menu-item-icon]', host: { 'aria-hidden': 'true', class: 'example-icon material-symbols-outlined', @@ -91,13 +91,13 @@ export class SimpleMenuItem { export class SimpleMenuItemIcon {} @Directive({ - selector: '[menu-item-text]', + selector: '[ng-menu-item-text]', host: {class: 'example-menu-item-text'}, }) export class SimpleMenuItemText {} @Directive({ - selector: '[menu-item-shortcut]', + selector: '[ng-menu-item-shortcut]', host: { 'aria-hidden': 'true', class: 'example-menu-item-shortcut', From 45cb88a360d33af9bbad32198d5b2008055ceb5a Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Tue, 28 Oct 2025 15:28:47 -0400 Subject: [PATCH 3/7] fix(aria/menu): defer rendering of menu content --- src/aria/menu/BUILD.bazel | 1 + src/aria/menu/index.ts | 2 +- src/aria/menu/menu.ts | 22 + .../aria/menu/menu-bar/menu-bar-example.html | 497 +++++++++--------- .../aria/menu/menu-bar/menu-bar-example.ts | 2 + .../menu-context/menu-context-example.html | 52 +- .../menu/menu-context/menu-context-example.ts | 3 +- .../menu-standalone-example.html | 92 ++-- .../menu-standalone-example.ts | 4 +- .../menu-trigger/menu-trigger-example.html | 88 ++-- .../menu/menu-trigger/menu-trigger-example.ts | 11 +- 11 files changed, 424 insertions(+), 350 deletions(-) diff --git a/src/aria/menu/BUILD.bazel b/src/aria/menu/BUILD.bazel index 8d77abf0b0e3..64d3f2e60123 100644 --- a/src/aria/menu/BUILD.bazel +++ b/src/aria/menu/BUILD.bazel @@ -11,6 +11,7 @@ ng_project( ), deps = [ "//:node_modules/@angular/core", + "//src/aria/deferred-content", "//src/aria/private", "//src/cdk/a11y", "//src/cdk/bidi", diff --git a/src/aria/menu/index.ts b/src/aria/menu/index.ts index 135a0a300210..baacdeadfc02 100644 --- a/src/aria/menu/index.ts +++ b/src/aria/menu/index.ts @@ -6,4 +6,4 @@ * found in the LICENSE file at https://angular.dev/license */ -export {Menu, MenuBar, MenuItem, MenuTrigger} from './menu'; +export {Menu, MenuBar, MenuContent, MenuItem, MenuTrigger} from './menu'; diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index e8b919cf7d22..20589b1e14c5 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -29,6 +29,7 @@ import { } from '@angular/aria/private'; import {toSignal} from '@angular/core/rxjs-interop'; import {Directionality} from '@angular/cdk/bidi'; +import {DeferredContent, DeferredContentAware} from '@angular/aria/deferred-content'; /** * A trigger for a menu. @@ -103,8 +104,17 @@ export class MenuTrigger { '(focusin)': '_pattern.onFocusIn()', '(click)': '_pattern.onClick($event)', }, + hostDirectives: [ + { + directive: DeferredContentAware, + inputs: ['preserveContent'], + }, + ], }) export class Menu { + /** The DeferredContentAware host directive. */ + private readonly _deferredContentAware = inject(DeferredContentAware, {optional: true}); + /** The menu items contained in the menu. */ readonly _allItems = contentChildren>(MenuItem, {descendants: true}); @@ -174,6 +184,10 @@ export class Menu { onSubmit: (value: V) => this.onSubmit.emit(value), }); + afterRenderEffect(() => { + this._deferredContentAware?.contentVisible.set(this._pattern.isVisible()); + }); + // TODO(wagnermaciel): This is a redundancy needed for if the user uses display: none to hide // submenus. In those cases, the ui pattern is calling focus() before the ui has a chance to // update the display property. The result is focus() being called on an element that is not @@ -360,3 +374,11 @@ export class MenuItem { submenu: computed(() => this.submenu()?._pattern), }); } + +/** Defers the rendering of the menu content. */ +@Directive({ + selector: 'ng-template[ngMenuContent]', + exportAs: 'ngMenuContent', + hostDirectives: [DeferredContent], +}) +export class MenuContent {} diff --git a/src/components-examples/aria/menu/menu-bar/menu-bar-example.html b/src/components-examples/aria/menu/menu-bar/menu-bar-example.html index 21a6f8f9b2b1..943fb690e05a 100644 --- a/src/components-examples/aria/menu/menu-bar/menu-bar-example.html +++ b/src/components-examples/aria/menu/menu-bar/menu-bar-example.html @@ -2,299 +2,328 @@
File
-
- article - New - ⌘N -
- -
- folder - Open - ⌘O -
- -
- file_copy - Make a copy -
- - - -
- person_add - Share - arrow_right -
- -
-
+ +
+ article + New + ⌘N +
+ +
+ folder + Open + ⌘O +
+ +
+ file_copy + Make a copy +
+ + + +
person_add - Share with others + Share + arrow_right
-
- public - Publish to web +
+ +
+ person_add + Share with others +
+ +
+ public + Publish to web +
+
-
-
- download - Download -
+
+ download + Download +
-
- print - Print -
+
+ print + Print +
- + -
- edit - Rename -
+
+ edit + Rename +
-
- delete - Move to trash -
+
+ delete + Move to trash +
+
Edit
-
- undo - Undo - ⌘Z -
- -
- redo - Redo - ⌘Y -
- - - -
- content_cut - Cut - ⌘X -
- -
- content_copy - Copy - ⌘C -
- -
- content_paste - Paste - ⌘V -
- - - -
- find_replace - Find and replace - ⇧⌘H -
-
- -
View
+ +
+ undo + Undo + ⌘Z +
-
-
- check - Show print layout -
+
+ redo + Redo + ⌘Y +
-
- check - Show ruler -
+ - +
+ content_cut + Cut + ⌘X +
-
- Zoom in - ⌘+ -
+
+ content_copy + Copy + ⌘C +
-
- Zoom out - ⌘- -
+
+ content_paste + Paste + ⌘V +
- + -
- Full screen -
+
+ find_replace + Find and replace + ⇧⌘H +
+
-
Insert
- -
-
- image - Image - arrow_right -
- -
-
- upload - Upload from computer -
+
View
-
- search - Search the web +
+ +
+ check + Show print layout
-
- link - By URL +
+ check + Show ruler
-
-
- table_chart - Table -
- -
- insert_chart - Chart - arrow_right -
+ -
-
- bar_chart - Bar +
+ Zoom in + ⌘+
-
- insert_chart - Column +
+ Zoom out + ⌘-
-
- show_chart - Line -
+ -
- pie_chart - Pie +
+ Full screen
-
- -
- horizontal_rule - Horizontal line -
+
-
Format
- -
-
- format_bold - Text - arrow_right -
- -
-
- format_bold - Bold - ⌘B -
+
Insert
-
- format_italic - Italic - ⌘I +
+ +
+ image + Image + arrow_right
-
- format_underlined - Underline - ⌘U +
+ +
+ upload + Upload from computer +
+ +
+ search + Search the web +
+ +
+ link + By URL +
+
-
- strikethrough_s - Strikethrough - ⇧⌘X +
+ table_chart + Table
- - -
- Size +
+ insert_chart + Chart arrow_right
-
-
- Increase font size - ⇧⌘. -
+
+ +
+ bar_chart + Bar +
+ +
+ insert_chart + Column +
+ +
+ show_chart + Line +
+ +
+ pie_chart + Pie +
+
+
-
- Decrease font size - ⇧⌘, -
+
+ horizontal_rule + Horizontal line
-
+ +
-
- format_align_justify - Paragraph styles - arrow_right -
+
Format
-
-
Normal text
-
Heading 1
-
Heading 2
-
+
+ +
+ format_bold + Text + arrow_right +
-
- format_indent_increase - Align & indent - arrow_right -
+
+ +
+ format_bold + Bold + ⌘B +
+ +
+ format_italic + Italic + ⌘I +
+ +
+ format_underlined + Underline + ⌘U +
+ +
+ strikethrough_s + Strikethrough + ⇧⌘X +
+ + + +
+ Size + arrow_right +
+ +
+ +
+ Increase font size + ⇧⌘. +
+ +
+ Decrease font size + ⇧⌘, +
+
+
+
+
-
-
- format_align_left - Align left +
+ format_align_justify + Paragraph styles + arrow_right
-
- format_align_center - Align center +
+ +
Normal text
+
Heading 1
+
Heading 2
+
-
- format_align_right - Align right +
+ format_indent_increase + Align & indent + arrow_right
-
- format_align_justify - Justify +
+ +
+ format_align_left + Align left +
+ +
+ format_align_center + Align center +
+ +
+ format_align_right + Align right +
+ +
+ format_align_justify + Justify +
+
-
+
diff --git a/src/components-examples/aria/menu/menu-bar/menu-bar-example.ts b/src/components-examples/aria/menu/menu-bar/menu-bar-example.ts index fd3aa5768f7d..912d2eed22ba 100644 --- a/src/components-examples/aria/menu/menu-bar/menu-bar-example.ts +++ b/src/components-examples/aria/menu/menu-bar/menu-bar-example.ts @@ -8,6 +8,7 @@ import { SimpleMenuItemShortcut, SimpleMenuItemText, } from '../simple-menu'; +import {MenuContent} from '@angular/aria/menu'; /** @title Menu bar example. */ @Component({ @@ -24,6 +25,7 @@ import { SimpleMenuItemIcon, SimpleMenuItemText, SimpleMenuItemShortcut, + MenuContent, ], }) export class MenuBarExample {} diff --git a/src/components-examples/aria/menu/menu-context/menu-context-example.html b/src/components-examples/aria/menu/menu-context/menu-context-example.html index ed2ab74c5787..dbcf2bc729bd 100644 --- a/src/components-examples/aria/menu/menu-context/menu-context-example.html +++ b/src/components-examples/aria/menu/menu-context/menu-context-example.html @@ -9,33 +9,37 @@ (focusout)="close($event)" class="example-context-menu" > -
- content_cut - Cut - ⌘X -
- -
- content_copy - Copy - ⌘C -
+ +
+ content_cut + Cut + ⌘X +
-
- content_paste - Paste - arrow_right -
+
+ content_copy + Copy + ⌘C +
-
-
- Paste as plain text - ⌘⇧V +
+ content_paste + Paste + arrow_right
-
- Paste without formatting - ⌘⇧V +
+ +
+ Paste as plain text + ⌘⇧V +
+ +
+ Paste without formatting + ⌘⇧V +
+
-
+
diff --git a/src/components-examples/aria/menu/menu-context/menu-context-example.ts b/src/components-examples/aria/menu/menu-context/menu-context-example.ts index ecc94334ecee..8e5c07bdae5a 100644 --- a/src/components-examples/aria/menu/menu-context/menu-context-example.ts +++ b/src/components-examples/aria/menu/menu-context/menu-context-example.ts @@ -1,5 +1,5 @@ import {Component, viewChild} from '@angular/core'; -import {Menu} from '@angular/aria/menu'; +import {Menu, MenuContent} from '@angular/aria/menu'; import { SimpleMenu, SimpleMenuItem, @@ -21,6 +21,7 @@ import { SimpleMenuItemText, SimpleMenuItemIcon, SimpleMenuItemShortcut, + MenuContent, ], }) export class MenuContextExample { diff --git a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html index ebafb8976e97..18c93821cf96 100644 --- a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html +++ b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html @@ -1,61 +1,65 @@
- SECURITY + + SECURITY -
-
- lock_open - Change password -
- -
- security_key - Two-factor authentication -
- -
- refresh - Reset - arrow_right -
+
+
+ lock_open + Change password +
-
-
- email - Email address +
+ security_key + Two-factor authentication
-
- phone - Phone number +
+ refresh + Reset + arrow_right
-
- vpn_key - Password +
+ +
+ email + Email address +
+ +
+ phone + Phone number +
+ +
+ vpn_key + Password +
+
-
- + - HELP + HELP -
-
- help - Support -
+
+
+ help + Support +
-
- feedback - Feedback +
+ feedback + Feedback +
-
- + -
- logout - Logout -
+
+ logout + Logout +
+
diff --git a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.ts b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.ts index e2c12304b18a..f720e1c4a8e6 100644 --- a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.ts +++ b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import {Menu} from '@angular/aria/menu'; +import {Menu, MenuContent} from '@angular/aria/menu'; import {SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText} from '../simple-menu'; /** @@ -11,6 +11,6 @@ import {SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText} from templateUrl: 'menu-standalone-example.html', styleUrl: '../menu-example.css', standalone: true, - imports: [Menu, SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText], + imports: [Menu, MenuContent, SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText], }) export class MenuStandaloneExample {} diff --git a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html index 41efd1f92bc7..1e4ee66abe37 100644 --- a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html +++ b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html @@ -9,55 +9,59 @@
-
- mark_email_read - Mark as read -
- -
- snooze - Snooze -
- - - -
- category - Categorize - arrow_right -
- -
-
- label_important - Mark as important + +
+ mark_email_read + Mark as read
-
- star - Star +
+ snooze + Snooze
-
- label - Label + + +
+ category + Categorize + arrow_right +
+ +
+ +
+ label_important + Mark as important +
+ +
+ star + Star +
+ +
+ label + Label +
+
-
- + -
- archive - Archive -
+
+ archive + Archive +
-
- report - Report spam -
+
+ report + Report spam +
-
- delete - Delete -
+
+ delete + Delete +
+
diff --git a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.ts b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.ts index 0cf84e867441..b4acbdacae88 100644 --- a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.ts +++ b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import {MenuTrigger} from '@angular/aria/menu'; +import {MenuTrigger, MenuContent} from '@angular/aria/menu'; import {SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText} from '../simple-menu'; /** @title Menu trigger example. */ @@ -9,6 +9,13 @@ import {SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText} from templateUrl: 'menu-trigger-example.html', styleUrl: '../menu-example.css', standalone: true, - imports: [SimpleMenu, SimpleMenuItem, SimpleMenuItemIcon, SimpleMenuItemText, MenuTrigger], + imports: [ + MenuContent, + MenuTrigger, + SimpleMenu, + SimpleMenuItem, + SimpleMenuItemIcon, + SimpleMenuItemText, + ], }) export class MenuTriggerExample {} From 2f008ce35e18670190b39b2dc10b5a4a3c4bcf01 Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Tue, 28 Oct 2025 15:59:41 -0400 Subject: [PATCH 4/7] refactor(aria/menu): remove parent input --- src/aria/menu/menu.spec.ts | 24 +++++----- src/aria/menu/menu.ts | 11 ++++- .../aria/menu/menu-bar/menu-bar-example.html | 48 +++++++++---------- .../menu-context/menu-context-example.html | 4 +- .../menu-standalone-example.html | 4 +- .../menu-trigger/menu-trigger-example.html | 7 ++- .../aria/menu/simple-menu.ts | 2 +- 7 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/aria/menu/menu.spec.ts b/src/aria/menu/menu.spec.ts index 103216db1ed8..f849a866d62a 100644 --- a/src/aria/menu/menu.spec.ts +++ b/src/aria/menu/menu.spec.ts @@ -880,9 +880,9 @@ describe('Menu Bar Pattern', () => {
Apple
Banana
-
Berries
+
Berries
-
+
Blueberry
Blackberry
Strawberry
@@ -899,14 +899,14 @@ class StandaloneMenuExample { @Component({ template: ` - + -
+
Apple
Banana
-
Berries
+
Berries
-
+
Blueberry
Blackberry
Strawberry
@@ -923,24 +923,24 @@ class MenuTriggerExample {} template: `
File
-
Edit
+
Edit
-
+
Undo
Redo
-
View
+
View
-
+
Zoom In
Zoom Out
Full Screen
-
Help
+
Help
-
+
Documentation
About
diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index 20589b1e14c5..76ceaac601e2 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -11,6 +11,7 @@ import { computed, contentChildren, Directive, + effect, ElementRef, inject, input, @@ -71,6 +72,10 @@ export class MenuTrigger { element: computed(() => this._elementRef.nativeElement), menu: computed(() => this.menu()?._pattern), }); + + constructor() { + effect(() => this.menu()?.parent.set(this)); + } } /** @@ -150,7 +155,7 @@ export class Menu { readonly typeaheadDelay = input(0.5); // Picked arbitrarily. /** A reference to the parent menu item or menu trigger. */ - readonly parent = input | MenuItem>(); + readonly parent = signal | MenuItem | undefined>(undefined); /** The menu ui pattern instance. */ readonly _pattern: MenuPattern; @@ -373,6 +378,10 @@ export class MenuItem { parent: computed(() => this.parent?._pattern), submenu: computed(() => this.submenu()?._pattern), }); + + constructor() { + effect(() => this.submenu()?.parent.set(this)); + } } /** Defers the rendering of the menu content. */ diff --git a/src/components-examples/aria/menu/menu-bar/menu-bar-example.html b/src/components-examples/aria/menu/menu-bar/menu-bar-example.html index 943fb690e05a..6d2f4406768b 100644 --- a/src/components-examples/aria/menu/menu-bar/menu-bar-example.html +++ b/src/components-examples/aria/menu/menu-bar/menu-bar-example.html @@ -1,7 +1,7 @@
-
File
+
File
-
+
article @@ -22,13 +22,13 @@ -
+
person_add Share arrow_right
-
+
person_add @@ -66,9 +66,9 @@
-
Edit
+
Edit
-
+
undo @@ -112,9 +112,9 @@
-
View
+
View
-
+
check @@ -146,17 +146,17 @@
-
Insert
+
Insert
-
+
-
+
image Image arrow_right
-
+
upload @@ -180,13 +180,13 @@ Table
-
+
insert_chart Chart arrow_right
-
+
bar_chart @@ -217,17 +217,17 @@
-
Format
+
Format
-
+
-
+
format_bold Text arrow_right
-
+
format_bold @@ -255,12 +255,12 @@ -
+
Size arrow_right
-
+
Increase font size @@ -280,14 +280,14 @@ ng-menu-item value="Paragraph styles" [submenu]="paragraphMenu" - #paragraphItem="ngMenuItem" + > format_align_justify Paragraph styles arrow_right
-
+
Normal text
Heading 1
@@ -295,13 +295,13 @@
-
+
format_indent_increase Align & indent arrow_right
-
+
format_align_left diff --git a/src/components-examples/aria/menu/menu-context/menu-context-example.html b/src/components-examples/aria/menu/menu-context/menu-context-example.html index dbcf2bc729bd..cf2ee2fea501 100644 --- a/src/components-examples/aria/menu/menu-context/menu-context-example.html +++ b/src/components-examples/aria/menu/menu-context/menu-context-example.html @@ -22,13 +22,13 @@ ⌘C
-
+
content_paste Paste arrow_right
-
+
Paste as plain text diff --git a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html index 18c93821cf96..ad7fd866e21b 100644 --- a/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html +++ b/src/components-examples/aria/menu/menu-standalone/menu-standalone-example.html @@ -13,13 +13,13 @@ Two-factor authentication
-
+
refresh Reset arrow_right
-
+
email diff --git a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html index 1e4ee66abe37..686b5d81b85e 100644 --- a/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html +++ b/src/components-examples/aria/menu/menu-trigger/menu-trigger-example.html @@ -2,13 +2,12 @@ ngMenuTrigger [menu]="formatMenu" aria-label="Open menu" - #trigger="ngMenuTrigger" class="example-menu-trigger" > -
+
mark_email_read @@ -22,13 +21,13 @@ -
+
category Categorize arrow_right
-
+
label_important diff --git a/src/components-examples/aria/menu/simple-menu.ts b/src/components-examples/aria/menu/simple-menu.ts index 9eb9c5b2decd..d00a0651854b 100644 --- a/src/components-examples/aria/menu/simple-menu.ts +++ b/src/components-examples/aria/menu/simple-menu.ts @@ -3,7 +3,7 @@ import {afterRenderEffect, Directive, effect, inject} from '@angular/core'; @Directive({ selector: '[ng-menu]', - hostDirectives: [{directive: Menu, inputs: ['parent']}], + hostDirectives: [{directive: Menu}], host: { class: 'example-menu', popover: 'manual', From 36cd689fba5da660c6fd3078e44117799a01eb66 Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Tue, 28 Oct 2025 16:05:02 -0400 Subject: [PATCH 5/7] refactor(aria/menu): remove submenu input --- src/aria/menu/menu.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index 76ceaac601e2..4b470173162b 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -142,9 +142,6 @@ export class Menu { initialValue: this._directionality.value, }); - /** The submenu associated with the menu. */ - readonly submenu = input | undefined>(undefined); - /** The unique ID of the menu. */ readonly id = input(Math.random().toString(36).substring(2, 10)); From 427d510e3f68bca555bd645faacd9246d065d13d Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Tue, 28 Oct 2025 16:07:42 -0400 Subject: [PATCH 6/7] refactor(aria/menu): rename onSubmit to onSelect --- src/aria/menu/menu.spec.ts | 36 +++++++++++++++--------------- src/aria/menu/menu.ts | 10 ++++----- src/aria/private/menu/menu.spec.ts | 20 ++++++++--------- src/aria/private/menu/menu.ts | 8 +++---- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/aria/menu/menu.spec.ts b/src/aria/menu/menu.spec.ts index f849a866d62a..8e799347c103 100644 --- a/src/aria/menu/menu.spec.ts +++ b/src/aria/menu/menu.spec.ts @@ -151,49 +151,49 @@ describe('Standalone Menu Pattern', () => { it('should select an item on click', () => { const banana = getItem('Banana'); - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); click(banana!); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Banana'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Banana'); }); it('should select an item on enter', () => { const banana = getItem('Banana'); - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); keydown(document.activeElement!, 'ArrowDown'); // Move focus to Banana expect(document.activeElement).toBe(banana); keydown(banana!, 'Enter'); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Banana'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Banana'); }); it('should select an item on space', () => { const banana = getItem('Banana'); - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); keydown(document.activeElement!, 'ArrowDown'); // Move focus to Banana expect(document.activeElement).toBe(banana); keydown(banana!, ' '); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Banana'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Banana'); }); it('should not select a disabled item', () => { const cherry = getItem('Cherry'); - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); click(cherry!); - expect(fixture.componentInstance.onSubmit).not.toHaveBeenCalled(); + expect(fixture.componentInstance.onSelect).not.toHaveBeenCalled(); keydown(document.activeElement!, 'End'); expect(document.activeElement).toBe(cherry); keydown(cherry!, 'Enter'); - expect(fixture.componentInstance.onSubmit).not.toHaveBeenCalled(); + expect(fixture.componentInstance.onSelect).not.toHaveBeenCalled(); keydown(cherry!, ' '); - expect(fixture.componentInstance.onSubmit).not.toHaveBeenCalled(); + expect(fixture.componentInstance.onSelect).not.toHaveBeenCalled(); }); }); @@ -316,18 +316,18 @@ describe('Standalone Menu Pattern', () => { })); it('should close on selecting an item on click', () => { - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); click(getItem('Berries')!); // open submenu expect(isSubmenuExpanded()).toBe(true); click(getItem('Blueberry')!); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Blueberry'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Blueberry'); expect(isSubmenuExpanded()).toBe(false); }); it('should close on selecting an item on enter', () => { - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); @@ -341,12 +341,12 @@ describe('Standalone Menu Pattern', () => { keydown(blueberry!, 'Enter'); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Blueberry'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Blueberry'); expect(isSubmenuExpanded()).toBe(false); }); it('should close on selecting an item on space', () => { - spyOn(fixture.componentInstance, 'onSubmit'); + spyOn(fixture.componentInstance, 'onSelect'); const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); @@ -360,7 +360,7 @@ describe('Standalone Menu Pattern', () => { keydown(blueberry!, ' '); - expect(fixture.componentInstance.onSubmit).toHaveBeenCalledWith('Blueberry'); + expect(fixture.componentInstance.onSelect).toHaveBeenCalledWith('Blueberry'); expect(isSubmenuExpanded()).toBe(false); }); @@ -877,7 +877,7 @@ describe('Menu Bar Pattern', () => { @Component({ template: ` -
+
Apple
Banana
Berries
@@ -894,7 +894,7 @@ describe('Menu Bar Pattern', () => { imports: [Menu, MenuItem], }) class StandaloneMenuExample { - onSubmit(value: string) {} + onSelect(value: string) {} } @Component({ diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index 4b470173162b..699672a7787c 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -65,7 +65,7 @@ export class MenuTrigger { menu = input | undefined>(undefined); /** A callback function triggered when a menu item is selected. */ - onSubmit = output(); + onSelect = output(); /** The menu trigger ui pattern instance. */ _pattern: MenuTriggerPattern = new MenuTriggerPattern({ @@ -170,7 +170,7 @@ export class Menu { isVisible = computed(() => this._pattern.isVisible()); /** A callback function triggered when a menu item is selected. */ - onSubmit = output(); + onSelect = output(); constructor() { this._pattern = new MenuPattern({ @@ -183,7 +183,7 @@ export class Menu { selectionMode: () => 'explicit', activeItem: signal(undefined), element: computed(() => this._elementRef.nativeElement), - onSubmit: (value: V) => this.onSubmit.emit(value), + onSelect: (value: V) => this.onSelect.emit(value), }); afterRenderEffect(() => { @@ -286,7 +286,7 @@ export class MenuBar { readonly items = signal[]>([]); /** A callback function triggered when a menu item is selected. */ - onSubmit = output(); + onSelect = output(); constructor() { this._pattern = new MenuBarPattern({ @@ -296,7 +296,7 @@ export class MenuBar { focusMode: () => 'roving', orientation: () => 'horizontal', selectionMode: () => 'explicit', - onSubmit: (value: V) => this.onSubmit.emit(value), + onSelect: (value: V) => this.onSelect.emit(value), activeItem: signal(undefined), element: computed(() => this._elementRef.nativeElement), }); diff --git a/src/aria/private/menu/menu.spec.ts b/src/aria/private/menu/menu.spec.ts index 50dad6b65de4..bfce2d3b161a 100644 --- a/src/aria/private/menu/menu.spec.ts +++ b/src/aria/private/menu/menu.spec.ts @@ -244,43 +244,43 @@ describe('Standalone Menu Pattern', () => { describe('Selection', () => { it('should select an item on click', () => { const items = menu.inputs.items(); - menu.inputs.onSubmit = jasmine.createSpy('onSubmit'); + menu.inputs.onSelect = jasmine.createSpy('onSelect'); menu.onClick(clickMenuItem(items, 1)); - expect(menu.inputs.onSubmit).toHaveBeenCalledWith('b'); + expect(menu.inputs.onSelect).toHaveBeenCalledWith('b'); }); it('should select an item on enter', () => { const items = menu.inputs.items(); menu.inputs.activeItem.set(items[1]); - menu.inputs.onSubmit = jasmine.createSpy('onSubmit'); + menu.inputs.onSelect = jasmine.createSpy('onSelect'); menu.onKeydown(enter()); - expect(menu.inputs.onSubmit).toHaveBeenCalledWith('b'); + expect(menu.inputs.onSelect).toHaveBeenCalledWith('b'); }); it('should select an item on space', () => { const items = menu.inputs.items(); menu.inputs.activeItem.set(items[1]); - menu.inputs.onSubmit = jasmine.createSpy('onSubmit'); + menu.inputs.onSelect = jasmine.createSpy('onSelect'); menu.onKeydown(space()); - expect(menu.inputs.onSubmit).toHaveBeenCalledWith('b'); + expect(menu.inputs.onSelect).toHaveBeenCalledWith('b'); }); it('should not select a disabled item', () => { const items = menu.inputs.items() as TestMenuItem[]; items[1].disabled.set(true); menu.inputs.activeItem.set(items[1]); - menu.inputs.onSubmit = jasmine.createSpy('onSubmit'); + menu.inputs.onSelect = jasmine.createSpy('onSelect'); menu.onClick(clickMenuItem(items, 1)); - expect(menu.inputs.onSubmit).not.toHaveBeenCalled(); + expect(menu.inputs.onSelect).not.toHaveBeenCalled(); menu.onKeydown(enter()); - expect(menu.inputs.onSubmit).not.toHaveBeenCalled(); + expect(menu.inputs.onSelect).not.toHaveBeenCalled(); menu.onKeydown(space()); - expect(menu.inputs.onSubmit).not.toHaveBeenCalled(); + expect(menu.inputs.onSelect).not.toHaveBeenCalled(); }); }); diff --git a/src/aria/private/menu/menu.ts b/src/aria/private/menu/menu.ts index fcd05d71395a..e49dfa1e5dbc 100644 --- a/src/aria/private/menu/menu.ts +++ b/src/aria/private/menu/menu.ts @@ -17,7 +17,7 @@ export interface MenuBarInputs extends Omit, V> items: SignalLike[]>; /** Callback function triggered when a menu item is selected. */ - onSubmit?: (value: V) => void; + onSelect?: (value: V) => void; } /** The inputs for the MenuPattern class. */ @@ -33,7 +33,7 @@ export interface MenuInputs parent: SignalLike | MenuItemPattern | undefined>; /** Callback function triggered when a menu item is selected. */ - onSubmit?: (value: V) => void; + onSelect?: (value: V) => void; } /** The inputs for the MenuTriggerPattern class. */ @@ -311,12 +311,12 @@ export class MenuPattern { if (!item.submenu() && isMenuBar) { root.close(); - root?.inputs.onSubmit?.(item.value()); + root?.inputs.onSelect?.(item.value()); } if (!item.submenu() && isMenu) { root.inputs.activeItem()?.close({refocus: true}); - root?.inputs.onSubmit?.(item.value()); + root?.inputs.onSelect?.(item.value()); } } } From 17bb9c6f614fc721f6f58b1f370821106b52372d Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Tue, 28 Oct 2025 16:13:09 -0400 Subject: [PATCH 7/7] refactor(aria/menu): remove onSelect from MenuTrigger --- src/aria/menu/menu.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/aria/menu/menu.ts b/src/aria/menu/menu.ts index 699672a7787c..b1ead192bec0 100644 --- a/src/aria/menu/menu.ts +++ b/src/aria/menu/menu.ts @@ -64,9 +64,6 @@ export class MenuTrigger { /** The menu associated with the trigger. */ menu = input | undefined>(undefined); - /** A callback function triggered when a menu item is selected. */ - onSelect = output(); - /** The menu trigger ui pattern instance. */ _pattern: MenuTriggerPattern = new MenuTriggerPattern({ element: computed(() => this._elementRef.nativeElement),