feat: implement css-variables and css-calc (#7553)

* feat: implement basic support for css-variables

* fix(test): test-watch-android and test-watch-ios was broken

* fix: processing css-variables belong in CssProperty-classes

Not in the StyleScope.

* fix(css-variables): set style attribute override value from css-classes

* feat: add css calc-support using 'reduce-css-calc'

* fix(tslint): missing semicolon and incorrect quotemark

* feat: move css-variable handling to Style-class

* chor: add comments explaining css-variable implmentation

* chor: set css-variables before other style properties

* chor(css-variables): cleaning up

* chor: code style fixes

* test(CSS-CALC): Add tests for nested css-calc statements

* fix(CSS-CALC): dip-unit not supported by reduce-css-calc

* fix(tslint): use double quotemarks

* test(css-calc): test _cssCalcConverter directly

* chor(css-variables): rename and clean up _cssVariableConverter to _evaluateCssVariable

* chor: rename varname to varName for consistency

* chor: support css-calc and variables for normal properties

* chor: use string.replace to evaluate css-variables

* fix: Missing blank line before return

* chor: rename css-calc functions

* fix: undefined css-variables treated as 'unset'

* fix(tslint): use double quotemarks

* feat(css-variable): handle fallback values

* chor(css-variables): handle unsetValue

* chor: process css-calc and css-variables in style-scope

* chore: clean-up css-calc/variable expressions

* fix(css-calc): handle invalid expressions

* chore(CSSState): update comments

* chore(Style): rename css-variable functions

* chore(css-variables): describe fallback logic

* chore: move reset scoped css-variables to Style-class

* chore(CssState): simplify check for css expressions

* chore: add reduce-css-calc to /package.json
This commit is contained in:
Morten Sjøgren
2019-08-19 23:56:56 +02:00
committed by Svetoslav
parent 0adcb64cc3
commit 673c8087e0
8 changed files with 651 additions and 14 deletions

View File

@@ -144,6 +144,10 @@ export function makeParser<T>(isValid: (value: any) => boolean): (value: any) =>
export function getSetProperties(view: ViewBase): [string, any][];
export function getComputedCssValues(view: ViewBase): [string, any][];
export function isCssVariable(property: string): boolean;
export function isCssCalcExpression(value: string): boolean;
export function isCssVariableExpression(value: string): boolean;
//@private
/**
* @private get all properties defined on ViewBase
@@ -154,4 +158,8 @@ export function _getProperties(): Property<any, any>[];
* @private get all properties defined on Style
*/
export function _getStyleProperties(): CssProperty<any, any>[];
export function _evaluateCssVariableExpression(view: ViewBase, cssName: string, value: string): string;
export function _evaluateCssCalcExpression(value: string): string;
//@endprivate

View File

@@ -1,3 +1,5 @@
import reduceCSSCalc from "reduce-css-calc";
// Definitions.
import * as definitions from "../view-base";
import { ViewBase } from "../view-base";
@@ -56,6 +58,76 @@ export function _getStyleProperties(): CssProperty<any, any>[] {
return getPropertiesFromMap(cssSymbolPropertyMap) as CssProperty<any, any>[];
}
const cssVariableExpressionRegexp = /\bvar\(\s*(--[^,\s]+?)(?:\s*,\s*(.+))?\s*\)/;
const cssVariableAllExpressionsRegexp = /\bvar\(\s*(--[^,\s]+?)(?:\s*,\s*(.+))?\s*\)/g;
export function isCssVariable(property: string) {
return /^--[^,\s]+?$/.test(property);
}
export function isCssCalcExpression(value: string) {
return /\bcalc\(/.test(value);
}
export function isCssVariableExpression(value: string) {
return cssVariableExpressionRegexp.test(value);
}
export function _evaluateCssVariableExpression(view: ViewBase, cssName: string, value: string): string {
if (typeof value !== "string") {
return value;
}
if (!isCssVariableExpression(value)) {
// Value is not using css-variable(s)
return value;
}
let output = value.trim();
// Evaluate every (and nested) css-variables in the value.
let lastValue: string;
while (lastValue !== output) {
lastValue = output;
output = output.replace(cssVariableAllExpressionsRegexp, (matchStr, cssVariableName: string, fallbackStr: string) => {
const cssVariableValue = view.style.getCssVariable(cssVariableName);
if (cssVariableValue !== null) {
return cssVariableValue;
}
if (fallbackStr) {
// css-variable not found, using fallback-string.
const fallbackOutput = _evaluateCssVariableExpression(view, cssName, fallbackStr);
if (fallbackOutput) {
// If the fallback have multiple values, return the first of them.
return fallbackOutput.split(",")[0];
}
}
// Couldn't find a value for the css-variable or the fallback, return "unset"
traceWrite(`Failed to get value for css-variable "${cssVariableName}" used in "${cssName}"=[${value}] to ${view}`, traceCategories.Style, traceMessageType.error);
return "unset";
});
}
return output;
}
export function _evaluateCssCalcExpression(value: string) {
if (typeof value !== "string") {
return value;
}
if (isCssCalcExpression(value)) {
// WORKAROUND: reduce-css-calc can't handle the dip-unit.
return reduceCSSCalc(value.replace(/([0-9]+(\.[0-9]+)?)dip\b/g, "$1"));
} else {
return value;
}
}
function getPropertiesFromMap(map): Property<any, any>[] | CssProperty<any, any>[] {
const props = [];
Object.getOwnPropertySymbols(map).forEach(symbol => props.push(map[symbol]));