diff --git a/apps/nativescript-demo-ng/src/app/app.routes.ts b/apps/nativescript-demo-ng/src/app/app.routes.ts index 2ed3853..3099fef 100644 --- a/apps/nativescript-demo-ng/src/app/app.routes.ts +++ b/apps/nativescript-demo-ng/src/app/app.routes.ts @@ -2,6 +2,7 @@ import { Routes } from '@angular/router'; import { ItemDetailComponent } from './item/item-detail.component'; import { ItemsComponent } from './item/items.component'; import { ListViewStickyComponent } from './list-view-sticky/list-view-sticky.component'; +import { SPLIT_VIEW_ROUTES } from './split-view-demo/split-view.routes'; // import { HomeComponent } from './home/home.component'; // import { BootGuardService } from './boot-guard.service'; @@ -15,6 +16,10 @@ export const routes: Routes = [ path: 'list-view-sticky', component: ListViewStickyComponent, }, + { + path: 'split-view-demo', + children: SPLIT_VIEW_ROUTES, + }, /** * Test tab named outlets diff --git a/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-demo.component.html b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-demo.component.html new file mode 100644 index 0000000..ad72418 --- /dev/null +++ b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-demo.component.html @@ -0,0 +1,13 @@ + + + + + + diff --git a/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-demo.component.ts b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-demo.component.ts new file mode 100644 index 0000000..6a0a561 --- /dev/null +++ b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-demo.component.ts @@ -0,0 +1,52 @@ +import { Component, inject, NO_ERRORS_SCHEMA, OnInit, AfterViewInit } from '@angular/core'; +import { + NativeScriptCommonModule, + NativeScriptRouterModule, + PageRouterOutlet, + RouterExtensions, +} from '@nativescript/angular'; +import { SplitViewState } from './split-view.state'; + +@Component({ + selector: 'ns-split-view-demo', + templateUrl: './split-view-demo.component.html', + imports: [NativeScriptCommonModule, NativeScriptRouterModule, PageRouterOutlet], + schemas: [NO_ERRORS_SCHEMA], +}) +export class SplitViewDemoComponent implements OnInit, AfterViewInit { + router = inject(RouterExtensions); + splitViewState = inject(SplitViewState); + + ngOnInit() { + console.log('[SplitViewDemo] ngOnInit'); + } + + ngAfterViewInit() { + console.log('[SplitViewDemo] ngAfterViewInit - view is initialized, navigating to outlets'); + // Use setTimeout to ensure the view is fully rendered and outlets are registered + setTimeout(() => { + console.log('[SplitViewDemo] Navigating to outlets...'); + this.router + .navigate( + [ + '/', + { + outlets: { + primary: ['primary'], + secondary: ['secondary'], + supplementary: ['supplementary'], + inspector: ['inspector'], + }, + }, + ], + { animated: false }, + ) + .then((success) => { + console.log(`[SplitViewDemo] navigation result: ${success}`); + }) + .catch((err) => { + console.error(`[SplitViewDemo] navigation error: ${err}`); + }); + }, 0); + } +} diff --git a/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-inspector.component.ts b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-inspector.component.ts new file mode 100644 index 0000000..0e055d4 --- /dev/null +++ b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-inspector.component.ts @@ -0,0 +1,44 @@ +import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NativeScriptCommonModule } from '@nativescript/angular'; + +@Component({ + selector: 'ns-split-view-inspector', + template: ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + `, + imports: [NativeScriptCommonModule], + schemas: [NO_ERRORS_SCHEMA], +}) +export class SplitViewInspectorComponent {} diff --git a/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-primary.component.ts b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-primary.component.ts new file mode 100644 index 0000000..a663614 --- /dev/null +++ b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-primary.component.ts @@ -0,0 +1,57 @@ +import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NativeScriptCommonModule } from '@nativescript/angular'; + +@Component({ + selector: 'ns-split-view-primary', + template: ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `, + imports: [NativeScriptCommonModule], + schemas: [NO_ERRORS_SCHEMA], +}) +export class SplitViewPrimaryComponent {} diff --git a/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-secondary.component.ts b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-secondary.component.ts new file mode 100644 index 0000000..047cd5a --- /dev/null +++ b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-secondary.component.ts @@ -0,0 +1,98 @@ +import { Component, inject, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NativeScriptCommonModule } from '@nativescript/angular'; +import { SplitViewState } from './split-view.state'; + +@Component({ + selector: 'ns-split-view-secondary', + template: ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @if (!splitViewState.inspectorVisible()) { + + + + + } + + + + `, + imports: [NativeScriptCommonModule], + schemas: [NO_ERRORS_SCHEMA], +}) +export class SplitViewSecondaryComponent { + splitViewState = inject(SplitViewState); +} diff --git a/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-supplementary.component.ts b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-supplementary.component.ts new file mode 100644 index 0000000..ec085dc --- /dev/null +++ b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view-supplementary.component.ts @@ -0,0 +1,64 @@ +import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NativeScriptCommonModule } from '@nativescript/angular'; + +@Component({ + selector: 'ns-split-view-supplementary', + template: ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `, + imports: [NativeScriptCommonModule], + schemas: [NO_ERRORS_SCHEMA], +}) +export class SplitViewSupplementaryComponent {} diff --git a/apps/nativescript-demo-ng/src/app/split-view-demo/split-view.routes.ts b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view.routes.ts new file mode 100644 index 0000000..db72531 --- /dev/null +++ b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view.routes.ts @@ -0,0 +1,31 @@ +import { Routes } from '@angular/router'; +import { SplitViewPrimaryComponent } from './split-view-primary.component'; +import { SplitViewSecondaryComponent } from './split-view-secondary.component'; +import { SplitViewSupplementaryComponent } from './split-view-supplementary.component'; +import { SplitViewInspectorComponent } from './split-view-inspector.component'; + +// Since SplitViewDemoComponent is bootstrapped directly, we don't include it in routes. +// The named outlets are defined in SplitViewDemoComponent's template, +// and these child routes activate into those outlets. +export const SPLIT_VIEW_ROUTES: Routes = [ + { + path: 'primary', + component: SplitViewPrimaryComponent, + outlet: 'primary', + }, + { + path: 'secondary', + component: SplitViewSecondaryComponent, + outlet: 'secondary', + }, + { + path: 'supplementary', + component: SplitViewSupplementaryComponent, + outlet: 'supplementary', + }, + { + path: 'inspector', + component: SplitViewInspectorComponent, + outlet: 'inspector', + }, +]; diff --git a/apps/nativescript-demo-ng/src/app/split-view-demo/split-view.state.ts b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view.state.ts new file mode 100644 index 0000000..3b9cfa8 --- /dev/null +++ b/apps/nativescript-demo-ng/src/app/split-view-demo/split-view.state.ts @@ -0,0 +1,21 @@ +import { Injectable, signal } from '@angular/core'; +import { SplitView } from '@nativescript/core'; + +@Injectable({ + providedIn: 'root', +}) +export class SplitViewState { + inspectorVisible = signal(true); + + onInspectorChange(event: any) { + console.log(`[SplitViewState] Inspector visibility changed: ${event.data.showing}`); + if (!event.data.showing) { + this.inspectorVisible.set(event.data.showing); + } + } + + setInspectorVisible(visible: boolean) { + this.inspectorVisible.set(visible); + SplitView.getInstance().showInspector(); + } +} diff --git a/apps/nativescript-demo-ng/src/main.ts b/apps/nativescript-demo-ng/src/main.ts index e725d50..8083544 100644 --- a/apps/nativescript-demo-ng/src/main.ts +++ b/apps/nativescript-demo-ng/src/main.ts @@ -5,28 +5,33 @@ import { provideNativeScriptRouter, runNativeScriptAngularApp, } from '@nativescript/angular'; -import { Trace, Utils } from '@nativescript/core'; +import { Trace, Utils, SplitView } from '@nativescript/core'; // import { AppModule } from './app/app.module'; import { withInterceptorsFromDi } from '@angular/common/http'; -import { AppComponent } from './app/app.component'; -import { routes } from './app/app.routes'; +// import { AppComponent } from './app/app.component'; +// import { routes } from './app/app.routes'; import { provideZonelessChangeDetection } from '@angular/core'; +import { SPLIT_VIEW_ROUTES } from './app/split-view-demo/split-view.routes'; +import { SplitViewDemoComponent } from './app/split-view-demo/split-view-demo.component'; const ZONELESS = true; Trace.enable(); Trace.setCategories('ns-route-reuse-strategy,ns-router'); +// Set the split style before bootstrapping - 'triple' is needed for primary/supplementary/secondary layout +SplitView.SplitStyle = 'triple'; + runNativeScriptAngularApp({ appModuleBootstrap: () => { if (__APPLE__) { Utils.ios.setWindowBackgroundColor('#a6120d'); } - return bootstrapApplication(AppComponent, { + return bootstrapApplication(SplitViewDemoComponent, { providers: [ provideNativeScriptHttpClient(withInterceptorsFromDi()), - provideNativeScriptRouter(routes), + provideNativeScriptRouter(SPLIT_VIEW_ROUTES), ZONELESS ? provideZonelessChangeDetection() : provideNativeScriptNgZone(), ], }); diff --git a/packages/angular/src/lib/element-registry/common-views.ts b/packages/angular/src/lib/element-registry/common-views.ts index 3d8283c..f4436ec 100644 --- a/packages/angular/src/lib/element-registry/common-views.ts +++ b/packages/angular/src/lib/element-registry/common-views.ts @@ -1,4 +1,4 @@ -import { AbsoluteLayout, ActivityIndicator, Button, ContentView, DatePicker, DockLayout, FlexboxLayout, FormattedString, Frame, GridLayout, HtmlView, Image, Label, ListPicker, ListView, Page, Placeholder, Progress, ProxyViewContainer, Repeater, RootLayout, ScrollView, SearchBar, SegmentedBar, SegmentedBarItem, Slider, Span, StackLayout, Switch, TabView, TextField, TextView, TimePicker, WebView, WrapLayout } from '@nativescript/core'; +import { AbsoluteLayout, ActivityIndicator, Button, ContentView, DatePicker, DockLayout, FlexboxLayout, FormattedString, Frame, GridLayout, HtmlView, Image, Label, ListPicker, ListView, Page, Placeholder, Progress, ProxyViewContainer, Repeater, RootLayout, ScrollView, SearchBar, SegmentedBar, SegmentedBarItem, Slider, Span, SplitView, StackLayout, Switch, TabView, TextField, TextView, TimePicker, WebView, WrapLayout } from '@nativescript/core'; import { formattedStringMeta, frameMeta, textBaseMeta } from './metas'; import { registerElement } from './registry'; @@ -33,6 +33,7 @@ export function registerNativeScriptViewComponents() { registerElement('SegmentedBar', () => SegmentedBar); registerElement('SegmentedBarItem', () => SegmentedBarItem); registerElement('Slider', () => Slider); + registerElement('SplitView', () => SplitView); registerElement('StackLayout', () => StackLayout); registerElement('FlexboxLayout', () => FlexboxLayout); registerElement('Switch', () => Switch);