199 lines
5.7 KiB
JavaScript
199 lines
5.7 KiB
JavaScript
|
/**
|
||
|
* Copyright (c) Nicolas Gallagher.
|
||
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||
|
import { MONOSPACE_FONT_STACK, SYSTEM_FONT_STACK, STYLE_SHORT_FORM_EXPANSIONS } from './constants';
|
||
|
import normalizeValueWithProperty from './normalizeValueWithProperty';
|
||
|
/**
|
||
|
* The browser implements the CSS cascade, where the order of properties is a
|
||
|
* factor in determining which styles to paint. React Native is different. It
|
||
|
* gives giving precedence to the more specific style property. For example,
|
||
|
* the value of `paddingTop` takes precedence over that of `padding`.
|
||
|
*
|
||
|
* This module creates mutally exclusive style declarations by expanding all of
|
||
|
* React Native's supported shortform properties (e.g. `padding`) to their
|
||
|
* longfrom equivalents.
|
||
|
*/
|
||
|
|
||
|
var emptyObject = {};
|
||
|
var supportsCSS3TextDecoration = !canUseDOM || window.CSS != null && window.CSS.supports != null && (window.CSS.supports('text-decoration-line', 'none') || window.CSS.supports('-webkit-text-decoration-line', 'none'));
|
||
|
/**
|
||
|
* Transform
|
||
|
*/
|
||
|
// { scale: 2 } => 'scale(2)'
|
||
|
// { translateX: 20 } => 'translateX(20px)'
|
||
|
|
||
|
var mapTransform = function mapTransform(transform) {
|
||
|
var type = Object.keys(transform)[0];
|
||
|
var value = normalizeValueWithProperty(transform[type], type);
|
||
|
return type + "(" + value + ")";
|
||
|
}; // [1,2,3,4,5,6] => 'matrix3d(1,2,3,4,5,6)'
|
||
|
|
||
|
|
||
|
var convertTransformMatrix = function convertTransformMatrix(transformMatrix) {
|
||
|
var matrix = transformMatrix.join(',');
|
||
|
return "matrix3d(" + matrix + ")";
|
||
|
};
|
||
|
|
||
|
var resolveTransform = function resolveTransform(resolvedStyle, style) {
|
||
|
var transform = style.transform;
|
||
|
|
||
|
if (Array.isArray(style.transform)) {
|
||
|
transform = style.transform.map(mapTransform).join(' ');
|
||
|
} else if (style.transformMatrix) {
|
||
|
transform = convertTransformMatrix(style.transformMatrix);
|
||
|
}
|
||
|
|
||
|
resolvedStyle.transform = transform;
|
||
|
};
|
||
|
/**
|
||
|
* Reducer
|
||
|
*/
|
||
|
|
||
|
|
||
|
var createReactDOMStyle = function createReactDOMStyle(style) {
|
||
|
if (!style) {
|
||
|
return emptyObject;
|
||
|
}
|
||
|
|
||
|
var resolvedStyle = {};
|
||
|
Object.keys(style).sort().forEach(function (prop) {
|
||
|
var value = normalizeValueWithProperty(style[prop], prop); // Ignore everything else with a null value
|
||
|
|
||
|
if (value == null) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
switch (prop) {
|
||
|
// Ignore some React Native styles
|
||
|
case 'aspectRatio':
|
||
|
case 'elevation':
|
||
|
case 'overlayColor':
|
||
|
case 'resizeMode':
|
||
|
case 'tintColor':
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
// TODO: remove once this issue is fixed
|
||
|
// https://github.com/rofrischmann/inline-style-prefixer/issues/159
|
||
|
|
||
|
case 'backgroundClip':
|
||
|
{
|
||
|
if (value === 'text') {
|
||
|
resolvedStyle.backgroundClip = value;
|
||
|
resolvedStyle.WebkitBackgroundClip = value;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
// The 'flex' property value in React Native must be a positive integer,
|
||
|
// 0, or -1.
|
||
|
|
||
|
case 'flex':
|
||
|
{
|
||
|
if (value > 0) {
|
||
|
resolvedStyle.flexGrow = value;
|
||
|
resolvedStyle.flexShrink = 1;
|
||
|
resolvedStyle.flexBasis = '0%';
|
||
|
} else if (value === 0) {
|
||
|
resolvedStyle.flexGrow = 0;
|
||
|
resolvedStyle.flexShrink = 0;
|
||
|
resolvedStyle.flexBasis = '0%';
|
||
|
} else if (value === -1) {
|
||
|
resolvedStyle.flexGrow = 0;
|
||
|
resolvedStyle.flexShrink = 1;
|
||
|
resolvedStyle.flexBasis = 'auto';
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'font':
|
||
|
{
|
||
|
resolvedStyle[prop] = value.replace('System', SYSTEM_FONT_STACK);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'fontFamily':
|
||
|
{
|
||
|
if (value.indexOf('System') > -1) {
|
||
|
var stack = value.split(/,\s*/);
|
||
|
stack[stack.indexOf('System')] = SYSTEM_FONT_STACK;
|
||
|
resolvedStyle[prop] = stack.join(',');
|
||
|
} else if (value === 'monospace') {
|
||
|
resolvedStyle[prop] = MONOSPACE_FONT_STACK;
|
||
|
} else {
|
||
|
resolvedStyle[prop] = value;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'fontVariant':
|
||
|
{
|
||
|
if (Array.isArray(value) && value.length > 0) {
|
||
|
resolvedStyle.fontVariant = value.join(' ');
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'textAlignVertical':
|
||
|
{
|
||
|
resolvedStyle.verticalAlign = value === 'center' ? 'middle' : value;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'textDecorationLine':
|
||
|
{
|
||
|
// use 'text-decoration' for browsers that only support CSS2
|
||
|
// text-decoration (e.g., IE, Edge)
|
||
|
if (!supportsCSS3TextDecoration) {
|
||
|
resolvedStyle.textDecoration = value;
|
||
|
} else {
|
||
|
resolvedStyle.textDecorationLine = value;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'transform':
|
||
|
case 'transformMatrix':
|
||
|
{
|
||
|
resolveTransform(resolvedStyle, style);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'writingDirection':
|
||
|
{
|
||
|
resolvedStyle.direction = value;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
var longFormProperties = STYLE_SHORT_FORM_EXPANSIONS[prop];
|
||
|
|
||
|
if (longFormProperties) {
|
||
|
longFormProperties.forEach(function (longForm, i) {
|
||
|
// The value of any longform property in the original styles takes
|
||
|
// precedence over the shortform's value.
|
||
|
if (typeof style[longForm] === 'undefined') {
|
||
|
resolvedStyle[longForm] = value;
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
resolvedStyle[prop] = Array.isArray(value) ? value.join(',') : value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
return resolvedStyle;
|
||
|
};
|
||
|
|
||
|
export default createReactDOMStyle;
|