Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit277e2bf

Browse files
feat(core): add enter and leave animation instructions
This adds the instructions to support enter and leave animations on nodes.
1 parentfc8247d commit277e2bf

File tree

22 files changed

+1362
-21
lines changed

22 files changed

+1362
-21
lines changed

‎goldens/public-api/core/index.api.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,18 @@ export interface AfterViewInit {
8181
// @public
8282
exportconst ANIMATION_MODULE_TYPE:InjectionToken<"NoopAnimations"|"BrowserAnimations">;
8383

84+
// @public
85+
exporttypeAnimationCallbackEvent= {
86+
target:Element;
87+
animationComplete:Function;
88+
};
89+
90+
// @public
91+
exporttypeAnimationFunction= (event:AnimationCallbackEvent)=>void;
92+
93+
// @public
94+
exportconst ANIMATIONS_DISABLED:InjectionToken<boolean>;
95+
8496
// @public
8597
exportconst APP_BOOTSTRAP_LISTENER:InjectionToken<readonly ((compRef:ComponentRef<any>)=>void)[]>;
8698

@@ -667,6 +679,23 @@ export class ElementRef<T = any> {
667679
nativeElement:T;
668680
}
669681

682+
// @public
683+
exportclassElementRegistry {
684+
add(el:Element,value:string|string[]|Function,animateWrapperFn:AnimationClassFunction):void;
685+
addCallback(el:Element,value:AnimationFunction,animateWrapperFn:AnimationEventFunction):void;
686+
addClasses(details:AnimationDetails,classes:string|string[]):void;
687+
addResolver(details:AnimationDetails,resolver:Function):void;
688+
animate(el:Element,removeFn:Function):void;
689+
// (undocumented)
690+
has(el:Element):boolean;
691+
// (undocumented)
692+
remove(el:Element):void;
693+
// (undocumented)
694+
static ɵfac: ɵɵFactoryDeclaration<ElementRegistry,never>;
695+
// (undocumented)
696+
static ɵprov: ɵɵInjectableDeclaration<ElementRegistry>;
697+
}
698+
670699
// @public
671700
exportabstractclassEmbeddedViewRef<C>extendsViewRef {
672701
abstract context:C;

‎packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ describe('type check blocks', () => {
2121
expect(tcb('{{hello}} {{world}}')).toContain('"" + (((this).hello)) + (((this).world));');
2222
});
2323

24-
it('should generate an animationin function call',()=>{
25-
constTEMPLATE='<p (animate.enter)="animateFn($event)"></p>';
24+
it('should generate an animationleave function call',()=>{
25+
constTEMPLATE='<p (animate.leave)="animateFn($event)"></p>';
2626
constresults=tcb(TEMPLATE);
2727
expect(results).toContain(
2828
'($event: i1.AnimationCallbackEvent): any => { (this).animateFn($event); };',

‎packages/compiler-cli/test/compliance/test_cases/r3_view_compiler/animations/GOLDEN_PARTIAL.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
148148
/****************************************************************************************************
149149
* PARTIAL FILE: animate_enter_with_event_listener.d.ts
150150
****************************************************************************************************/
151+
import{AnimationCallbackEvent}from'@angular/core';
151152
import*asi0from"@angular/core";
152153
exportdeclareclassMyComponent{
153-
slideFn(event:any):void;
154+
slideFn(event:AnimationCallbackEvent):void;
154155
staticɵfac:i0.ɵɵFactoryDeclaration<MyComponent,never>;
155156
staticɵcmp:i0.ɵɵComponentDeclaration<MyComponent,"my-component",never,{},{},never,never,true,never>;
156157
}
@@ -258,9 +259,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
258259
/****************************************************************************************************
259260
* PARTIAL FILE: animate_leave_with_event_listener.d.ts
260261
****************************************************************************************************/
262+
import{AnimationCallbackEvent}from'@angular/core';
261263
import*asi0from"@angular/core";
262264
exportdeclareclassMyComponent{
263-
fadeFn(event:any):void;
265+
fadeFn(event:AnimationCallbackEvent):void;
264266
staticɵfac:i0.ɵɵFactoryDeclaration<MyComponent,never>;
265267
staticɵcmp:i0.ɵɵComponentDeclaration<MyComponent,"my-component",never,{},{},never,never,true,never>;
266268
}

‎packages/compiler-cli/test/compliance/test_cases/r3_view_compiler/animations/animate_enter_with_event_listener.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import{Component}from'@angular/core';
1+
import{Component,AnimationCallbackEvent}from'@angular/core';
22

33
@Component({
44
selector:'my-component',
@@ -9,7 +9,7 @@ import {Component} from '@angular/core';
99
`,
1010
})
1111
exportclassMyComponent{
12-
slideFn(event:any){
12+
slideFn(event:AnimationCallbackEvent){
1313
event.target.classList.add('slide-in');
1414
}
1515
}

‎packages/compiler-cli/test/compliance/test_cases/r3_view_compiler/animations/animate_leave_with_event_listener.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import{Component}from'@angular/core';
1+
import{Component,AnimationCallbackEvent}from'@angular/core';
22

33
@Component({
44
selector:'my-component',
@@ -9,7 +9,7 @@ import {Component} from '@angular/core';
99
`,
1010
})
1111
exportclassMyComponent{
12-
fadeFn(event:any){
12+
fadeFn(event:AnimationCallbackEvent){
1313
event.target.classList.add('fade-out');
1414
}
1515
}

‎packages/core/src/animation.ts

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/**
2+
*@license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import{Injectable}from'./di';
10+
11+
/**
12+
* The event type for when `animate.enter` and `animate.leave` are used with function
13+
* callbacks.
14+
*
15+
*@publicApi 20.2
16+
*/
17+
exporttypeAnimationCallbackEvent={target:Element;animationComplete:Function};
18+
19+
/**
20+
* Animation removal functions have a four second long maximum duration timeout.
21+
* This value mirrors from Chrome's cross document navigation view transition timeout.
22+
* It's intended to prevent people from accidentally forgetting to call the removal
23+
* function in their callback.
24+
*/
25+
constMAX_ANIMATION_TIMEOUT=4000;
26+
27+
/**
28+
* The function type for `animate.enter` and `animate.leave` when they are used with
29+
* function callbacks.
30+
*
31+
*@publicApi 20.2
32+
*/
33+
exporttypeAnimationFunction=(event:AnimationCallbackEvent)=>void;
34+
35+
exporttypeAnimationEventFunction=(
36+
el:Element,
37+
value:AnimationFunction,
38+
)=>AnimationRemoveFunction;
39+
exporttypeAnimationClassFunction=(
40+
el:Element,
41+
value:Set<string>|null,
42+
resolvers:Function[]|undefined,
43+
)=>AnimationRemoveFunction;
44+
exporttypeAnimationRemoveFunction=(removeFn:VoidFunction)=>void;
45+
46+
exportinterfaceLongestAnimation{
47+
animationName:string|undefined;
48+
propertyName:string|undefined;
49+
duration:number;
50+
}
51+
52+
exportinterfaceAnimationDetails{
53+
classes:Set<string>|null;
54+
classFns?:Function[];
55+
animateFn:AnimationRemoveFunction;
56+
}
57+
58+
/**
59+
* Registers elements for delayed removal action for animation in the case
60+
* that `animate.leave` is used. This stores the target element and any
61+
* classes, class resolvers, and callback functions that may be needed
62+
* to apply the removal animation, and then stashes the actual element
63+
* removal function from the dom renderer to be called after the
64+
* animation is finished.
65+
*/
66+
@Injectable({providedIn:'root'})
67+
exportclassElementRegistry{
68+
privateoutElements=newMap<Element,AnimationDetails>();
69+
70+
remove(el:Element):void{
71+
this.outElements.delete(el);
72+
}
73+
74+
/** Used when animate.leave is only applying classes */
75+
addClasses(details:AnimationDetails,classes:string|string[]):void{
76+
constclassList=typeofclasses==='string' ?[classes] :classes;
77+
for(letklassofclassList){
78+
details.classes?.add(klass);
79+
}
80+
}
81+
82+
/** Used when animate.leave is applying classes via a bound attribute
83+
* which requires resolving the binding function at the right time
84+
* to get the proper class list. There may be multiple resolvers due
85+
* to composition via host bindings.
86+
*/
87+
addResolver(details:AnimationDetails,resolver:Function):void{
88+
if(!details.classFns){
89+
details.classFns=[resolver];
90+
}else{
91+
details.classFns.push(resolver);
92+
}
93+
}
94+
95+
/** Used when `animate.leave` is using the function signature and will have a
96+
* callback function, rather than a list of classes.
97+
*/
98+
addCallback(
99+
el:Element,
100+
value:AnimationFunction,
101+
animateWrapperFn:AnimationEventFunction,
102+
):void{
103+
constdetails=this.outElements.get(el)??{classes:null,animateFn:()=>{}};
104+
details.animateFn=animateWrapperFn(el,value);
105+
this.outElements.set(el,details);
106+
}
107+
108+
/** Used when `animate.leave` is using classes. */
109+
add(el:Element,value:string|string[]|Function,animateWrapperFn:AnimationClassFunction){
110+
constdetails=this.outElements.get(el)??{
111+
classes:newSet<string>(),
112+
animateFn:():void=>{},
113+
};
114+
if(typeofvalue==='function'){
115+
this.addResolver(details,value);
116+
}else{
117+
this.addClasses(details,value);
118+
}
119+
details.animateFn=animateWrapperFn(el,details.classes,details.classFns);
120+
this.outElements.set(el,details);
121+
}
122+
123+
has(el:Element):boolean{
124+
returnthis.outElements.has(el);
125+
}
126+
127+
/** This is called by the dom renderer to actually initiate the animation
128+
* using the animateFn stored in the registry. The DOM renderer passes in
129+
* the removal function to be fired off when the animation finishes.
130+
*/
131+
animate(el:Element,removeFn:Function):void{
132+
if(!this.outElements.has(el))return;
133+
constdetails=this.outElements.get(el)!;
134+
// this timeout is used to ensure elements actually get removed in the case
135+
// that the user forgot to call the remove callback. The timeout is cleared
136+
// in the DOM renderer during the remove child process.
137+
consttimeout=setTimeout(()=>removeFn(),MAX_ANIMATION_TIMEOUT);
138+
details.animateFn(()=>removeFn(timeout));
139+
}
140+
}

‎packages/core/src/application/application_tokens.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,15 @@ export const IMAGE_CONFIG = new InjectionToken<ImageConfig>(ngDevMode ? 'ImageCo
164164
providedIn:'root',
165165
factory:()=>IMAGE_CONFIG_DEFAULTS,
166166
});
167+
168+
/**
169+
* A [DI token](api/core/InjectionToken) that enables or disables all enter and leave animations.
170+
*@publicApi 20.2
171+
*/
172+
exportconstANIMATIONS_DISABLED=newInjectionToken<boolean>(
173+
ngDevMode ?'AnimationsDisabled' :'',
174+
{
175+
providedIn:'root',
176+
factory:()=>false,
177+
},
178+
);

‎packages/core/src/core.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export {
5555
PLATFORM_ID,
5656
ANIMATION_MODULE_TYPE,
5757
CSP_NONCE,
58+
ANIMATIONS_DISABLED,
5859
}from'./application/application_tokens';
5960
export{
6061
APP_INITIALIZER,
@@ -121,6 +122,7 @@ export {booleanAttribute, numberAttribute} from './util/coercion';
121122
export{REQUEST,REQUEST_CONTEXT,RESPONSE_INIT}from'./application/platform_tokens';
122123
export{DOCUMENT}from'./document';
123124
export{provideNgReflectAttributes}from'./ng_reflect';
125+
export{AnimationCallbackEvent,AnimationFunction}from'./animation';
124126

125127
import{global}from'./util/global';
126128
if(typeofngDevMode!=='undefined'&&ngDevMode){

‎packages/core/src/core_private_export.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,4 @@ export {getComponentDef as ɵgetComponentDef} from './render3/def_getters';
172172
export{DEHYDRATED_BLOCK_REGISTRYasɵDEHYDRATED_BLOCK_REGISTRY}from'./defer/registry';
173173
export{TimerSchedulerasɵTimerScheduler}from'./defer/timer_scheduler';
174174
export{ɵassertType}from'./type_checking';
175+
export{ElementRegistry}from'./animation';

‎packages/core/src/errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export const enum RuntimeErrorCode {
9292
ASSERTION_NOT_INSIDE_REACTIVE_CONTEXT=-602,
9393

9494
// Styling Errors
95-
95+
ANIMATE_INVALID_VALUE=650,
9696
// Declarations Errors
9797

9898
// i18n Errors

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp