diff --git a/core/src/utils/focus-visible.ts b/core/src/utils/focus-visible.ts index b5473c9e680..851e32f1ab2 100644 --- a/core/src/utils/focus-visible.ts +++ b/core/src/utils/focus-visible.ts @@ -1,19 +1,5 @@ const ION_FOCUSED = 'ion-focused'; const ION_FOCUSABLE = 'ion-focusable'; -const FOCUS_KEYS = [ - 'Tab', - 'ArrowDown', - 'Space', - 'Escape', - ' ', - 'Shift', - 'Enter', - 'ArrowLeft', - 'ArrowRight', - 'ArrowUp', - 'Home', - 'End', -]; export interface FocusVisibleUtility { destroy: () => void; @@ -22,7 +8,6 @@ export interface FocusVisibleUtility { export const startFocusVisible = (rootEl?: HTMLElement): FocusVisibleUtility => { let currentFocus: Element[] = []; - let keyboardMode = true; const ref = rootEl ? rootEl.shadowRoot! : document; const root = rootEl ? rootEl : document.body; @@ -32,43 +17,31 @@ export const startFocusVisible = (rootEl?: HTMLElement): FocusVisibleUtility => elements.forEach((el) => el.classList.add(ION_FOCUSED)); currentFocus = elements; }; + const pointerDown = () => { - keyboardMode = false; setFocus([]); }; - const onKeydown = (ev: Event) => { - keyboardMode = FOCUS_KEYS.includes((ev as KeyboardEvent).key); - if (!keyboardMode) { - setFocus([]); - } - }; const onFocusin = (ev: Event) => { - if (keyboardMode && ev.composedPath !== undefined) { - const toFocus = ev.composedPath().filter((el: any) => { - // TODO(FW-2832): type - if (el.classList) { - return el.classList.contains(ION_FOCUSABLE); - } - return false; - }) as Element[]; - setFocus(toFocus); - } + const toFocus = ev.composedPath().filter((el): el is HTMLElement => { + return el instanceof HTMLElement && el.classList.contains(ION_FOCUSABLE); + }); + + setFocus(toFocus); }; + const onFocusout = () => { if (ref.activeElement === root) { setFocus([]); } }; - ref.addEventListener('keydown', onKeydown); ref.addEventListener('focusin', onFocusin); ref.addEventListener('focusout', onFocusout); ref.addEventListener('touchstart', pointerDown, { passive: true }); ref.addEventListener('mousedown', pointerDown); const destroy = () => { - ref.removeEventListener('keydown', onKeydown); ref.removeEventListener('focusin', onFocusin); ref.removeEventListener('focusout', onFocusout); ref.removeEventListener('touchstart', pointerDown); diff --git a/packages/angular/test/apps/ng19/src/app/app.module.ts b/packages/angular/test/apps/ng19/src/app/app.module.ts deleted file mode 100644 index cdc0a89be04..00000000000 --- a/packages/angular/test/apps/ng19/src/app/app.module.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { APP_ID, NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { RouteReuseStrategy } from '@angular/router'; -import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; -import { AppComponent } from './app.component'; -import { AppRoutingModule } from './app-routing.module'; - -const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; - -export function ionicConfigFactory(): any { - const isLazy = isBrowser && window.location.href.includes('lazy'); - return isLazy ? { keyboardHeight: 12345 } : {}; -} - -@NgModule({ - declarations: [AppComponent], - imports: [ - BrowserModule, - AppRoutingModule, - IonicModule.forRoot(ionicConfigFactory()), - ], - providers: [ - { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, - { provide: APP_ID, useValue: 'serverApp' }, - ], - bootstrap: [AppComponent], -}) -export class AppModule {} diff --git a/packages/angular/test/base/e2e/src/lazy/tabs.spec.ts b/packages/angular/test/base/e2e/src/lazy/tabs.spec.ts index ac31d74060b..ef3b8a3f32b 100644 --- a/packages/angular/test/base/e2e/src/lazy/tabs.spec.ts +++ b/packages/angular/test/base/e2e/src/lazy/tabs.spec.ts @@ -3,122 +3,122 @@ describe('Tabs', () => { beforeEach(() => { cy.visit('/lazy/tabs'); }) - + describe('entry url - /tabs', () => { it('should redirect and load tab-account', () => { testTabTitle('Tab 1 - Page 1'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1']); testState(1, 'account'); }); - + it('should navigate between tabs and ionChange events should be dispatched', () => { let tab = testTabTitle('Tab 1 - Page 1'); tab.find('.segment-changed').should('have.text', 'false'); - + cy.get('#tab-button-contact').click(); tab = testTabTitle('Tab 2 - Page 1'); tab.find('.segment-changed').should('have.text', 'false'); }); - + describe('when navigating between tabs', () => { - + it('should emit ionTabsWillChange before setting the selected tab', () => { cy.get('#ionTabsWillChangeCounter').should('have.text', '1'); cy.get('#ionTabsWillChangeEvent').should('have.text', 'account'); cy.get('#ionTabsWillChangeSelectedTab').should('have.text', ''); - + cy.get('#ionTabsDidChangeCounter').should('have.text', '1'); cy.get('#ionTabsDidChangeEvent').should('have.text', 'account'); cy.get('#ionTabsDidChangeSelectedTab').should('have.text', 'account'); - + cy.get('#tab-button-contact').click(); - + cy.get('#ionTabsWillChangeCounter').should('have.text', '2'); cy.get('#ionTabsWillChangeEvent').should('have.text', 'contact'); cy.get('#ionTabsWillChangeSelectedTab').should('have.text', 'account'); - + cy.get('#ionTabsDidChangeCounter').should('have.text', '2'); cy.get('#ionTabsDidChangeEvent').should('have.text', 'contact'); cy.get('#ionTabsDidChangeSelectedTab').should('have.text', 'contact'); }) - + }); - + it('should simulate stack + double tab click', () => { let tab = getSelectedTab(); tab.find('#goto-tab1-page2').click(); testTabTitle('Tab 1 - Page 2 (1)'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested']); testState(1, 'account'); - + // When you call find on tab above it changes the value of tab // so we need to redefine it tab = getSelectedTab(); tab.find('ion-back-button').should('be.visible'); - + cy.get('#tab-button-contact').click(); testTabTitle('Tab 2 - Page 1'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']); testState(2, 'contact'); - + cy.get('#tab-button-account').click(); testTabTitle('Tab 1 - Page 2 (1)'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']); testState(3, 'account'); - + tab = getSelectedTab(); tab.find('ion-back-button').should('be.visible'); - + cy.get('#tab-button-account').click(); testTabTitle('Tab 1 - Page 1'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab2']); testState(3, 'account'); }); - + it('should simulate stack + back button click', () => { const tab = getSelectedTab(); tab.find('#goto-tab1-page2').click(); testTabTitle('Tab 1 - Page 2 (1)'); testState(1, 'account'); - + cy.get('#tab-button-contact').click(); testTabTitle('Tab 2 - Page 1'); testState(2, 'contact'); - + cy.get('#tab-button-account').click(); testTabTitle('Tab 1 - Page 2 (1)'); testState(3, 'account'); - + cy.get('ion-back-button').click(); testTabTitle('Tab 1 - Page 1'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab2']); testState(3, 'account'); }); - + it('should navigate deep then go home', () => { const tab = getSelectedTab(); tab.find('#goto-tab1-page2').click(); cy.ionPageVisible('app-tabs-tab1-nested'); cy.ionPageHidden('app-tabs-tab1'); - + testTabTitle('Tab 1 - Page 2 (1)'); - + cy.get('#goto-next').click(); cy.ionPageVisible('app-tabs-tab1-nested:last-of-type'); cy.ionPageHidden('app-tabs-tab1-nested:first-of-type'); - + testTabTitle('Tab 1 - Page 2 (2)'); - + cy.get('#tab-button-contact').click(); cy.ionPageVisible('app-tabs-tab2'); cy.ionPageHidden('app-tabs-tab1-nested:last-of-type'); - + testTabTitle('Tab 2 - Page 1'); - + cy.get('#tab-button-account').click(); cy.ionPageVisible('app-tabs-tab1-nested:last-of-type'); cy.ionPageHidden('app-tabs-tab2'); - + testTabTitle('Tab 1 - Page 2 (2)'); cy.testStack('ion-tabs ion-router-outlet', [ 'app-tabs-tab1', @@ -126,9 +126,9 @@ describe('Tabs', () => { 'app-tabs-tab1-nested', 'app-tabs-tab2' ]); - + cy.get('#tab-button-account').click(); - + /** * Wait for the leaving view to * be unmounted otherwise testTabTitle @@ -137,65 +137,65 @@ describe('Tabs', () => { */ cy.ionPageVisible('app-tabs-tab1'); cy.ionPageDoesNotExist('app-tabs-tab1-nested'); - + testTabTitle('Tab 1 - Page 1'); cy.testStack('ion-tabs ion-router-outlet', [ 'app-tabs-tab1', 'app-tabs-tab2' ]); }); - + it('should switch tabs and go back', () => { cy.get('#tab-button-contact').click(); const tab = testTabTitle('Tab 2 - Page 1'); - + tab.find('#goto-tab1-page1').click(); testTabTitle('Tab 1 - Page 1'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab2']); }); - + it('should switch tabs and go to nested', () => { cy.get('#tab-button-contact').click(); const tab = testTabTitle('Tab 2 - Page 1'); - + tab.find('#goto-tab1-page2').click(); testTabTitle('Tab 1 - Page 2 (1)'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab2', 'app-tabs-tab1-nested']); }); - + it('should load lazy loaded tab', () => { cy.get('#tab-button-lazy').click(); cy.ionPageVisible('app-tabs-tab3'); testTabTitle('Tab 3 - Page 1'); }); - + it('should use ion-back-button defaultHref', () => { let tab = getSelectedTab(); tab.find('#goto-tab3-page2').click(); testTabTitle('Tab 3 - Page 2'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab3-nested']); - + tab = getSelectedTab(); tab.find('ion-back-button').click(); testTabTitle('Tab 3 - Page 1'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab3']); }); - + it('should preserve navigation extras when switching tabs', () => { const expectUrlToContain = 'search=hello#fragment'; let tab = getSelectedTab(); tab.find('#goto-nested-page1-with-query-params').click(); testTabTitle('Tab 1 - Page 2 (1)'); testUrlContains(expectUrlToContain); - + cy.get('#tab-button-contact').click(); testTabTitle('Tab 2 - Page 1'); - + cy.get('#tab-button-account').click(); tab = testTabTitle('Tab 1 - Page 2 (1)'); testUrlContains(expectUrlToContain); }); - + it('should set root when clicking on an active tab to navigate to the root', () => { const expectNestedTabUrlToContain = 'search=hello#fragment'; cy.url().then(url => { @@ -203,74 +203,74 @@ describe('Tabs', () => { tab.find('#goto-nested-page1-with-query-params').click(); testTabTitle('Tab 1 - Page 2 (1)'); testUrlContains(expectNestedTabUrlToContain); - + cy.get('#tab-button-account').click(); testTabTitle('Tab 1 - Page 1'); - + testUrlEquals(url); }) }); }) - + describe('entry tab contains navigation extras', () => { const expectNestedTabUrlToContain = 'search=hello#fragment'; const rootUrlParams = 'test=123#rootFragment'; const rootUrl = `/lazy/tabs/account?${rootUrlParams}`; - + beforeEach(() => { cy.visit(rootUrl); }) - + it('should preserve root url navigation extras when clicking on an active tab to navigate to the root', () => { const tab = getSelectedTab(); tab.find('#goto-nested-page1-with-query-params').click(); - + testTabTitle('Tab 1 - Page 2 (1)'); testUrlContains(expectNestedTabUrlToContain); - + cy.get('#tab-button-account').click(); testTabTitle('Tab 1 - Page 1'); - + testUrlContains(rootUrl); }); - + it('should preserve root url navigation extras when changing tabs', () => { getSelectedTab(); cy.get('#tab-button-contact').click(); testTabTitle('Tab 2 - Page 1'); - + cy.get('#tab-button-account').click(); testTabTitle('Tab 1 - Page 1'); - + testUrlContains(rootUrl); }); - + it('should navigate deep then go home and preserve navigation extras', () => { let tab = getSelectedTab(); tab.find('#goto-tab1-page2').click(); cy.ionPageVisible('app-tabs-tab1-nested'); cy.ionPageHidden('app-tabs-tab1'); - + tab = testTabTitle('Tab 1 - Page 2 (1)'); - + tab.find('#goto-next').click(); cy.ionPageVisible('app-tabs-tab1-nested:last-of-type'); cy.ionPageHidden('app-tabs-tab1-nested:first-of-type'); - + testTabTitle('Tab 1 - Page 2 (2)'); - + cy.ionTabClick('Tab Two'); cy.ionPageVisible('app-tabs-tab2'); cy.ionPageHidden('app-tabs-tab1-nested:last-of-type'); - + testTabTitle('Tab 2 - Page 1'); - + cy.ionTabClick('Tab One'); cy.ionPageVisible('app-tabs-tab1-nested:last-of-type'); cy.ionPageHidden('app-tabs-tab2'); - + testTabTitle('Tab 1 - Page 2 (2)'); - + cy.ionTabClick('Tab One'); /** * Wait for the leaving view to @@ -280,37 +280,37 @@ describe('Tabs', () => { */ cy.ionPageVisible('app-tabs-tab1'); cy.ionPageDoesNotExist('app-tabs-tab1-nested'); - + testTabTitle('Tab 1 - Page 1'); - + testUrlContains(rootUrl); }); }) - + describe('entry url - /tabs/account', () => { beforeEach(() => { cy.visit('/lazy/tabs/account'); }); it('should pop to previous view when leaving tabs outlet', () => { - + cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1'); - + cy.get('#goto-tab1-page2').click(); - + cy.get('ion-title').should('contain.text', 'Tab 1 - Page 2 (1)'); - + cy.get('#goto-global').click(); - + cy.get('ion-title').should('contain.text', 'Global Page'); - + cy.get('#goto-prev-pop').click(); - + cy.get('ion-title').should('contain.text', 'Tab 1 - Page 2 (1)'); - + cy.get('#goto-prev').click(); - + cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1'); - + /** * Verifies that when entering the tabs outlet directly, * the navController.pop() method does not pop the previous view, @@ -320,117 +320,117 @@ describe('Tabs', () => { cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1'); }); }); - + describe('entry url - /', () => { it('should pop to the root outlet from the tabs outlet', () => { cy.visit('/lazy/'); - + cy.get('ion-title').should('contain.text', 'Test App'); - - cy.get('ion-item').contains('Tabs test').click(); - + + cy.get('ion-item').contains('Tabs Test').click(); + cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1'); - + cy.get('#goto-tab1-page2').click(); - + cy.get('ion-title').should('contain.text', 'Tab 1 - Page 2 (1)'); - + cy.get('#goto-global').click(); - + cy.get('ion-title').should('contain.text', 'Global Page'); - + cy.get('#goto-prev-pop').click(); - + cy.get('ion-title').should('contain.text', 'Tab 1 - Page 2 (1)'); - + cy.get('#goto-prev').click(); - + cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1'); - + cy.get('#goto-previous-page').click(); - + cy.get('ion-title').should('contain.text', 'Test App'); - + }); }); - - + + describe('entry url - /tabs/account/nested/1', () => { beforeEach(() => { cy.visit('/lazy/tabs/account/nested/1'); }) - + it('should only display the back-button when there is a page in the stack', () => { let tab = getSelectedTab(); tab.find('ion-back-button').should('not.be.visible'); testTabTitle('Tab 1 - Page 2 (1)'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']); - + cy.get('#tab-button-account').click(); tab = testTabTitle('Tab 1 - Page 1'); - + tab.find('#goto-tab1-page2').click(); tab = testTabTitle('Tab 1 - Page 2 (1)'); tab.find('ion-back-button').should('be.visible'); }); - + it('should not reuse the same page', () => { let tab = testTabTitle('Tab 1 - Page 2 (1)'); tab.find('#goto-next').click(); tab = testTabTitle('Tab 1 - Page 2 (2)'); - + tab.find('#goto-next').click(); tab = testTabTitle('Tab 1 - Page 2 (3)'); - + cy.testStack('ion-tabs ion-router-outlet', [ 'app-tabs-tab1-nested', 'app-tabs-tab1-nested', 'app-tabs-tab1-nested' ]); - + tab = getSelectedTab(); tab.find('ion-back-button').click(); tab = testTabTitle('Tab 1 - Page 2 (2)'); tab.find('ion-back-button').click(); tab = testTabTitle('Tab 1 - Page 2 (1)'); - + tab.find('ion-back-button').should('not.be.visible'); - + cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']); }); }) - + describe('entry url - /tabs/lazy', () => { beforeEach(() => { cy.visit('/lazy/tabs/lazy'); }); - + it('should not display the back-button if coming from a different stack', () => { let tab = testTabTitle('Tab 3 - Page 1'); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3']); - + tab = getSelectedTab(); tab.find('#goto-tab1-page2').click(); cy.testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3', 'app-tabs-tab1-nested']); - + tab = testTabTitle('Tab 1 - Page 2 (1)'); tab.find('ion-back-button').should('not.be.visible'); }); }) - + describe('enter url - /tabs/contact/one', () => { beforeEach(() => { cy.visit('/lazy/tabs/contact/one'); }); - + it('should return to correct tab after going to page in different outlet', () => { const tab = getSelectedTab(); tab.find('#goto-nested-page1').click(); cy.testStack('app-nested-outlet ion-router-outlet', ['app-nested-outlet-page']); - + const nestedOutlet = cy.get('app-nested-outlet'); nestedOutlet.find('ion-back-button').click(); - + testTabTitle('Tab 2 - Page 1'); }); }) diff --git a/packages/angular/test/base/src/app/app-landing/app-landing.component.html b/packages/angular/test/base/src/app/app-landing/app-landing.component.html new file mode 100644 index 00000000000..8689c0e29bc --- /dev/null +++ b/packages/angular/test/base/src/app/app-landing/app-landing.component.html @@ -0,0 +1,16 @@ + + + Test App - Angular {{ angularVersion.major }} + + + + + + + Go to Lazy App + + + Go to Standalone App + + + diff --git a/packages/angular/test/base/src/app/app-landing/app-landing.component.ts b/packages/angular/test/base/src/app/app-landing/app-landing.component.ts new file mode 100644 index 00000000000..62814291cdd --- /dev/null +++ b/packages/angular/test/base/src/app/app-landing/app-landing.component.ts @@ -0,0 +1,13 @@ +import { Component, VERSION } from '@angular/core'; + +@Component({ + selector: 'app-landing', + templateUrl: './app-landing.component.html', + standalone: false +}) +export class AppLandingComponent { + angularVersion = VERSION; + + constructor() {} + +} diff --git a/packages/angular/test/base/src/app/app.module.ts b/packages/angular/test/base/src/app/app.module.ts index 9d0a2a78eab..c419cd6d0d8 100644 --- a/packages/angular/test/base/src/app/app.module.ts +++ b/packages/angular/test/base/src/app/app.module.ts @@ -1,30 +1,29 @@ +import { APP_ID, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; import { RouteReuseStrategy } from '@angular/router'; - -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; +import { AppLandingComponent } from './app-landing/app-landing.component'; -const isLazy = window.location.href.includes('lazy'); - -const imports = [ - BrowserModule.withServerTransition({ appId: 'serverApp' }), - AppRoutingModule, -]; +const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; -if (isLazy) { - imports.push(IonicModule.forRoot({ keyboardHeight: 12345 })); +export function ionicConfigFactory(): any { + const isLazy = isBrowser && window.location.href.includes('lazy'); + return isLazy ? { keyboardHeight: 12345 } : {}; } @NgModule({ - declarations: [ - AppComponent, + declarations: [AppComponent, AppLandingComponent], + imports: [ + BrowserModule, + AppRoutingModule, + IonicModule.forRoot(ionicConfigFactory()), ], - imports, providers: [ { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, + { provide: APP_ID, useValue: 'serverApp' }, ], - bootstrap: [AppComponent] + bootstrap: [AppComponent], }) -export class AppModule { } +export class AppModule {} diff --git a/packages/angular/test/base/src/app/app.routes.ts b/packages/angular/test/base/src/app/app.routes.ts index 679d1812259..291e96540de 100644 --- a/packages/angular/test/base/src/app/app.routes.ts +++ b/packages/angular/test/base/src/app/app.routes.ts @@ -1,16 +1,18 @@ import { Routes } from '@angular/router'; +import { AppLandingComponent } from './app-landing/app-landing.component'; export const routes: Routes = [ { path: '', pathMatch: 'full', - /** - * Omit the slash at the beginning - * so query params are preserved. - * https://github.com/angular/angular/issues/13315#issuecomment-427254639 - */ - redirectTo: 'lazy' + component: AppLandingComponent }, - { path: 'lazy', loadChildren: () => import('./lazy/app-lazy/app.module').then(m => m.AppModule) }, - { path: 'standalone', loadChildren: () => import('./standalone/app-standalone/app.routes').then(m => m.routes) } + { + path: 'lazy', + loadChildren: () => import('./lazy/app-lazy/app.module').then(m => m.AppModule) + }, + { + path: 'standalone', + loadChildren: () => import('./standalone/app-standalone/app.routes').then(m => m.routes) + } ]; diff --git a/packages/angular/test/base/src/app/lazy/home-page/home-page.component.html b/packages/angular/test/base/src/app/lazy/home-page/home-page.component.html index 7fdca9c50d8..80418148c5e 100644 --- a/packages/angular/test/base/src/app/lazy/home-page/home-page.component.html +++ b/packages/angular/test/base/src/app/lazy/home-page/home-page.component.html @@ -1,7 +1,10 @@ + + + - Test App - Angular {{ angularVersion.major }} + Test App - Angular {{ angularVersion.major }} - Lazy @@ -9,37 +12,37 @@ - Alerts test + Alerts Test - Inputs test + Inputs Test - Form test + Form Test - Modals test + Modals Test - Router link test + Router link Test - Tabs test + Tabs Test - Basic Tabs test + Basic Tabs Test 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 40afc7a68de..c58432e0e9d 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: '', loadComponent: () => import('../home-page/home-page.component').then(c => c.HomePageComponent) }, { path: 'menu-controller', loadComponent: () => import('../menu-controller/menu-controller.component').then(c => c.MenuControllerComponent) }, { path: 'action-sheet-controller', loadComponent: () => import('../action-sheet-controller/action-sheet-controller.component').then(c => c.ActionSheetControllerComponent) }, { path: 'popover', loadComponent: () => import('../popover/popover.component').then(c => c.PopoverComponent) }, @@ -18,6 +19,14 @@ export const routes: Routes = [ { path: 'overlay-controllers', loadComponent: () => import('../overlay-controllers/overlay-controllers.component').then(c => c.OverlayControllersComponent) }, { path: 'button', loadComponent: () => import('../button/button.component').then(c => c.ButtonComponent) }, { path: 'icon', loadComponent: () => import('../icon/icon.component').then(c => c.IconComponent) }, + { path: 'split-pane', redirectTo: '/standalone/split-pane/inbox', pathMatch: 'full' }, + { + path: 'split-pane', + loadComponent: () => import('../split-pane/split-pane.component').then(c => c.SplitPaneComponent), + children: [ + { path: ':id', loadComponent: () => import('../split-pane/split-pane-page.component').then(c => c.SplitPanePageComponent) }, + ] + }, { path: 'tabs', redirectTo: '/standalone/tabs/tab-one', pathMatch: 'full' }, { path: 'tabs', diff --git a/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html b/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html new file mode 100644 index 00000000000..af57a62512c --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html @@ -0,0 +1,166 @@ + + + + + + + Test App - Angular {{ angularVersion.major }} - Standalone + + + + + + + Components + + + + Back Button Test + + + + + Button Test + + + + + Icon Test + + + + + + + Navigation + + + + Nav Test + + + + + Router Link Test + + + + + Router Outlet Test + + + + + Split Pane Test + + + + + Tabs Test + + + + + Tabs Basic Test + + + + + + + Overlays + + + + Action Sheet Controller Test + + + + + Menu Controller Test + + + + + Modal Test + + + + + Overlay Controllers Test + + + + + Popover Test + + + + + + + Value Accessors + + + + Checkbox Test + + + + + Datetime Test + + + + + Input Test + + + + + Radio Group Test + + + + + Range Test + + + + + Searchbar Test + + + + + Segment Test + + + + + Select Test + + + + + Textarea Test + + + + + Toggle Test + + + + + + + Miscellaneous + + + + Providers Test + + + + diff --git a/packages/angular/test/base/src/app/standalone/home-page/home-page.component.ts b/packages/angular/test/base/src/app/standalone/home-page/home-page.component.ts new file mode 100644 index 00000000000..dc2d78e6ab9 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/home-page/home-page.component.ts @@ -0,0 +1,15 @@ +import { Component, VERSION } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { IonBackButton, IonButtons, IonContent, IonLabel, IonList, IonListHeader, IonHeader, IonItem, IonRouterLink, IonTitle, IonToolbar } from '@ionic/angular/standalone'; + +@Component({ + selector: 'app-home-page', + templateUrl: './home-page.component.html', + standalone: true, + imports: [ IonBackButton, IonButtons, IonContent, IonLabel, IonList, IonHeader, IonListHeader, IonItem, IonRouterLink, IonTitle, IonToolbar, RouterModule ] +}) +export class HomePageComponent { + angularVersion = VERSION; + + constructor() {} +} diff --git a/packages/angular/test/base/src/app/standalone/split-pane/split-pane-page.component.html b/packages/angular/test/base/src/app/standalone/split-pane/split-pane-page.component.html new file mode 100644 index 00000000000..3d03206fee4 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/split-pane/split-pane-page.component.html @@ -0,0 +1,23 @@ + + + + + + {{ folder }} + + + + + + + {{ folder }} + + + +
+ Button One + Button Two + Button Three + Button Four +
+
diff --git a/packages/angular/test/base/src/app/standalone/split-pane/split-pane-page.component.ts b/packages/angular/test/base/src/app/standalone/split-pane/split-pane-page.component.ts new file mode 100644 index 00000000000..d913c6a3b64 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/split-pane/split-pane-page.component.ts @@ -0,0 +1,24 @@ +import { Component, inject, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonTitle, IonToolbar } from '@ionic/angular/standalone'; + +@Component({ + selector: 'app-split-pane-page', + templateUrl: './split-pane-page.component.html', + imports: [ IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonTitle, IonToolbar ], + standalone: true, +}) +export class SplitPanePageComponent implements OnInit { + public folder!: string; + private activatedRoute = inject(ActivatedRoute); + + constructor() {} + + ngOnInit() { + this.folder = this.activatedRoute.snapshot.paramMap.get('id') as string; + } + + onClick(val: string) { + console.log(val); + } +} diff --git a/packages/angular/test/base/src/app/standalone/split-pane/split-pane.component.css b/packages/angular/test/base/src/app/standalone/split-pane/split-pane.component.css new file mode 100644 index 00000000000..f91c443385e --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/split-pane/split-pane.component.css @@ -0,0 +1,3 @@ +ion-item.selected { + --background: rgb(var(--ion-color-primary-rgb, 0, 84, 233), 0.14); +} diff --git a/packages/angular/test/base/src/app/standalone/split-pane/split-pane.component.html b/packages/angular/test/base/src/app/standalone/split-pane/split-pane.component.html new file mode 100644 index 00000000000..89a192dc6e3 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/split-pane/split-pane.component.html @@ -0,0 +1,22 @@ + + + + + Inbox + + + + {{ p.title }} + + + + + + + diff --git a/packages/angular/test/base/src/app/standalone/split-pane/split-pane.component.ts b/packages/angular/test/base/src/app/standalone/split-pane/split-pane.component.ts new file mode 100644 index 00000000000..747e28d75f5 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/split-pane/split-pane.component.ts @@ -0,0 +1,49 @@ +import { CommonModule } from '@angular/common'; +import { Component } from '@angular/core'; +import { RouterLink, RouterLinkActive } from '@angular/router'; +import { + IonContent, + IonItem, + IonLabel, + IonList, + IonListHeader, + IonMenu, + IonMenuToggle, + IonRouterLink, + IonRouterOutlet, + IonSplitPane +} from '@ionic/angular/standalone'; + +@Component({ + selector: 'app-split-pane', + templateUrl: 'split-pane.component.html', + styleUrls: ['split-pane.component.css'], + standalone: true, + imports: [ + CommonModule, + IonContent, + IonItem, + IonLabel, + IonList, + IonListHeader, + IonMenu, + IonMenuToggle, + IonRouterLink, + IonRouterOutlet, + IonSplitPane, + RouterLink, + RouterLinkActive, + ], +}) +export class SplitPaneComponent { + public appPages = [ + { title: 'Inbox', url: '/standalone/split-pane/inbox' }, + { title: 'Outbox', url: '/standalone/split-pane/outbox' }, + { title: 'Favorites', url: '/standalone/split-pane/favorites' }, + { title: 'Archived', url: '/standalone/split-pane/archived' }, + { title: 'Trash', url: '/standalone/split-pane/trash' }, + { title: 'Spam', url: '/standalone/split-pane/spam'} + ]; + + constructor() { } +}