Skip to content

Commit

Permalink
feat(ivy): enhance [style] and [class] bindings to be animation aware
Browse files Browse the repository at this point in the history
  • Loading branch information
matsko committed Sep 27, 2018
1 parent c7c3ddd commit 8d3f767
Show file tree
Hide file tree
Showing 28 changed files with 3,101 additions and 1,572 deletions.
8 changes: 6 additions & 2 deletions packages/core/src/core_render3_private_export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,16 @@ export {
Player as ɵPlayer,
PlayState as ɵPlayState,
PlayerHandler as ɵPlayerHandler,
} from './render3/animations/interfaces';
} from './render3/interfaces/player';

export {
BindingPlayerFactory as ɵBindingPlayerFactory
} from './render3/styling/binding_player_factory';

export {
addPlayer as ɵaddPlayer,
getPlayers as ɵgetPlayers,
} from './render3/animations/players';
} from './render3/players';

// we reexport these symbols just so that they are retained during the dead code elimination
// performed by rollup while it's creating fesm files.
Expand Down
72 changes: 0 additions & 72 deletions packages/core/src/render3/animations/players.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/core/src/render3/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import {Type} from '../core';
import {Injector} from '../di/injector';
import {Sanitizer} from '../sanitization/security';

import {PlayerHandler} from './animations/interfaces';
import {assertComponentType, assertDefined} from './assert';
import {getLElementFromComponent, readPatchedLViewData} from './context_discovery';
import {getComponentDef} from './definition';
import {queueInitHooks, queueLifecycleHooks} from './hooks';
import {PlayerHandler} from './interfaces/player';
import {CLEAN_PROMISE, baseDirectiveCreate, createLViewData, createTView, detectChangesInternal, enterView, executeInitAndContentHooks, hostElement, leaveView, locateHostElement, setHostBindings, queueHostBindingForCheck,} from './instructions';
import {ComponentDef, ComponentDefInternal, ComponentType} from './interfaces/definition';
import {LElementNode} from './interfaces/node';
Expand All @@ -25,7 +25,6 @@ import {CONTEXT, INJECTOR, LViewData, LViewFlags, RootContext, RootContextFlags,
import {getRootView, stringify} from './util';



/** Options that control how the component should be bootstrapped. */
export interface CreateComponentOptions {
/** Which renderer factory to use. */
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/render3/context_discovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ export function getContext(target: any): LContext|null {
/**
* Creates an empty instance of a `LContext` context
*/
function createLContext(lViewData: LViewData, lNodeIndex: number, native: RElement): LContext {
export function createLContext(
lViewData: LViewData, lNodeIndex: number, native: RElement): LContext {
return {
lViewData,
lNodeIndex,
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/render3/discovery_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ export function getHostComponent<T = {}>(target: {}): T|null {
* Returns the `RootContext` instance that is associated with
* the application where the target is situated.
*/
export function getRootContext(target: {}): RootContext {
const context = loadContext(target) !;
const rootLViewData = getRootView(context.lViewData);
export function getRootContext(target: LViewData | {}): RootContext {
const lViewData = Array.isArray(target) ? target : loadContext(target) !.lViewData;
const rootLViewData = getRootView(lViewData);
return rootLViewData[CONTEXT] as RootContext;
}

Expand Down
36 changes: 23 additions & 13 deletions packages/core/src/render3/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import './ng_dev_mode';
import {QueryList} from '../linker';
import {Sanitizer} from '../sanitization/security';
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';

import {assertDefined, assertEqual, assertLessThan, assertNotEqual} from './assert';
import {attachPatchData, getLElementFromComponent, readElementValue, readPatchedLViewData} from './context_discovery';
import {getRootView} from './discovery_utils';
import {attachPatchData, getContext, getLElementFromComponent, readElementValue, readPatchedLViewData} from './context_discovery';
import {getRootContext, getRootView} from './discovery_utils';
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
Expand All @@ -23,13 +24,17 @@ import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LEleme
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
import {LQueries} from './interfaces/query';
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer';
import {StylingContext} from './interfaces/styling';
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DECLARATION_VIEW, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RootContext, RootContextFlags, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {appendChild, appendProjectedNode, createTextNode, findComponentView, getContainerNode, getHostElementNode, getLViewChild, getParentOrContainerNode, getRenderParent, insertView, removeView} from './node_manipulation';
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
import {StylingContext, allocStylingContext, createStylingContextTemplate, renderStyling as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling';
import {BindingPlayerFactory} from './styling/binding_player_factory';
import {allocStylingContext, createStylingContextTemplate, renderStyleAndClassBindings as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings';
import {assertDataInRangeInternal, getLNode, isContentQueryHost, isDifferent, loadElementInternal, loadInternal, stringify} from './util';



/**
* A permanent marker promise which signifies that the current CD tree is
* clean.
Expand Down Expand Up @@ -1488,8 +1493,10 @@ function generatePropertyAliases(
* @param value A value indicating if a given class should be added or removed.
*/
export function elementClassProp<T>(
index: number, stylingIndex: number, value: T | NO_CHANGE): void {
updateElementClassProp(getStylingContext(index), stylingIndex, value ? true : false);
index: number, stylingIndex: number,
value: T | BindingPlayerFactory<boolean>| NO_CHANGE): void {
let val = (value instanceof BindingPlayerFactory) ? value : (!!value);
updateElementClassProp(getStylingContext(index), stylingIndex, val);
}

/**
Expand Down Expand Up @@ -1574,7 +1581,11 @@ function getStylingContext(index: number): StylingContext {
* index.)
*/
export function elementStylingApply<T>(index: number): void {
renderElementStyles(getStylingContext(index), renderer);
const totalPlayersQueued = renderElementStyles(getStylingContext(index), renderer, viewData);
if (totalPlayersQueued > 0) {
const rootContext = getRootContext(viewData);
scheduleTick(rootContext, RootContextFlags.FlushPlayers);
}
}

/**
Expand Down Expand Up @@ -2357,11 +2368,7 @@ export function markViewDirty(view: LViewData): void {
ngDevMode && assertDefined(currentView[CONTEXT], 'rootContext should be defined');

const rootContext = currentView[CONTEXT] as RootContext;
const nothingScheduled = rootContext.flags === RootContextFlags.Empty;
rootContext.flags |= RootContextFlags.DetectChanges;
if (nothingScheduled) {
scheduleTick(rootContext);
}
scheduleTick(rootContext, RootContextFlags.DetectChanges);
}

/**
Expand All @@ -2375,8 +2382,11 @@ export function markViewDirty(view: LViewData): void {
* `scheduleTick` requests. The scheduling function can be overridden in
* `renderComponent`'s `scheduler` option.
*/
export function scheduleTick<T>(rootContext: RootContext) {
if (rootContext.clean == _CLEAN_PROMISE) {
export function scheduleTick<T>(rootContext: RootContext, flags: RootContextFlags) {
const nothingScheduled = rootContext.flags === RootContextFlags.Empty;
rootContext.flags |= flags;

if (nothingScheduled && rootContext.clean == _CLEAN_PROMISE) {
let res: null|((val: null) => void);
rootContext.clean = new Promise<null>((r) => res = r);
rootContext.scheduler(() => {
Expand Down
3 changes: 1 addition & 2 deletions packages/core/src/render3/interfaces/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/

import {StylingContext} from '../styling';

import {LContainer} from './container';
import {LInjector} from './injector';
import {LQueries} from './query';
import {RComment, RElement, RText} from './renderer';
import {StylingContext} from './styling';
import {LViewData, TView} from './view';


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ export interface Player {
addEventListener(state: PlayState|string, cb: (data?: any) => any): void;
}

export abstract class PlayerFactory {
public dirty !: boolean;
abstract buildPlayer(existingPlayer?: Player|null): Player|null;
}

/**
* The state of a given player
*
Expand All @@ -29,11 +34,15 @@ export interface Player {
export const enum PlayState {Pending = 0, Running = 1, Paused = 2, Finished = 100, Destroyed = 200}

/**
* The context that stores all active animation players present on an element.
* The context that stores all the active players and queued player factories present on an element.
*/
export declare type AnimationContext = Player[];
export declare type ComponentInstance = {};
export declare type DirectiveInstance = {};
export interface PlayerContext extends Array<null|number|Player|PlayerFactory> {
[PlayerIndex.NonFactoryPlayersStart]: number;
[PlayerIndex.ClassMapFactoryPosition]: PlayerFactory|null;
[PlayerIndex.ClassMapPlayerPosition]: Player|null;
[PlayerIndex.StyleMapFactoryPosition]: PlayerFactory|null;
[PlayerIndex.StyleMapPlayerPosition]: Player|null;
}

/**
* Designed to be used as an injection service to capture all animation players.
Expand All @@ -54,3 +63,27 @@ export interface PlayerHandler {
*/
queuePlayer(player: Player, context: ComponentInstance|DirectiveInstance|HTMLElement): void;
}

export const enum PlayerIndex {
// The position where the index that reveals where players start in the PlayerContext
NonFactoryPlayersStart = 0,
// The position where the factory to handle a {key:value} map expression for classes
ClassMapFactoryPosition = 1,
// The position where the last player assigned to the class factory is stored
ClassMapPlayerPosition = 2,
// The position where the factory to handle a {key:value} map expression for styles
StyleMapFactoryPosition = 3,
// The position where the last player assigned to the style factory is stored
StyleMapPlayerPosition = 4,
// The position where any factories start in the PlayerContext
FactoriesStartPosition = 1,
// The position where non map-based factories start in the PlayerContext
SingleFactoriesStartPosition = 5,
// For each factory there is a player in the player context (therefore size = 2)
PlayerAndFactoryTupleSize = 2,
// The player exists next to the factory in the list
PlayerOffsetPosition = 1,
}

export declare type ComponentInstance = {};
export declare type DirectiveInstance = {};

0 comments on commit 8d3f767

Please sign in to comment.