Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/compiler/src/render3/view/styling_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,11 @@ export class StylingBuilder {
private _buildMapBasedInstruction(
valueConverter: ValueConverter, isClassBased: boolean, stylingInput: BoundStylingEntry) {
let totalBindingSlotsRequired = 0;
if (compilerIsNewStylingInUse()) {
// the old implementation does not reserve slot values for
// binding entries. The new one does.
totalBindingSlotsRequired++;
}

// these values must be outside of the update block so that they can
// be evaluated (the AST visit call) during creation time so that any
Expand Down
10 changes: 9 additions & 1 deletion packages/core/src/render3/instructions/styling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {BoundPlayerFactory} from '../styling/player_factory';
import {DEFAULT_TEMPLATE_DIRECTIVE_INDEX} from '../styling/shared';
import {getCachedStylingContext, setCachedStylingContext} from '../styling/state';
import {allocateOrUpdateDirectiveIntoContext, createEmptyStylingContext, forceClassesAsString, forceStylesAsString, getStylingContextFromLView, hasClassInput, hasStyleInput} from '../styling/util';
import {classProp as newClassProp, styleProp as newStyleProp, stylingApply as newStylingApply, stylingInit as newStylingInit} from '../styling_next/instructions';
import {classMap as newClassMap, classProp as newClassProp, styleMap as newStyleMap, styleProp as newStyleProp, stylingApply as newStylingApply, stylingInit as newStylingInit} from '../styling_next/instructions';
import {runtimeAllowOldStyling, runtimeIsNewStylingInUse} from '../styling_next/state';
import {getBindingNameFromIndex} from '../styling_next/util';
import {NO_CHANGE} from '../tokens';
Expand Down Expand Up @@ -285,6 +285,10 @@ export function ɵɵstyleMap(styles: {[styleName: string]: any} | NO_CHANGE | nu
}
updateStyleMap(stylingContext, styles);
}

if (runtimeIsNewStylingInUse()) {
newStyleMap(styles);
}
}


Expand Down Expand Up @@ -328,6 +332,10 @@ export function ɵɵclassMap(classes: {[styleName: string]: any} | NO_CHANGE | s
}
updateClassMap(stylingContext, classes);
}

if (runtimeIsNewStylingInUse()) {
newClassMap(classes);
}
}

/**
Expand Down
330 changes: 228 additions & 102 deletions packages/core/src/render3/styling_next/bindings.ts

Large diffs are not rendered by default.

129 changes: 93 additions & 36 deletions packages/core/src/render3/styling_next/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,25 @@ import {RElement} from '../interfaces/renderer';
import {StylingContext as OldStylingContext, StylingIndex as OldStylingIndex} from '../interfaces/styling';
import {BINDING_INDEX, HEADER_OFFSET, HOST, LView, RENDERER} from '../interfaces/view';
import {getActiveDirectiveId, getActiveDirectiveSuperClassDepth, getActiveDirectiveSuperClassHeight, getLView, getSelectedIndex} from '../state';
import {NO_CHANGE} from '../tokens';
import {getTNode, isStylingContext as isOldStylingContext} from '../util/view_utils';

import {applyClasses, applyStyles, registerBinding, updateClassBinding, updateStyleBinding} from './bindings';
import {TStylingContext} from './interfaces';
import {activeStylingMapFeature, normalizeIntoStylingMap} from './map_based_bindings';
import {attachStylingDebugObject} from './styling_debug';
import {allocStylingContext, updateContextDirectiveIndex} from './util';
import {allocStylingContext, hasValueChanged, updateContextDirectiveIndex} from './util';



/**
* --------
*
* This file contains the core logic for how styling instructions are processed in Angular.
*
* To learn more about the algorithm see `TStylingContext`.
*
* --------
*/

/**
Expand All @@ -49,26 +56,76 @@ export function stylingInit() {
*/
export function styleProp(
prop: string, value: string | number | String | null, suffix?: string | null): void {
_stylingProp(prop, value, false);
}

/**
* Mirror implementation of the `classProp()` instruction (found in `instructions/styling.ts`).
*/
export function classProp(className: string, value: boolean | null): void {
_stylingProp(className, value, true);
}

/**
* Shared function used to update a prop-based styling binding for an element.
*/
function _stylingProp(
prop: string, value: boolean | number | String | string | null, isClassBased: boolean) {
const index = getSelectedIndex();
const lView = getLView();
const bindingIndex = lView[BINDING_INDEX]++;
const tNode = getTNode(index, lView);
const tContext = getStylesContext(tNode);
const defer = getActiveDirectiveSuperClassHeight() > 0;
updateStyleBinding(tContext, lView, prop, bindingIndex, value, defer);
if (isClassBased) {
updateClassBinding(
getClassesContext(tNode), lView, prop, bindingIndex, value as string | boolean | null,
defer);
} else {
updateStyleBinding(
getStylesContext(tNode), lView, prop, bindingIndex, value as string | null, defer);
}
}

/**
* Mirror implementation of the `classProp()` instruction (found in `instructions/styling.ts`).
* Mirror implementation of the `styleMap()` instruction (found in `instructions/styling.ts`).
*/
export function classProp(className: string, value: boolean | null): void {
export function styleMap(styles: {[styleName: string]: any} | NO_CHANGE | null): void {
_stylingMap(styles, false);
}

/**
* Mirror implementation of the `classMap()` instruction (found in `instructions/styling.ts`).
*/
export function classMap(classes: {[className: string]: any} | NO_CHANGE | string | null): void {
_stylingMap(classes, true);
}

/**
* Shared function used to update a map-based styling binding for an element.
*
* When this function is called it will activate support for `[style]` and
* `[class]` bindings in Angular.
*/
function _stylingMap(value: {[key: string]: any} | string | null, isClassBased: boolean) {
activeStylingMapFeature();
const index = getSelectedIndex();
const lView = getLView();
const bindingIndex = lView[BINDING_INDEX]++;
const tNode = getTNode(index, lView);
const tContext = getClassesContext(tNode);
const defer = getActiveDirectiveSuperClassHeight() > 0;
updateClassBinding(tContext, lView, className, bindingIndex, value, defer);

if (value !== NO_CHANGE) {
const tNode = getTNode(index, lView);
const defer = getActiveDirectiveSuperClassHeight() > 0;
const oldValue = lView[bindingIndex];
const valueHasChanged = hasValueChanged(oldValue, value);
const lStylingMap = normalizeIntoStylingMap(oldValue, value);
if (isClassBased) {
updateClassBinding(
getClassesContext(tNode), lView, null, bindingIndex, lStylingMap, defer, valueHasChanged);
} else {
updateStyleBinding(
getStylesContext(tNode), lView, null, bindingIndex, lStylingMap, defer, valueHasChanged);
}
}
}

/**
Expand Down Expand Up @@ -97,33 +154,6 @@ export function stylingApply() {
applyStyles(renderer, lView, getStylesContext(tNode), native, directiveIndex);
}

function getStylesContext(tNode: TNode): TStylingContext {
return getContext(tNode, false);
}

function getClassesContext(tNode: TNode): TStylingContext {
return getContext(tNode, true);
}

/**
* Returns/instantiates a styling context from/to a `tNode` instance.
*/
function getContext(tNode: TNode, isClassBased: boolean) {
let context = isClassBased ? tNode.newClasses : tNode.newStyles;
if (!context) {
context = allocStylingContext();
if (ngDevMode) {
attachStylingDebugObject(context);
}
if (isClassBased) {
tNode.newClasses = context;
} else {
tNode.newStyles = context;
}
}
return context;
}

/**
* Temporary function to bridge styling functionality between this new
* refactor (which is here inside of `styling_next/`) and the old
Expand Down Expand Up @@ -209,3 +239,30 @@ function updateLastDirectiveIndex(tNode: TNode, directiveIndex: number) {
updateContextDirectiveIndex(getClassesContext(tNode), directiveIndex);
updateContextDirectiveIndex(getStylesContext(tNode), directiveIndex);
}

function getStylesContext(tNode: TNode): TStylingContext {
return getContext(tNode, false);
}

function getClassesContext(tNode: TNode): TStylingContext {
return getContext(tNode, true);
}

/**
* Returns/instantiates a styling context from/to a `tNode` instance.
*/
function getContext(tNode: TNode, isClassBased: boolean) {
let context = isClassBased ? tNode.newClasses : tNode.newStyles;
if (!context) {
context = allocStylingContext();
if (ngDevMode) {
attachStylingDebugObject(context);
}
if (isClassBased) {
tNode.newClasses = context;
} else {
tNode.newStyles = context;
}
}
return context;
}
Loading