refactor(ivy): break apart stylingMap into styleMap and classMap instructions (#30293)
This patch breaks up the existing `elementStylingMap` into `elementClassMap` and `elementStyleMap` instructions. It also breaks apart `hostStlyingMap` into `hostClassMap` and `hostStyleMap` instructions. This change allows for better tree-shaking and reduces the complexity of the styling algorithm code for `[style]` and `[class]` bindings. PR Close #30293
This commit is contained in:

committed by
Kara Erickson

parent
98a38ec98b
commit
be8fbac942
@ -51,7 +51,9 @@ export class Identifiers {
|
||||
|
||||
static elementStyling: o.ExternalReference = {name: 'ɵɵelementStyling', moduleName: CORE};
|
||||
|
||||
static elementStylingMap: o.ExternalReference = {name: 'ɵɵelementStylingMap', moduleName: CORE};
|
||||
static elementStyleMap: o.ExternalReference = {name: 'ɵɵelementStyleMap', moduleName: CORE};
|
||||
|
||||
static elementClassMap: o.ExternalReference = {name: 'ɵɵelementClassMap', moduleName: CORE};
|
||||
|
||||
static elementStyleProp: o.ExternalReference = {name: 'ɵɵelementStyleProp', moduleName: CORE};
|
||||
|
||||
@ -62,8 +64,11 @@ export class Identifiers {
|
||||
|
||||
static elementHostStyling: o.ExternalReference = {name: 'ɵɵelementHostStyling', moduleName: CORE};
|
||||
|
||||
static elementHostStylingMap:
|
||||
o.ExternalReference = {name: 'ɵɵelementHostStylingMap', moduleName: CORE};
|
||||
static elementHostStyleMap:
|
||||
o.ExternalReference = {name: 'ɵɵelementHostStyleMap', moduleName: CORE};
|
||||
|
||||
static elementHostClassMap:
|
||||
o.ExternalReference = {name: 'ɵɵelementHostClassMap', moduleName: CORE};
|
||||
|
||||
static elementHostStyleProp:
|
||||
o.ExternalReference = {name: 'ɵɵelementHostStyleProp', moduleName: CORE};
|
||||
|
@ -61,7 +61,8 @@ interface BoundStylingEntry {
|
||||
* elementStyling(...)
|
||||
* }
|
||||
* if (updateMode) {
|
||||
* elementStylingMap(...)
|
||||
* elementStyleMap(...)
|
||||
* elementClassMap(...)
|
||||
* elementStyleProp(...)
|
||||
* elementClassProp(...)
|
||||
* elementStylingApp(...)
|
||||
@ -339,73 +340,67 @@ export class StylingBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an instruction with all the expressions and parameters for `elementStylingMap`.
|
||||
* Builds an instruction with all the expressions and parameters for `elementClassMap`.
|
||||
*
|
||||
* The instruction data will contain all expressions for `elementStylingMap` to function
|
||||
* which include the `[style]` and `[class]` expression params (if they exist) as well as
|
||||
* the sanitizer and directive reference expression.
|
||||
* The instruction data will contain all expressions for `elementClassMap` to function
|
||||
* which includes the `[class]` expression params.
|
||||
*/
|
||||
buildElementStylingMapInstruction(valueConverter: ValueConverter): Instruction|null {
|
||||
if (this._classMapInput || this._styleMapInput) {
|
||||
const stylingInput = this._classMapInput ! || this._styleMapInput !;
|
||||
let totalBindingSlotsRequired = 0;
|
||||
|
||||
// these values must be outside of the update block so that they can
|
||||
// be evaluted (the AST visit call) during creation time so that any
|
||||
// pipes can be picked up in time before the template is built
|
||||
const mapBasedClassValue =
|
||||
this._classMapInput ? this._classMapInput.value.visit(valueConverter) : null;
|
||||
if (mapBasedClassValue instanceof Interpolation) {
|
||||
totalBindingSlotsRequired += mapBasedClassValue.expressions.length;
|
||||
}
|
||||
|
||||
const mapBasedStyleValue =
|
||||
this._styleMapInput ? this._styleMapInput.value.visit(valueConverter) : null;
|
||||
if (mapBasedStyleValue instanceof Interpolation) {
|
||||
totalBindingSlotsRequired += mapBasedStyleValue.expressions.length;
|
||||
}
|
||||
|
||||
const isHostBinding = this._directiveExpr;
|
||||
const reference = isHostBinding ? R3.elementHostStylingMap : R3.elementStylingMap;
|
||||
|
||||
return {
|
||||
sourceSpan: stylingInput.sourceSpan,
|
||||
reference,
|
||||
allocateBindingSlots: totalBindingSlotsRequired,
|
||||
buildParams: (convertFn: (value: any) => o.Expression) => {
|
||||
// HOST:
|
||||
// min params => elementHostStylingMap(classMap)
|
||||
// max params => elementHostStylingMap(classMap, styleMap)
|
||||
// Template:
|
||||
// min params => elementStylingMap(elmIndex, classMap)
|
||||
// max params => elementStylingMap(elmIndex, classMap, styleMap)
|
||||
|
||||
const params: o.Expression[] = [];
|
||||
if (!isHostBinding) {
|
||||
params.push(this._elementIndexExpr);
|
||||
}
|
||||
|
||||
let expectedNumberOfArgs = 0;
|
||||
if (mapBasedStyleValue) {
|
||||
expectedNumberOfArgs = 2;
|
||||
} else if (mapBasedClassValue) {
|
||||
// index and class = 2
|
||||
expectedNumberOfArgs = 1;
|
||||
}
|
||||
|
||||
addParam(
|
||||
params, mapBasedClassValue, mapBasedClassValue ? convertFn(mapBasedClassValue) : null,
|
||||
1, expectedNumberOfArgs);
|
||||
addParam(
|
||||
params, mapBasedStyleValue, mapBasedStyleValue ? convertFn(mapBasedStyleValue) : null,
|
||||
2, expectedNumberOfArgs);
|
||||
return params;
|
||||
}
|
||||
};
|
||||
buildElementClassMapInstruction(valueConverter: ValueConverter): Instruction|null {
|
||||
if (this._classMapInput) {
|
||||
return this._buildMapBasedInstruction(valueConverter, true, this._classMapInput);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an instruction with all the expressions and parameters for `elementStyleMap`.
|
||||
*
|
||||
* The instruction data will contain all expressions for `elementStyleMap` to function
|
||||
* which includes the `[style]` expression params.
|
||||
*/
|
||||
buildElementStyleMapInstruction(valueConverter: ValueConverter): Instruction|null {
|
||||
if (this._styleMapInput) {
|
||||
return this._buildMapBasedInstruction(valueConverter, false, this._styleMapInput);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private _buildMapBasedInstruction(
|
||||
valueConverter: ValueConverter, isClassBased: boolean, stylingInput: BoundStylingEntry) {
|
||||
let totalBindingSlotsRequired = 0;
|
||||
|
||||
// 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
|
||||
// pipes can be picked up in time before the template is built
|
||||
const mapValue = stylingInput.value.visit(valueConverter);
|
||||
if (mapValue instanceof Interpolation) {
|
||||
totalBindingSlotsRequired += mapValue.expressions.length;
|
||||
}
|
||||
|
||||
const isHostBinding = this._directiveExpr;
|
||||
let reference: o.ExternalReference;
|
||||
if (isClassBased) {
|
||||
reference = isHostBinding ? R3.elementHostClassMap : R3.elementClassMap;
|
||||
} else {
|
||||
reference = isHostBinding ? R3.elementHostStyleMap : R3.elementStyleMap;
|
||||
}
|
||||
|
||||
return {
|
||||
sourceSpan: stylingInput.sourceSpan,
|
||||
reference,
|
||||
allocateBindingSlots: totalBindingSlotsRequired,
|
||||
buildParams: (convertFn: (value: any) => o.Expression) => {
|
||||
const params: o.Expression[] = [];
|
||||
if (!isHostBinding) {
|
||||
params.push(this._elementIndexExpr);
|
||||
}
|
||||
|
||||
params.push(convertFn(mapValue));
|
||||
return params;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private _buildSingleInputs(
|
||||
reference: o.ExternalReference, isHostBinding: boolean, inputs: BoundStylingEntry[],
|
||||
mapIndex: Map<string, number>, allowUnits: boolean,
|
||||
@ -498,9 +493,13 @@ export class StylingBuilder {
|
||||
buildUpdateLevelInstructions(valueConverter: ValueConverter) {
|
||||
const instructions: Instruction[] = [];
|
||||
if (this.hasBindings) {
|
||||
const mapInstruction = this.buildElementStylingMapInstruction(valueConverter);
|
||||
if (mapInstruction) {
|
||||
instructions.push(mapInstruction);
|
||||
const styleMapInstruction = this.buildElementStyleMapInstruction(valueConverter);
|
||||
if (styleMapInstruction) {
|
||||
instructions.push(styleMapInstruction);
|
||||
}
|
||||
const classMapInstruction = this.buildElementClassMapInstruction(valueConverter);
|
||||
if (classMapInstruction) {
|
||||
instructions.push(classMapInstruction);
|
||||
}
|
||||
instructions.push(...this._buildStyleInputs(valueConverter));
|
||||
instructions.push(...this._buildClassInputs(valueConverter));
|
||||
|
@ -686,8 +686,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
|
||||
// the code here will collect all update-level styling instructions and add them to the
|
||||
// update block of the template function AOT code. Instructions like `elementStyleProp`,
|
||||
// `elementStylingMap`, `elementClassProp` and `elementStylingApply` are all generated
|
||||
// and assign in the code below.
|
||||
// `elementStyleMap`, `elementClassMap`, `elementClassProp` and `elementStylingApply`
|
||||
// are all generated and assigned in the code below.
|
||||
stylingBuilder.buildUpdateLevelInstructions(this._valueConverter).forEach(instruction => {
|
||||
this._bindingSlots += instruction.allocateBindingSlots;
|
||||
this.processStylingInstruction(implicit, instruction, false);
|
||||
|
Reference in New Issue
Block a user