feat(ivy): provide support for map-based host bindings for [style] and [class] (#28246)

Up until now, `[style]` and `[class]` bindings (the map-based ones) have only
worked as template bindings and have not been supported at all inside of host
bindings. This patch ensures that multiple host binding sources (components and
directives) all properly assign style values and merge them correctly in terms
of priority.

Jira: FW-882

PR Close #28246
This commit is contained in:
Matias Niemelä
2019-02-08 15:03:54 -08:00
committed by Miško Hevery
parent e5861e1c79
commit fe8301c462
16 changed files with 3104 additions and 1714 deletions

File diff suppressed because it is too large Load Diff

View File

@ -26,17 +26,24 @@ export function createEmptyStylingContext(
element?: RElement | null, sanitizer?: StyleSanitizeFn | null,
initialStyles?: InitialStylingValues | null,
initialClasses?: InitialStylingValues | null): StylingContext {
return [
0, // MasterFlags
[null, -1, false, sanitizer || null], // DirectiveRefs
initialStyles || [null], // InitialStyles
initialClasses || [null], // InitialClasses
[0, 0], // SinglePropOffsets
element || null, // Element
null, // PreviousMultiClassValue
null, // PreviousMultiStyleValue
null, // PlayerContext
const context: StylingContext = [
0, // MasterFlags
[] as any, // DirectiveRefs (this gets filled below)
initialStyles || [null, null], // InitialStyles
initialClasses || [null, null], // InitialClasses
[0, 0], // SinglePropOffsets
element || null, // Element
[0], // CachedMultiClassValue
[0], // CachedMultiStyleValue
null, // PlayerContext
];
allocateDirectiveIntoContext(context, null);
return context;
}
export function allocateDirectiveIntoContext(context: StylingContext, directiveRef: any | null) {
// this is a new directive which we have not seen yet.
context[StylingIndex.DirectiveRegistryPosition].push(directiveRef, -1, false, null);
}
/**
@ -103,6 +110,34 @@ export function isAnimationProp(name: string): boolean {
return name[0] === ANIMATION_PROP_PREFIX;
}
export function hasClassInput(tNode: TNode) {
return (tNode.flags & TNodeFlags.hasClassInput) !== 0;
}
export function hasStyleInput(tNode: TNode) {
return (tNode.flags & TNodeFlags.hasStyleInput) !== 0;
}
export function forceClassesAsString(classes: string | {[key: string]: any} | null | undefined):
string {
if (classes && typeof classes !== 'string') {
classes = Object.keys(classes).join(' ');
}
return (classes as string) || '';
}
export function forceStylesAsString(styles: {[key: string]: any} | null | undefined): string {
let str = '';
if (styles) {
const props = Object.keys(styles);
for (let i = 0; i < props.length; i++) {
const prop = props[i];
str += (i ? ';' : '') + `${prop}:${styles[prop]}`;
}
}
return str;
}
export function addPlayerInternal(
playerContext: PlayerContext, rootContext: RootContext, element: HTMLElement,
player: Player | null, playerContextIndex: number, ref?: any): boolean {
@ -196,7 +231,3 @@ export function hasStyling(attrs: TAttributes): boolean {
}
return false;
}
export function hasClassInput(tNode: TNode) {
return tNode.flags & TNodeFlags.hasClassInput ? true : false;
}