feat(animations): expose element
and params
within transition matchers (#22693)
PR Close #22693
This commit is contained in:
parent
db56836425
commit
58b94e6f5e
@ -46,7 +46,8 @@ export interface StateAst extends Ast<AnimationMetadataType.State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TransitionAst extends Ast<AnimationMetadataType.Transition> {
|
export interface TransitionAst extends Ast<AnimationMetadataType.Transition> {
|
||||||
matchers: ((fromState: string, toState: string) => boolean)[];
|
matchers: ((fromState: string, toState: string, element: any, params: {[key: string]:
|
||||||
|
any}) => boolean)[];
|
||||||
animation: Ast<AnimationMetadataType>;
|
animation: Ast<AnimationMetadataType>;
|
||||||
queryCount: number;
|
queryCount: number;
|
||||||
depCount: number;
|
depCount: number;
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
export const ANY_STATE = '*';
|
export const ANY_STATE = '*';
|
||||||
export declare type TransitionMatcherFn = (fromState: any, toState: any) => boolean;
|
export declare type TransitionMatcherFn =
|
||||||
|
(fromState: any, toState: any, element: any, params: {[key: string]: any}) => boolean;
|
||||||
|
|
||||||
export function parseTransitionExpr(
|
export function parseTransitionExpr(
|
||||||
transitionValue: string | TransitionMatcherFn, errors: string[]): TransitionMatcherFn[] {
|
transitionValue: string | TransitionMatcherFn, errors: string[]): TransitionMatcherFn[] {
|
||||||
|
@ -24,8 +24,8 @@ export class AnimationTransitionFactory {
|
|||||||
private _triggerName: string, public ast: TransitionAst,
|
private _triggerName: string, public ast: TransitionAst,
|
||||||
private _stateStyles: {[stateName: string]: AnimationStateStyles}) {}
|
private _stateStyles: {[stateName: string]: AnimationStateStyles}) {}
|
||||||
|
|
||||||
match(currentState: any, nextState: any): boolean {
|
match(currentState: any, nextState: any, element: any, params: {[key: string]: any}): boolean {
|
||||||
return oneOrMoreTransitionsMatch(this.ast.matchers, currentState, nextState);
|
return oneOrMoreTransitionsMatch(this.ast.matchers, currentState, nextState, element, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
buildStyles(stateName: string, params: {[key: string]: any}, errors: any[]) {
|
buildStyles(stateName: string, params: {[key: string]: any}, errors: any[]) {
|
||||||
@ -89,8 +89,9 @@ export class AnimationTransitionFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function oneOrMoreTransitionsMatch(
|
function oneOrMoreTransitionsMatch(
|
||||||
matchFns: TransitionMatcherFn[], currentState: any, nextState: any): boolean {
|
matchFns: TransitionMatcherFn[], currentState: any, nextState: any, element: any,
|
||||||
return matchFns.some(fn => fn(currentState, nextState));
|
params: {[key: string]: any}): boolean {
|
||||||
|
return matchFns.some(fn => fn(currentState, nextState, element, params));
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AnimationStateStyles {
|
export class AnimationStateStyles {
|
||||||
|
@ -47,8 +47,10 @@ export class AnimationTrigger {
|
|||||||
|
|
||||||
get containsQueries() { return this.ast.queryCount > 0; }
|
get containsQueries() { return this.ast.queryCount > 0; }
|
||||||
|
|
||||||
matchTransition(currentState: any, nextState: any): AnimationTransitionFactory|null {
|
matchTransition(currentState: any, nextState: any, element: any, params: {[key: string]: any}):
|
||||||
const entry = this.transitionFactories.find(f => f.match(currentState, nextState));
|
AnimationTransitionFactory|null {
|
||||||
|
const entry =
|
||||||
|
this.transitionFactories.find(f => f.match(currentState, nextState, element, params));
|
||||||
return entry || null;
|
return entry || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,8 @@ export class AnimationTransitionNamespace {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let transition = trigger.matchTransition(fromState.value, toState.value);
|
let transition =
|
||||||
|
trigger.matchTransition(fromState.value, toState.value, element, toState.params);
|
||||||
let isFallbackTransition = false;
|
let isFallbackTransition = false;
|
||||||
if (!transition) {
|
if (!transition) {
|
||||||
if (!defaultToFallback) return;
|
if (!defaultToFallback) return;
|
||||||
|
@ -103,7 +103,7 @@ import {makeTrigger} from '../shared';
|
|||||||
it('should null when no results are found', () => {
|
it('should null when no results are found', () => {
|
||||||
const result = makeTrigger('name', [transition('a => b', animate(1111))]);
|
const result = makeTrigger('name', [transition('a => b', animate(1111))]);
|
||||||
|
|
||||||
const trigger = result.matchTransition('b', 'a');
|
const trigger = result.matchTransition('b', 'a', {}, {});
|
||||||
expect(trigger).toBeFalsy();
|
expect(trigger).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -226,7 +226,8 @@ function buildTransition(
|
|||||||
trigger: AnimationTrigger, element: any, fromState: any, toState: any,
|
trigger: AnimationTrigger, element: any, fromState: any, toState: any,
|
||||||
fromOptions?: AnimationOptions, toOptions?: AnimationOptions): AnimationTransitionInstruction|
|
fromOptions?: AnimationOptions, toOptions?: AnimationOptions): AnimationTransitionInstruction|
|
||||||
null {
|
null {
|
||||||
const trans = trigger.matchTransition(fromState, toState) !;
|
const params = toOptions && toOptions.params || {};
|
||||||
|
const trans = trigger.matchTransition(fromState, toState, element, params) !;
|
||||||
if (trans) {
|
if (trans) {
|
||||||
const driver = new MockAnimationDriver();
|
const driver = new MockAnimationDriver();
|
||||||
return trans.build(
|
return trans.build(
|
||||||
|
@ -115,7 +115,9 @@ export interface AnimationStateMetadata extends AnimationMetadata {
|
|||||||
* @experimental Animation support is experimental.
|
* @experimental Animation support is experimental.
|
||||||
*/
|
*/
|
||||||
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
||||||
expr: string|((fromState: string, toState: string) => boolean);
|
expr: string|
|
||||||
|
((fromState: string, toState: string, element?: any,
|
||||||
|
params?: {[key: string]: any}) => boolean);
|
||||||
animation: AnimationMetadata|AnimationMetadata[];
|
animation: AnimationMetadata|AnimationMetadata[];
|
||||||
options: AnimationOptions|null;
|
options: AnimationOptions|null;
|
||||||
}
|
}
|
||||||
@ -294,6 +296,38 @@ export interface AnimationStaggerMetadata extends AnimationMetadata {
|
|||||||
* <div [@myAnimationTrigger]="myStatusExp">...</div>
|
* <div [@myAnimationTrigger]="myStatusExp">...</div>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
* ### Using an inline function
|
||||||
|
* The `transition` animation method also supports reading an inline function which can decide
|
||||||
|
* if its associated animation should be run.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* // this method will be run each time the `myAnimationTrigger`
|
||||||
|
* // trigger value changes...
|
||||||
|
* function myInlineMatcherFn(fromState: string, toState: string, element: any, params: {[key:
|
||||||
|
string]: any}): boolean {
|
||||||
|
* // notice that `element` and `params` are also available here
|
||||||
|
* return toState == 'yes-please-animate';
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Component({
|
||||||
|
* selector: 'my-component',
|
||||||
|
* templateUrl: 'my-component-tpl.html',
|
||||||
|
* animations: [
|
||||||
|
* trigger('myAnimationTrigger', [
|
||||||
|
* transition(myInlineMatcherFn, [
|
||||||
|
* // the animation sequence code
|
||||||
|
* ]),
|
||||||
|
* ])
|
||||||
|
* ]
|
||||||
|
* })
|
||||||
|
* class MyComponent {
|
||||||
|
* myStatusExp = "yes-please-animate";
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The inline method will be run each time the trigger
|
||||||
|
* value changes
|
||||||
|
*
|
||||||
* ## Disable Animations
|
* ## Disable Animations
|
||||||
* A special animation control binding called `@.disabled` can be placed on an element which will
|
* A special animation control binding called `@.disabled` can be placed on an element which will
|
||||||
then disable animations for any inner animation triggers situated within the element as well as
|
then disable animations for any inner animation triggers situated within the element as well as
|
||||||
@ -844,7 +878,8 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe
|
|||||||
* @experimental Animation support is experimental.
|
* @experimental Animation support is experimental.
|
||||||
*/
|
*/
|
||||||
export function transition(
|
export function transition(
|
||||||
stateChangeExpr: string | ((fromState: string, toState: string) => boolean),
|
stateChangeExpr: string | ((fromState: string, toState: string, element?: any,
|
||||||
|
params?: {[key: string]: any}) => boolean),
|
||||||
steps: AnimationMetadata | AnimationMetadata[],
|
steps: AnimationMetadata | AnimationMetadata[],
|
||||||
options: AnimationOptions | null = null): AnimationTransitionMetadata {
|
options: AnimationOptions | null = null): AnimationTransitionMetadata {
|
||||||
return {type: AnimationMetadataType.Transition, expr: stateChangeExpr, animation: steps, options};
|
return {type: AnimationMetadataType.Transition, expr: stateChangeExpr, animation: steps, options};
|
||||||
|
@ -38,7 +38,8 @@ export interface AnimationStateMetadata extends AnimationMetadata {
|
|||||||
* @deprecated This symbol has moved. Please Import from @angular/animations instead!
|
* @deprecated This symbol has moved. Please Import from @angular/animations instead!
|
||||||
*/
|
*/
|
||||||
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
||||||
expr: string|((fromState: string, toState: string) => boolean);
|
expr: string|
|
||||||
|
((fromState: string, toState: string, element: any, params: {[key: string]: any}) => boolean);
|
||||||
animation: AnimationMetadata|AnimationMetadata[];
|
animation: AnimationMetadata|AnimationMetadata[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,12 +301,15 @@ const DEFAULT_COMPONENT_ID = '1';
|
|||||||
|
|
||||||
it('should allow a transition to use a function to determine what method to run', () => {
|
it('should allow a transition to use a function to determine what method to run', () => {
|
||||||
let valueToMatch = '';
|
let valueToMatch = '';
|
||||||
const transitionFn =
|
let capturedElement: any;
|
||||||
(fromState: string, toState: string) => { return toState == valueToMatch; };
|
const transitionFn = (fromState: string, toState: string, element: any) => {
|
||||||
|
capturedElement = element;
|
||||||
|
return toState == valueToMatch;
|
||||||
|
};
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'if-cmp',
|
selector: 'if-cmp',
|
||||||
template: '<div [@myAnimation]="exp"></div>',
|
template: '<div #element [@myAnimation]="exp"></div>',
|
||||||
animations: [
|
animations: [
|
||||||
trigger('myAnimation', [transition(
|
trigger('myAnimation', [transition(
|
||||||
transitionFn,
|
transitionFn,
|
||||||
@ -314,6 +317,8 @@ const DEFAULT_COMPONENT_ID = '1';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
class Cmp {
|
class Cmp {
|
||||||
|
@ViewChild('element')
|
||||||
|
element: any;
|
||||||
exp: any = '';
|
exp: any = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,11 +328,13 @@ const DEFAULT_COMPONENT_ID = '1';
|
|||||||
const cmp = fixture.componentInstance;
|
const cmp = fixture.componentInstance;
|
||||||
valueToMatch = cmp.exp = 'something';
|
valueToMatch = cmp.exp = 'something';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
const element = cmp.element.nativeElement;
|
||||||
|
|
||||||
let players = getLog();
|
let players = getLog();
|
||||||
expect(players.length).toEqual(1);
|
expect(players.length).toEqual(1);
|
||||||
let [p1] = players;
|
let [p1] = players;
|
||||||
expect(p1.totalTime).toEqual(1234);
|
expect(p1.totalTime).toEqual(1234);
|
||||||
|
expect(capturedElement).toEqual(element);
|
||||||
resetLog();
|
resetLog();
|
||||||
|
|
||||||
valueToMatch = 'something-else';
|
valueToMatch = 'something-else';
|
||||||
@ -338,6 +345,49 @@ const DEFAULT_COMPONENT_ID = '1';
|
|||||||
expect(players.length).toEqual(0);
|
expect(players.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow a transition to use a function to determine what method to run and expose any parameter values',
|
||||||
|
() => {
|
||||||
|
const transitionFn =
|
||||||
|
(fromState: string, toState: string, element: any, params: {[key: string]: any}) => {
|
||||||
|
return params['doMatch'] == true;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'if-cmp',
|
||||||
|
template: '<div [@myAnimation]="{value:exp, params: {doMatch:doMatch}}"></div>',
|
||||||
|
animations: [
|
||||||
|
trigger(
|
||||||
|
'myAnimation',
|
||||||
|
[transition(
|
||||||
|
transitionFn, [style({opacity: 0}), animate(3333, style({opacity: 1}))])]),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
class Cmp {
|
||||||
|
doMatch = false;
|
||||||
|
exp: any = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||||
|
|
||||||
|
const fixture = TestBed.createComponent(Cmp);
|
||||||
|
const cmp = fixture.componentInstance;
|
||||||
|
cmp.doMatch = true;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
let players = getLog();
|
||||||
|
expect(players.length).toEqual(1);
|
||||||
|
let [p1] = players;
|
||||||
|
expect(p1.totalTime).toEqual(3333);
|
||||||
|
resetLog();
|
||||||
|
|
||||||
|
cmp.doMatch = false;
|
||||||
|
cmp.exp = 'this-wont-match';
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
players = getLog();
|
||||||
|
expect(players.length).toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
it('should allow a state value to be `0`', () => {
|
it('should allow a state value to be `0`', () => {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'if-cmp',
|
selector: 'if-cmp',
|
||||||
|
@ -173,7 +173,9 @@ export interface AnimationStyleMetadata extends AnimationMetadata {
|
|||||||
/** @experimental */
|
/** @experimental */
|
||||||
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
||||||
animation: AnimationMetadata | AnimationMetadata[];
|
animation: AnimationMetadata | AnimationMetadata[];
|
||||||
expr: string | ((fromState: string, toState: string) => boolean);
|
expr: string | ((fromState: string, toState: string, element?: any, params?: {
|
||||||
|
[key: string]: any;
|
||||||
|
}) => boolean);
|
||||||
options: AnimationOptions | null;
|
options: AnimationOptions | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +243,9 @@ export declare function style(tokens: '*' | {
|
|||||||
}>): AnimationStyleMetadata;
|
}>): AnimationStyleMetadata;
|
||||||
|
|
||||||
/** @experimental */
|
/** @experimental */
|
||||||
export declare function transition(stateChangeExpr: string | ((fromState: string, toState: string) => boolean), steps: AnimationMetadata | AnimationMetadata[], options?: AnimationOptions | null): AnimationTransitionMetadata;
|
export declare function transition(stateChangeExpr: string | ((fromState: string, toState: string, element?: any, params?: {
|
||||||
|
[key: string]: any;
|
||||||
|
}) => boolean), steps: AnimationMetadata | AnimationMetadata[], options?: AnimationOptions | null): AnimationTransitionMetadata;
|
||||||
|
|
||||||
/** @experimental */
|
/** @experimental */
|
||||||
export declare function trigger(name: string, definitions: AnimationMetadata[]): AnimationTriggerMetadata;
|
export declare function trigger(name: string, definitions: AnimationMetadata[]): AnimationTriggerMetadata;
|
||||||
|
4
tools/public_api_guard/core/core.d.ts
vendored
4
tools/public_api_guard/core/core.d.ts
vendored
@ -94,7 +94,9 @@ export interface AnimationTransitionEvent {
|
|||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
export interface AnimationTransitionMetadata extends AnimationMetadata {
|
||||||
animation: AnimationMetadata | AnimationMetadata[];
|
animation: AnimationMetadata | AnimationMetadata[];
|
||||||
expr: string | ((fromState: string, toState: string) => boolean);
|
expr: string | ((fromState: string, toState: string, element: any, params: {
|
||||||
|
[key: string]: any;
|
||||||
|
}) => boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user