1
1
import {
2
+ afterNextRender ,
3
+ AfterRenderPhase ,
2
4
DestroyRef ,
3
5
Directive ,
6
+ effect ,
4
7
ElementRef ,
8
+ inject ,
5
9
Injector ,
6
10
Input ,
7
- afterNextRender ,
8
- effect ,
9
- inject ,
10
11
signal ,
11
12
untracked ,
12
13
type WritableSignal ,
13
14
} from '@angular/core' ;
15
+ import { applyProps } from 'angular-three' ;
14
16
import { gsap } from 'gsap' ;
15
- import { applyProps } from 'libs/core/src/lib/utils/apply-props' ;
16
17
17
18
export function injectGsap ( config : Record < string , { value : ( ) => any } & gsap . TweenVars > ) {
18
19
const destroyRef = inject ( DestroyRef ) ;
19
- const targets : Record < string , WritableSignal < any > > = { } ;
20
- const timelines : Record < string , gsap . core . Timeline > = { } ;
21
- let context : gsap . Context ;
22
20
23
21
const entries = Object . entries ( config ) ;
24
22
25
- afterNextRender ( ( ) => {
26
- context = gsap . context ( ( ) => {
27
- entries . forEach ( ( [ key ] ) => {
28
- timelines [ key ] = gsap . timeline ( ) ;
29
- targets [ key ] = signal < any | null > ( null ) ;
30
- } ) ;
23
+ const targets : Record < string , WritableSignal < any > > = entries . reduce (
24
+ ( acc , [ key ] ) => {
25
+ acc [ key ] = signal ( null ! ) ;
26
+ return acc ;
27
+ } ,
28
+ { } as Record < string , WritableSignal < any > > ,
29
+ ) ;
30
+ const timelines : Record < string , gsap . core . Timeline > = { } ;
31
+
32
+ const context = gsap . context ( ( ) => {
33
+ entries . forEach ( ( [ key ] ) => {
34
+ timelines [ key ] = gsap . timeline ( ) ;
31
35
} ) ;
32
36
} ) ;
33
37
34
- destroyRef . onDestroy ( ( ) => context ? .revert ( ) ) ;
38
+ destroyRef . onDestroy ( ( ) => context . revert ( ) ) ;
35
39
36
40
return entries . reduce ( ( acc , [ key , { value, ...rest } ] ) => {
37
- const preConfig = {
38
- [ key ] : untracked ( value ) ,
39
- } ;
40
-
41
- acc [ key ] = {
42
- start : ( target : any , injector : Injector ) => {
43
- untracked ( ( ) => {
44
- targets [ key ] . set ( target ) ;
45
- rest . onUpdate = ( ) => {
46
- if ( timelines [ key ] . isActive ( ) ) {
47
- applyProps ( target , preConfig ) ;
48
- }
49
- } ;
50
- } ) ;
51
- queueMicrotask ( ( ) => {
52
- effect (
53
- ( onCleanup ) => {
54
- if ( ! target ) return ;
55
-
56
- timelines [ key ] . to ( preConfig , { ...rest , [ key ] : value ( ) } ) ;
41
+ const targetValue = untracked ( value ) ;
42
+ acc [ key ] = ( target : any , injector : Injector ) => {
43
+ queueMicrotask ( ( ) => {
44
+ effect (
45
+ ( onCleanup ) => {
46
+ const _target = targets [ key ] ( ) ;
47
+ if ( ! _target ) return ;
48
+ timelines [ key ] . to ( targetValue , Object . assign ( rest , value ( ) ) ) ;
49
+ onCleanup ( ( ) => timelines [ key ] . clear ( ) ) ;
50
+ } ,
51
+ { injector } ,
52
+ ) ;
53
+ } ) ;
57
54
58
- onCleanup ( ( ) => timelines [ key ] . clear ( ) ) ;
59
- } ,
60
- { injector } ,
61
- ) ;
62
- } ) ;
63
- } ,
55
+ untracked ( ( ) => {
56
+ applyProps ( target , targetValue ) ;
57
+ targets [ key ] . set ( target ) ;
58
+ const originalOnUpdate = rest . onUpdate ;
59
+ rest . onUpdate = ( ) => {
60
+ originalOnUpdate ?.( ) ;
61
+ if ( timelines [ key ] . isActive ( ) ) {
62
+ applyProps ( target , targetValue ) ;
63
+ }
64
+ } ;
65
+ } ) ;
64
66
} ;
65
67
66
68
return acc ;
@@ -72,8 +74,11 @@ export class WithTimeline {
72
74
@Input ( { required : true } ) withTimeline ! : any ;
73
75
74
76
constructor ( elementRef : ElementRef < any > , injector : Injector ) {
75
- afterNextRender ( ( ) => {
76
- this . withTimeline . start ( elementRef . nativeElement , injector ) ;
77
- } ) ;
77
+ afterNextRender (
78
+ ( ) => {
79
+ this . withTimeline ( elementRef . nativeElement , injector ) ;
80
+ } ,
81
+ { phase : AfterRenderPhase . Read } ,
82
+ ) ;
78
83
}
79
84
}
0 commit comments