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