1
1
import { CommonModule , DOCUMENT } from '@angular/common' ;
2
- import { Component , ElementRef , inject , Inject , OnDestroy , OnInit , ViewChild , ViewEncapsulation } from '@angular/core' ;
2
+ import {
3
+ Component ,
4
+ ElementRef ,
5
+ EventEmitter ,
6
+ inject ,
7
+ OnDestroy ,
8
+ OnInit ,
9
+ ViewChild ,
10
+ ViewEncapsulation ,
11
+ } from '@angular/core' ;
3
12
import { fromEvent , merge , Subject } from 'rxjs' ;
4
13
import { filter , takeUntil } from 'rxjs/operators' ;
5
14
import { InternalDialogRef } from './dialog-ref' ;
6
15
import { DialogService } from './dialog.service' ;
7
16
import { coerceCssPixelValue } from './dialog.utils' ;
8
17
import { DialogDraggableDirective , DragOffset } from './draggable.directive' ;
9
18
import { DIALOG_CONFIG , NODES_TO_INSERT } from './providers' ;
19
+ import { DialogConfig } from '@ngneat/dialog' ;
20
+ import { animate , animateChild , group , keyframes , query , state , style , transition , trigger } from '@angular/animations' ;
21
+
22
+ export const _defaultParams = {
23
+ params : { enterAnimationDuration : '150ms' , exitAnimationDuration : '75ms' } ,
24
+ } ;
10
25
11
26
@Component ( {
12
27
selector : 'ngneat-dialog' ,
13
28
standalone : true ,
14
29
imports : [ DialogDraggableDirective , CommonModule ] ,
30
+ animations : [
31
+ trigger ( 'dialogContent' , [
32
+ // Note: The `enter` animation transitions to `transform: none`, because for some reason
33
+ // specifying the transform explicitly, causes IE both to blur the dialog content and
34
+ // decimate the animation performance. Leaving it as `none` solves both issues.
35
+ state ( 'void, exit' , style ( { opacity : 0 , transform : 'scale(0.7)' } ) ) ,
36
+ state ( 'enter' , style ( { transform : 'none' } ) ) ,
37
+ transition (
38
+ '* => enter' ,
39
+ group ( [
40
+ animate (
41
+ '0.4s cubic-bezier(0.25, 0.8, 0.25, 1)' ,
42
+ keyframes ( [ style ( { opacity : 0 , transform : 'translateX(50px)' } ) , style ( { opacity : 1 , transform : 'none' } ) ] )
43
+ ) ,
44
+ query ( '@*' , animateChild ( ) , { optional : true } ) ,
45
+ ] ) ,
46
+ _defaultParams
47
+ ) ,
48
+ transition (
49
+ '* => void, * => exit' ,
50
+ group ( [
51
+ animate ( '0.4s cubic-bezier(0.4, 0.0, 0.2, 1)' , style ( { opacity : 0 } ) ) ,
52
+ query ( '@*' , animateChild ( ) , { optional : true } ) ,
53
+ ] ) ,
54
+ _defaultParams
55
+ ) ,
56
+ ] ) ,
57
+ trigger ( 'dialogContainer' , [
58
+ transition (
59
+ '* => void, * => exit' ,
60
+ group ( [
61
+ animate ( '0.4s cubic-bezier(0.4, 0.0, 0.2, 1)' , style ( { opacity : 0 } ) ) ,
62
+ query ( '@*' , animateChild ( ) , { optional : true } ) ,
63
+ ] ) ,
64
+ _defaultParams
65
+ ) ,
66
+ ] ) ,
67
+ ] ,
68
+ host : {
69
+ '[@dialogContainer]' : `this.dialogRef._getAnimationState()` ,
70
+ '(@dialogContainer.start)' : '_onAnimationStart($event)' ,
71
+ '(@dialogContainer.done)' : '_onAnimationDone($event)' ,
72
+ } ,
15
73
template : `
16
74
<div
17
75
#backdrop
@@ -21,6 +79,9 @@ import { DIALOG_CONFIG, NODES_TO_INSERT } from './providers';
21
79
>
22
80
<div
23
81
#dialog
82
+ [@dialogContent]="this.dialogRef._getAnimationState()"
83
+ (@dialogContent.start)="_onAnimationStart($event)"
84
+ (@dialogContent.done)="_onAnimationDone($event)"
24
85
class="ngneat-dialog-content"
25
86
[class.ngneat-dialog-resizable]="config.resizable"
26
87
[ngStyle]="styles"
@@ -49,6 +110,7 @@ import { DIALOG_CONFIG, NODES_TO_INSERT } from './providers';
49
110
encapsulation : ViewEncapsulation . None ,
50
111
} )
51
112
export class DialogComponent implements OnInit , OnDestroy {
113
+ _animationStateChanged = new EventEmitter < { state : string ; totalTime : number } > ( ) ;
52
114
config = inject ( DIALOG_CONFIG ) ;
53
115
dialogRef = inject ( InternalDialogRef ) ;
54
116
@@ -96,6 +158,34 @@ export class DialogComponent implements OnInit, OnDestroy {
96
158
}
97
159
98
160
ngOnInit ( ) {
161
+ const dialogElement = this . dialogElement . nativeElement ;
162
+ this . evaluateConfigBasedFields ( ) ;
163
+
164
+ // `dialogElement` is resolved at this point
165
+ // And here is where dialog finally will be placed
166
+ this . nodes . forEach ( ( node ) => dialogElement . appendChild ( node ) ) ;
167
+ this . dialogRef . _state = 'enter' ;
168
+ }
169
+
170
+ reset ( offset ?: DragOffset ) : void {
171
+ if ( this . config . draggable ) {
172
+ this . draggable . reset ( offset ) ;
173
+ }
174
+ }
175
+
176
+ closeDialog ( ) {
177
+ this . dialogRef . close ( ) ;
178
+ }
179
+
180
+ ngOnDestroy ( ) {
181
+ this . destroy$ . next ( ) ;
182
+ this . destroy$ . complete ( ) ;
183
+
184
+ this . dialogRef = null ;
185
+ this . nodes = null ;
186
+ }
187
+
188
+ private evaluateConfigBasedFields ( ) : void {
99
189
const backdrop = this . config . backdrop ? this . backdrop . nativeElement : this . document . body ;
100
190
const dialogElement = this . dialogElement . nativeElement ;
101
191
@@ -133,21 +223,19 @@ export class DialogComponent implements OnInit, OnDestroy {
133
223
}
134
224
}
135
225
136
- reset ( offset ?: DragOffset ) : void {
137
- if ( this . config . draggable ) {
138
- this . draggable . reset ( offset ) ;
226
+ _onAnimationStart ( event ) : any {
227
+ if ( event . toState === 'enter' ) {
228
+ this . _animationStateChanged . next ( { state : 'opening' , totalTime : event . totalTime } ) ;
229
+ } else if ( event . toState === 'exit' || event . toState === 'void' ) {
230
+ this . _animationStateChanged . next ( { state : 'closing' , totalTime : event . totalTime } ) ;
139
231
}
140
232
}
141
233
142
- closeDialog ( ) {
143
- this . dialogRef . close ( ) ;
144
- }
145
-
146
- ngOnDestroy ( ) {
147
- this . destroy$ . next ( ) ;
148
- this . destroy$ . complete ( ) ;
149
-
150
- this . dialogRef = null ;
151
- this . nodes = null ;
234
+ _onAnimationDone ( event ) {
235
+ if ( event . toState === 'enter' ) {
236
+ // this._openAnimationDone(totalTime);
237
+ } else if ( event . toState === 'exit' ) {
238
+ this . _animationStateChanged . next ( { state : 'closed' , totalTime : event . totalTime } ) ;
239
+ }
152
240
}
153
241
}
0 commit comments