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,16 @@ 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
+ private evaluateConfigBasedFields ( ) : void {
99
171
const backdrop = this . config . backdrop ? this . backdrop . nativeElement : this . document . body ;
100
172
const dialogElement = this . dialogElement . nativeElement ;
101
173
@@ -133,6 +205,22 @@ export class DialogComponent implements OnInit, OnDestroy {
133
205
}
134
206
}
135
207
208
+ _onAnimationStart ( event ) : any {
209
+ if ( event . toState === 'enter' ) {
210
+ this . _animationStateChanged . next ( { state : 'opening' , totalTime : event . totalTime } ) ;
211
+ } else if ( event . toState === 'exit' || event . toState === 'void' ) {
212
+ this . _animationStateChanged . next ( { state : 'closing' , totalTime : event . totalTime } ) ;
213
+ }
214
+ }
215
+
216
+ _onAnimationDone ( event ) {
217
+ if ( event . toState === 'enter' ) {
218
+ // this._openAnimationDone(totalTime);
219
+ } else if ( event . toState === 'exit' ) {
220
+ this . _animationStateChanged . next ( { state : 'closed' , totalTime : event . totalTime } ) ;
221
+ }
222
+ }
223
+
136
224
reset ( offset ?: DragOffset ) : void {
137
225
if ( this . config . draggable ) {
138
226
this . draggable . reset ( offset ) ;
0 commit comments