1
1
import { ComponentFactoryResolver , ComponentRef , Injectable , Injector , Type , ViewContainerRef } from '@angular/core' ;
2
+ import type { BottomSheetOptions as MaterialBottomSheetOptions } from '@nativescript-community/ui-material-bottomsheet' ;
2
3
import { AppHostView , DetachedLoader , once } from '@nativescript/angular' ;
3
- import { ProxyViewContainer } from '@nativescript/core' ;
4
+ import { LayoutBase , ProxyViewContainer , View } from '@nativescript/core' ;
4
5
import { Observable , Subject } from 'rxjs' ;
5
6
import { filter , first , map } from 'rxjs/operators' ;
6
- import { BottomSheetOptions as MaterialBottomSheetOptions } from '@nativescript-community/ui-material-bottomsheet' ; // ViewWithBottomSheetBase
7
7
8
- export type BaseShowBottomSheetOptions = Pick < MaterialBottomSheetOptions , Exclude < keyof MaterialBottomSheetOptions , 'closeCallback' | 'view' > > ;
8
+ export type BaseShowBottomSheetOptions = Omit < MaterialBottomSheetOptions , 'closeCallback' | 'view' > ;
9
9
10
10
export interface BottomSheetOptions extends BaseShowBottomSheetOptions {
11
11
viewContainerRef ?: ViewContainerRef ;
12
12
}
13
13
14
14
export class BottomSheetParams {
15
- context : any ;
16
- closeCallback : ( ...args ) => void ;
17
-
18
- constructor ( context , closeCallback ) {
19
- this . context = context ;
20
- this . closeCallback = closeCallback ;
21
- }
15
+ public constructor ( public readonly context : any , public readonly closeCallback : ( ...args ) => void ) { }
22
16
}
23
17
18
+ type ViewWithDialogRoot = View & { _ngDialogRoot ?: View } ;
19
+
24
20
@Injectable ( {
25
21
providedIn : 'root'
26
22
} )
27
23
export class BottomSheetService {
24
+ private readonly results$ = new Subject < { sheetId : number ; result : any } > ( ) ;
25
+
28
26
private detachedLoader : ComponentRef < DetachedLoader > ;
29
- private componentView : any ; //ViewWithBottomSheetBase;
30
- private subject$ : Subject < { requestId : number ; result : any } > = new Subject ( ) ;
31
- private currentId = 0 ;
32
27
33
- show < T = any > ( type : Type < any > , options : BottomSheetOptions ) : Observable < T > {
28
+ private componentView : View ;
29
+
30
+ private nextSheetId = 0 ;
31
+
32
+ public show < T = any > ( type : Type < any > , options : BottomSheetOptions ) : Observable < T > {
34
33
return this . showWithCloseCallback ( type , options ) . observable ;
35
34
}
36
35
37
- showWithCloseCallback < T = any > ( type : Type < any > , options : BottomSheetOptions ) : { observable : Observable < T > ; closeCallback : ( ) => void } {
36
+ public showWithCloseCallback < T = any > ( type : Type < any > , options : BottomSheetOptions ) : { observable : Observable < T > ; closeCallback : ( ) => void } {
38
37
if ( ! options . viewContainerRef ) {
39
38
throw new Error ( 'No viewContainerRef: Make sure you pass viewContainerRef in BottomSheetOptions.' ) ;
40
39
}
41
- this . currentId ++ ;
42
- const requestId = this . currentId ;
40
+
41
+ const sheetId = this . nextSheetId ++ ;
43
42
const parentView = this . getParentView ( options . viewContainerRef ) ;
44
43
const factoryResolver = this . getFactoryResolver ( options . viewContainerRef ) ;
45
- const bottomSheetParams = this . getBottomSheetParams ( options . context , requestId ) ;
44
+ const bottomSheetParams = this . getBottomSheetParams ( options . context , sheetId ) ;
46
45
47
46
this . detachedLoader = this . createDetachedLoader ( factoryResolver , bottomSheetParams , options . viewContainerRef ) ;
48
47
49
- this . loadComponent ( type ) . then ( componentView => {
48
+ this . loadComponent ( type ) . then ( ( componentView ) => {
50
49
parentView . showBottomSheet ( {
51
50
...options ,
52
51
...bottomSheetParams ,
@@ -55,17 +54,17 @@ export class BottomSheetService {
55
54
} ) ;
56
55
57
56
return {
58
- observable : this . subject $. pipe (
59
- filter ( item => item && item . requestId === requestId ) ,
60
- map ( item => item . result ) ,
57
+ observable : this . results $. pipe (
58
+ filter ( ( item ) => item && item . sheetId === sheetId ) ,
59
+ map ( ( item ) => item . result ) ,
61
60
first ( )
62
61
) ,
63
62
closeCallback : bottomSheetParams . closeCallback
64
63
} ;
65
64
}
66
65
67
- private getParentView ( viewContainerRef : ViewContainerRef ) : any { //ViewWithBottomSheetBase {
68
- let parentView = viewContainerRef . element . nativeElement ;
66
+ private getParentView ( viewContainerRef : ViewContainerRef ) : View {
67
+ let parentView = viewContainerRef . element . nativeElement as View ;
69
68
70
69
if ( parentView instanceof AppHostView && parentView . ngAppRoot ) {
71
70
parentView = parentView . ngAppRoot ;
@@ -74,8 +73,8 @@ export class BottomSheetService {
74
73
// _ngDialogRoot is the first child of the previously detached proxy.
75
74
// It should have 'viewController' (iOS) or '_dialogFragment' (Android) available for
76
75
// presenting future bottomSheets views.
77
- if ( parentView . _ngDialogRoot ) {
78
- parentView = parentView . _ngDialogRoot ;
76
+ if ( ( parentView as ViewWithDialogRoot ) . _ngDialogRoot ) {
77
+ parentView = ( parentView as ViewWithDialogRoot ) . _ngDialogRoot ;
79
78
}
80
79
81
80
return parentView ;
@@ -87,7 +86,7 @@ export class BottomSheetService {
87
86
return componentContainer . injector . get ( ComponentFactoryResolver ) ;
88
87
}
89
88
90
- private createChildInjector ( bottomSheetParams : BottomSheetParams , containerRef : ViewContainerRef ) {
89
+ private createChildInjector ( bottomSheetParams : BottomSheetParams , containerRef : ViewContainerRef ) : Injector {
91
90
return Injector . create ( {
92
91
providers : [
93
92
{
@@ -99,15 +98,16 @@ export class BottomSheetService {
99
98
} ) ;
100
99
}
101
100
102
- private getBottomSheetParams ( context : any , requestId : number ) {
103
- const closeCallback = once ( args => {
104
- this . subject $. next ( { result : args , requestId } ) ;
101
+ private getBottomSheetParams ( context : any , sheetId : number ) : BottomSheetParams {
102
+ const closeCallback = once ( ( args ) => {
103
+ this . results $. next ( { result : args , sheetId } ) ;
105
104
106
105
if ( ! this . componentView ) {
107
106
return ;
108
107
}
109
108
110
109
this . componentView . closeBottomSheet ( ) ;
110
+
111
111
this . detachedLoader . instance . detectChanges ( ) ;
112
112
this . detachedLoader . destroy ( ) ;
113
113
} ) ;
@@ -122,7 +122,7 @@ export class BottomSheetService {
122
122
return viewContainerRef . createComponent ( detachedLoaderFactory , 0 , childInjector , null ) ;
123
123
}
124
124
125
- private async loadComponent ( type : Type < any > ) : Promise < any > { //ViewWithBottomSheetBase > {
125
+ private async loadComponent ( type : Type < any > ) : Promise < View > {
126
126
try {
127
127
const componentRef = await this . detachedLoader . instance . loadComponent ( type ) ;
128
128
const detachedProxy = componentRef . location . nativeElement as ProxyViewContainer ;
@@ -131,16 +131,17 @@ export class BottomSheetService {
131
131
throw new Error ( 'BottomSheet content has more than one root view.' ) ;
132
132
}
133
133
134
- this . componentView = detachedProxy . getChildAt ( 0 ) as any ; //ViewWithBottomSheetBase ;
134
+ this . componentView = detachedProxy . getChildAt ( 0 ) ;
135
135
136
- if ( this . componentView . parent ) {
137
- ( this . componentView . parent ) . _ngDialogRoot = this . componentView ;
138
- ( this . componentView . parent ) . removeChild ( this . componentView ) ;
136
+ if ( this . componentView . parent instanceof LayoutBase ) {
137
+ ( this . componentView . parent as ViewWithDialogRoot ) . _ngDialogRoot = this . componentView ;
138
+ this . componentView . parent . removeChild ( this . componentView ) ;
139
139
}
140
140
141
141
return this . componentView ;
142
- } catch ( e ) {
143
- console . error ( e ) ;
142
+ } catch ( err ) {
143
+ console . error ( err ) ;
144
+
144
145
return null ;
145
146
}
146
147
}
0 commit comments