diff --git a/core/src/components/menu/menu-interface.ts b/core/src/components/menu/menu-interface.ts index 0361f207fb..9f1c4f3e8c 100644 --- a/core/src/components/menu/menu-interface.ts +++ b/core/src/components/menu/menu-interface.ts @@ -1,4 +1,4 @@ -import type { Animation } from '../../interface'; +import type { Animation, AnimationBuilder } from '@utils/animation/animation-interface'; export type Side = 'start' | 'end'; @@ -26,13 +26,23 @@ export interface MenuI { } export interface MenuControllerI { + registerAnimation(name: string, animation: AnimationBuilder): void; + get(menu?: string | null, logOnMultipleSideMenus?: boolean): Promise; + getMenus(): Promise; + getOpen(): Promise; + isEnabled(menu?: string | null): Promise; + swipeGesture(shouldEnable: boolean, menu?: string | null): Promise; + isAnimating(): Promise; + isOpen(menu?: string | null): Promise; + enable(shouldEnable: boolean, menu?: string | null): Promise; + toggle(menu?: string | null): Promise; + close(menu?: string | null): Promise; + open(menu?: string | null): Promise; + _getOpenSync(): HTMLIonMenuElement | undefined; _createAnimation(type: string, menuCmp: MenuI): Promise; - _setOpen(menu: MenuI, shouldOpen: boolean, animated: boolean): Promise; _register(menu: MenuI): void; _unregister(menu: MenuI): void; - - getMenus(): Promise; - getOpenSync(): HTMLIonMenuElement | undefined; + _setOpen(menu: MenuI, shouldOpen: boolean, animated: boolean): Promise; } export interface MenuChangeEventDetail { diff --git a/core/src/utils/menu-controller/index.ts b/core/src/utils/menu-controller/index.ts index a0e6cf25f7..ab5a1ffc01 100644 --- a/core/src/utils/menu-controller/index.ts +++ b/core/src/utils/menu-controller/index.ts @@ -1,6 +1,6 @@ import { printIonWarning } from '@utils/logging'; -import type { MenuI } from '../../components/menu/menu-interface'; +import type { MenuI, MenuControllerI } from '../../components/menu/menu-interface'; import type { AnimationBuilder, BackButtonEvent } from '../../interface'; import { MENU_BACK_BUTTON_PRIORITY } from '../hardware-back-button'; import { componentOnReady } from '../helpers'; @@ -9,7 +9,7 @@ import { menuOverlayAnimation } from './animations/overlay'; import { menuPushAnimation } from './animations/push'; import { menuRevealAnimation } from './animations/reveal'; -const createMenuController = () => { +const createMenuController = (): MenuControllerI => { const menuAnimations = new Map(); const menus: MenuI[] = []; diff --git a/packages/angular/common/src/providers/menu-controller.ts b/packages/angular/common/src/providers/menu-controller.ts index ba1876e23b..0a197b1f5b 100644 --- a/packages/angular/common/src/providers/menu-controller.ts +++ b/packages/angular/common/src/providers/menu-controller.ts @@ -1,17 +1,15 @@ -import { Injectable } from '@angular/core'; -import { menuController } from '@ionic/core/components'; +import type { MenuControllerI } from '@ionic/core/components'; -@Injectable({ - providedIn: 'root', -}) export class MenuController { + constructor(private menuController: MenuControllerI) {} + /** * Programmatically open the Menu. * @param [menuId] Optionally get the menu by its id, or side. * @return returns a promise when the menu is fully opened */ open(menuId?: string): Promise { - return menuController.open(menuId); + return this.menuController.open(menuId); } /** @@ -22,7 +20,7 @@ export class MenuController { * @return returns a promise when the menu is fully closed */ close(menuId?: string): Promise { - return menuController.close(menuId); + return this.menuController.close(menuId); } /** @@ -32,7 +30,7 @@ export class MenuController { * @return returns a promise when the menu has been toggled */ toggle(menuId?: string): Promise { - return menuController.toggle(menuId); + return this.menuController.toggle(menuId); } /** @@ -44,7 +42,7 @@ export class MenuController { * @return Returns the instance of the menu, which is useful for chaining. */ enable(shouldEnable: boolean, menuId?: string): Promise { - return menuController.enable(shouldEnable, menuId); + return this.menuController.enable(shouldEnable, menuId); } /** @@ -54,7 +52,7 @@ export class MenuController { * @return Returns the instance of the menu, which is useful for chaining. */ swipeGesture(shouldEnable: boolean, menuId?: string): Promise { - return menuController.swipeGesture(shouldEnable, menuId); + return this.menuController.swipeGesture(shouldEnable, menuId); } /** @@ -63,7 +61,7 @@ export class MenuController { * If the menuId is not specified, it returns true if ANY menu is currenly open. */ isOpen(menuId?: string): Promise { - return menuController.isOpen(menuId); + return this.menuController.isOpen(menuId); } /** @@ -71,7 +69,7 @@ export class MenuController { * @return Returns true if the menu is currently enabled, otherwise false. */ isEnabled(menuId?: string): Promise { - return menuController.isEnabled(menuId); + return this.menuController.isEnabled(menuId); } /** @@ -84,20 +82,20 @@ export class MenuController { * @return Returns the instance of the menu if found, otherwise `null`. */ get(menuId?: string): Promise { - return menuController.get(menuId); + return this.menuController.get(menuId); } /** * @return Returns the instance of the menu already opened, otherwise `null`. */ getOpen(): Promise { - return menuController.getOpen(); + return this.menuController.getOpen(); } /** * @return Returns an array of all menu instances. */ getMenus(): Promise { - return menuController.getMenus(); + return this.menuController.getMenus(); } } diff --git a/packages/angular/src/index.ts b/packages/angular/src/index.ts index a64ef4341f..6db8e3d7d2 100644 --- a/packages/angular/src/index.ts +++ b/packages/angular/src/index.ts @@ -23,7 +23,6 @@ export { ActionSheetController, AlertController, LoadingController, - MenuController, ModalController, PickerController, PopoverController, @@ -42,6 +41,7 @@ export { ViewDidEnter, ViewDidLeave, } from '@ionic/angular/common'; +export { MenuController } from './providers/menu-controller'; // PACKAGE MODULE export { IonicModule } from './ionic-module'; diff --git a/packages/angular/src/providers/menu-controller.ts b/packages/angular/src/providers/menu-controller.ts new file mode 100644 index 0000000000..04f9c6ddc5 --- /dev/null +++ b/packages/angular/src/providers/menu-controller.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@angular/core'; +import { MenuController as MenuControllerBase } from '@ionic/angular/common'; +import { menuController } from '@ionic/core'; + +@Injectable({ + providedIn: 'root', +}) +export class MenuController extends MenuControllerBase { + constructor() { + super(menuController); + } +} diff --git a/packages/angular/standalone/src/index.ts b/packages/angular/standalone/src/index.ts index 6b675977fe..36d8c2bf27 100644 --- a/packages/angular/standalone/src/index.ts +++ b/packages/angular/standalone/src/index.ts @@ -5,11 +5,11 @@ export { IonRouterOutlet } from './navigation/router-outlet'; export { IonRouterLink, IonRouterLinkWithHref } from './navigation/router-link-delegate'; export { IonTabs } from './navigation/tabs'; export { provideIonicAngular } from './providers/ionic-angular'; +export { MenuController } from './providers/menu-controller'; export { ActionSheetController, AlertController, LoadingController, - MenuController, ModalController, PickerController, PopoverController, diff --git a/packages/angular/standalone/src/providers/menu-controller.ts b/packages/angular/standalone/src/providers/menu-controller.ts new file mode 100644 index 0000000000..fa1f50f0d4 --- /dev/null +++ b/packages/angular/standalone/src/providers/menu-controller.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@angular/core'; +import { MenuController as MenuControllerBase } from '@ionic/angular/common'; +import { menuController } from '@ionic/core/components'; + +@Injectable({ + providedIn: 'root', +}) +export class MenuController extends MenuControllerBase { + constructor() { + super(menuController); + } +} diff --git a/packages/angular/test/base/e2e/src/lazy/providers.spec.ts b/packages/angular/test/base/e2e/src/lazy/providers.spec.ts index 215aa13cb4..0920ed35cd 100644 --- a/packages/angular/test/base/e2e/src/lazy/providers.spec.ts +++ b/packages/angular/test/base/e2e/src/lazy/providers.spec.ts @@ -27,5 +27,11 @@ describe('Providers', () => { cy.get('#query-params').should('have.text', 'firstParam: abc, firstParam: true'); }) + + // https://github.com/ionic-team/ionic-framework/issues/28337 + it('should register menus correctly', () => { + cy.get('#set-menu-count').click(); + cy.get('#registered-menu-count').should('have.text', '1'); + }); }); diff --git a/packages/angular/test/base/e2e/src/standalone/menu-controller.spec.ts b/packages/angular/test/base/e2e/src/standalone/menu-controller.spec.ts new file mode 100644 index 0000000000..b4dfd7245b --- /dev/null +++ b/packages/angular/test/base/e2e/src/standalone/menu-controller.spec.ts @@ -0,0 +1,11 @@ +describe('Menu Controller', () => { + beforeEach(() => { + cy.visit('/standalone/menu-controller'); + }) + + // https://github.com/ionic-team/ionic-framework/issues/28337 + it('should register menus correctly', () => { + cy.get('#set-menu-count').click(); + cy.get('#registered-menu-count').should('have.text', '1'); + }); +}) diff --git a/packages/angular/test/base/src/app/lazy/providers/providers.component.html b/packages/angular/test/base/src/app/lazy/providers/providers.component.html index f198ba6518..981847ac24 100644 --- a/packages/angular/test/base/src/app/lazy/providers/providers.component.html +++ b/packages/angular/test/base/src/app/lazy/providers/providers.component.html @@ -1,39 +1,48 @@ + + Menu Content + + - - - Providers Test - - - - -

- isLoaded: {{isLoaded}} -

-

- isReady: {{isReady}} -

-

- isResumed: {{isResumed}} -

-

- isPaused: {{isPaused}} -

-

- isResized: {{isResized}} -

-

- isTesting: {{isTesting}} -

-

- isDesktop: {{isDesktop}} -

-

- isMobile: {{isMobile}} -

-

- keyboardHeight: {{keyboardHeight}} -

-

- queryParams: {{queryParams}} -

-
+ + + Providers Test + + + + +

+ isLoaded: {{isLoaded}} +

+

+ isReady: {{isReady}} +

+

+ isResumed: {{isResumed}} +

+

+ isPaused: {{isPaused}} +

+

+ isResized: {{isResized}} +

+

+ isTesting: {{isTesting}} +

+

+ isDesktop: {{isDesktop}} +

+

+ isMobile: {{isMobile}} +

+

+ keyboardHeight: {{keyboardHeight}} +

+

+ queryParams: {{queryParams}} +

+

+ Registered Menu Count: {{registeredMenuCount}} +

+ + +
diff --git a/packages/angular/test/base/src/app/lazy/providers/providers.component.ts b/packages/angular/test/base/src/app/lazy/providers/providers.component.ts index 3ef12a0eee..c65a85600f 100644 --- a/packages/angular/test/base/src/app/lazy/providers/providers.component.ts +++ b/packages/angular/test/base/src/app/lazy/providers/providers.component.ts @@ -21,12 +21,13 @@ export class ProvidersComponent { isMobile?: boolean = undefined; keyboardHeight = 0; queryParams = ''; + registeredMenuCount = 0; constructor( actionSheetCtrl: ActionSheetController, alertCtrl: AlertController, loadingCtrl: LoadingController, - menuCtrl: MenuController, + private menuCtrl: MenuController, pickerCtrl: PickerController, modalCtrl: ModalController, platform: Platform, @@ -82,4 +83,9 @@ export class ProvidersComponent { window.dispatchEvent(new CustomEvent('resize')); }); } + + async setMenuCount() { + const menus = await this.menuCtrl.getMenus(); + this.registeredMenuCount = menus.length; + } } diff --git a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts index 93e869651a..d5618a3ce8 100644 --- a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts +++ b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts @@ -6,6 +6,7 @@ export const routes: Routes = [ path: '', component: AppComponent, children: [ + { path: 'menu-controller', loadComponent: () => import('../menu-controller/menu-controller.component').then(c => c.MenuControllerComponent) }, { path: 'popover', loadComponent: () => import('../popover/popover.component').then(c => c.PopoverComponent) }, { path: 'modal', loadComponent: () => import('../modal/modal.component').then(c => c.ModalComponent) }, { path: 'router-outlet', loadComponent: () => import('../router-outlet/router-outlet.component').then(c => c.RouterOutletComponent) }, diff --git a/packages/angular/test/base/src/app/standalone/menu-controller/menu-controller.component.html b/packages/angular/test/base/src/app/standalone/menu-controller/menu-controller.component.html new file mode 100644 index 0000000000..0d9df71538 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/menu-controller/menu-controller.component.html @@ -0,0 +1,10 @@ + + Menu Content + + +
    +
  • Registered Menu Count: {{registeredMenuCount}}
  • + + +
+ diff --git a/packages/angular/test/base/src/app/standalone/menu-controller/menu-controller.component.ts b/packages/angular/test/base/src/app/standalone/menu-controller/menu-controller.component.ts new file mode 100644 index 0000000000..d99944f5ad --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/menu-controller/menu-controller.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; +import { MenuController, IonMenu } from '@ionic/angular/standalone'; + +@Component({ + selector: 'app-menu-controller', + templateUrl: './menu-controller.component.html', + standalone: true, + imports: [IonMenu] +}) +export class MenuControllerComponent { + registeredMenuCount = 0; + + constructor(private menuCtrl: MenuController) {} + + async setMenuCount() { + const menus = await this.menuCtrl.getMenus(); + this.registeredMenuCount = menus.length; + } +}