refactor(ivy): evaluate prop-based styling bindings with a new algorithm (#30469)
This is the first refactor PR designed to change how styling bindings (i.e. `[style]` and `[class]`) behave in Ivy. Instead of having a heavy element-by-element context be generated for each element, this new refactor aims to use a single context for each `tNode` element that is examined and iterated over when styling values are to be applied to the element. This patch brings this new functionality to prop-based bindings such as `[style.prop]` and `[class.name]`. PR Close #30469
This commit is contained in:

committed by
Jason Aden

parent
848e53efd0
commit
f03475cac8
@ -17,6 +17,9 @@ 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 {runtimeAllowOldStyling, runtimeIsNewStylingInUse} from '../styling_next/state';
|
||||
import {getBindingNameFromIndex} from '../styling_next/util';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
import {renderStringify} from '../util/misc_utils';
|
||||
import {getRootContext} from '../util/view_traversal_utils';
|
||||
@ -73,6 +76,13 @@ export function Δstyling(
|
||||
|
||||
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||
if (directiveStylingIndex) {
|
||||
// this is temporary hack to get the existing styling instructions to
|
||||
// play ball with the new refactored implementation.
|
||||
// TODO (matsko): remove this once the old implementation is not needed.
|
||||
if (runtimeIsNewStylingInUse()) {
|
||||
newStylingInit();
|
||||
}
|
||||
|
||||
// despite the binding being applied in a queue (below), the allocation
|
||||
// of the directive into the context happens right away. The reason for
|
||||
// this is to retain the ordering of the directives (which is important
|
||||
@ -81,7 +91,7 @@ export function Δstyling(
|
||||
|
||||
const fns = tNode.onElementCreationFns = tNode.onElementCreationFns || [];
|
||||
fns.push(() => {
|
||||
initstyling(
|
||||
initStyling(
|
||||
tNode, classBindingNames, styleBindingNames, styleSanitizer, directiveStylingIndex);
|
||||
registerHostDirective(tNode.stylingTemplate !, directiveStylingIndex);
|
||||
});
|
||||
@ -92,13 +102,13 @@ export function Δstyling(
|
||||
// components) then they will be applied at the end of the `elementEnd`
|
||||
// instruction (because directives are created first before styling is
|
||||
// executed for a new element).
|
||||
initstyling(
|
||||
initStyling(
|
||||
tNode, classBindingNames, styleBindingNames, styleSanitizer,
|
||||
DEFAULT_TEMPLATE_DIRECTIVE_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
function initstyling(
|
||||
function initStyling(
|
||||
tNode: TNode, classBindingNames: string[] | null | undefined,
|
||||
styleBindingNames: string[] | null | undefined,
|
||||
styleSanitizer: StyleSanitizeFn | null | undefined, directiveStylingIndex: number): void {
|
||||
@ -148,6 +158,15 @@ export function ΔstyleProp(
|
||||
updatestyleProp(
|
||||
stylingContext, styleIndex, valueToAdd, DEFAULT_TEMPLATE_DIRECTIVE_INDEX, forceOverride);
|
||||
}
|
||||
|
||||
if (runtimeIsNewStylingInUse()) {
|
||||
const prop = getBindingNameFromIndex(stylingContext, styleIndex, directiveStylingIndex, false);
|
||||
|
||||
// the reason why we cast the value as `boolean` is
|
||||
// because the new styling refactor does not yet support
|
||||
// sanitization or animation players.
|
||||
newStyleProp(prop, value as string | number, suffix);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveStylePropValue(
|
||||
@ -206,6 +225,15 @@ export function ΔclassProp(
|
||||
updateclassProp(
|
||||
stylingContext, classIndex, input, DEFAULT_TEMPLATE_DIRECTIVE_INDEX, forceOverride);
|
||||
}
|
||||
|
||||
if (runtimeIsNewStylingInUse()) {
|
||||
const prop = getBindingNameFromIndex(stylingContext, classIndex, directiveStylingIndex, true);
|
||||
|
||||
// the reason why we cast the value as `boolean` is
|
||||
// because the new styling refactor does not yet support
|
||||
// sanitization or animation players.
|
||||
newClassProp(prop, input as boolean);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -324,11 +352,14 @@ export function ΔstylingApply(): void {
|
||||
const renderer = tNode.type === TNodeType.Element ? lView[RENDERER] : null;
|
||||
const isFirstRender = (lView[FLAGS] & LViewFlags.FirstLViewPass) !== 0;
|
||||
const stylingContext = getStylingContext(index, lView);
|
||||
const totalPlayersQueued = renderStyling(
|
||||
stylingContext, renderer, lView, isFirstRender, null, null, directiveStylingIndex);
|
||||
if (totalPlayersQueued > 0) {
|
||||
const rootContext = getRootContext(lView);
|
||||
scheduleTick(rootContext, RootContextFlags.FlushPlayers);
|
||||
|
||||
if (runtimeAllowOldStyling()) {
|
||||
const totalPlayersQueued = renderStyling(
|
||||
stylingContext, renderer, lView, isFirstRender, null, null, directiveStylingIndex);
|
||||
if (totalPlayersQueued > 0) {
|
||||
const rootContext = getRootContext(lView);
|
||||
scheduleTick(rootContext, RootContextFlags.FlushPlayers);
|
||||
}
|
||||
}
|
||||
|
||||
// because select(n) may not run between every instruction, the cached styling
|
||||
@ -339,6 +370,10 @@ export function ΔstylingApply(): void {
|
||||
// cleared because there is no code in Angular that applies more styling code after a
|
||||
// styling flush has occurred. Note that this will be fixed once FW-1254 lands.
|
||||
setCachedStylingContext(null);
|
||||
|
||||
if (runtimeIsNewStylingInUse()) {
|
||||
newStylingApply();
|
||||
}
|
||||
}
|
||||
|
||||
export function getActiveDirectiveStylingIndex() {
|
||||
|
Reference in New Issue
Block a user