mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-03-27 22:54:46 +08:00
Move color processing to JS
Reviewed By: @vjeux Differential Revision: D2346353
This commit is contained in:
committed by
facebook-github-bot-7
parent
6078a4f865
commit
9a2d05d9b2
@@ -40,30 +40,7 @@ var notMultiline = {
|
||||
onSubmitEditing: true,
|
||||
};
|
||||
|
||||
var AndroidTextInputAttributes = {
|
||||
autoCapitalize: true,
|
||||
autoCorrect: true,
|
||||
autoFocus: true,
|
||||
textAlign: true,
|
||||
textAlignVertical: true,
|
||||
keyboardType: true,
|
||||
mostRecentEventCount: true,
|
||||
multiline: true,
|
||||
numberOfLines: true,
|
||||
password: true,
|
||||
placeholder: true,
|
||||
placeholderTextColor: true,
|
||||
text: true,
|
||||
testID: true,
|
||||
underlineColorAndroid: true,
|
||||
editable : true,
|
||||
};
|
||||
|
||||
var viewConfigAndroid = {
|
||||
uiViewClassName: 'AndroidTextInput',
|
||||
validAttributes: AndroidTextInputAttributes,
|
||||
};
|
||||
|
||||
var AndroidTextInput = requireNativeComponent('AndroidTextInput', null);
|
||||
var RCTTextView = requireNativeComponent('RCTTextView', null);
|
||||
var RCTTextField = requireNativeComponent('RCTTextField', null);
|
||||
|
||||
@@ -317,7 +294,7 @@ var TextInput = React.createClass({
|
||||
mixins: [NativeMethodsMixin, TimerMixin],
|
||||
|
||||
viewConfig: ((Platform.OS === 'ios' ? RCTTextField.viewConfig :
|
||||
(Platform.OS === 'android' ? viewConfigAndroid : {})) : Object),
|
||||
(Platform.OS === 'android' ? AndroidTextInput.viewConfig : {})) : Object),
|
||||
|
||||
isFocused: function(): boolean {
|
||||
return TextInputState.currentlyFocusedField() ===
|
||||
@@ -578,9 +555,4 @@ var styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
var AndroidTextInput = createReactNativeComponentClass({
|
||||
validAttributes: AndroidTextInputAttributes,
|
||||
uiViewClassName: 'AndroidTextInput',
|
||||
});
|
||||
|
||||
module.exports = TextInput;
|
||||
|
||||
@@ -17,7 +17,7 @@ var React = require('React');
|
||||
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
||||
var ReactPropTypes = require('ReactPropTypes');
|
||||
|
||||
var createReactNativeComponentClass = require('createReactNativeComponentClass');
|
||||
var requireNativeComponent = require('requireNativeComponent');
|
||||
|
||||
/**
|
||||
* React component that wraps the Android-only [`Toolbar` widget][0]. A Toolbar can display a logo,
|
||||
@@ -166,9 +166,6 @@ var toolbarAttributes = {
|
||||
titleColor: true,
|
||||
};
|
||||
|
||||
var NativeToolbar = createReactNativeComponentClass({
|
||||
validAttributes: toolbarAttributes,
|
||||
uiViewClassName: 'ToolbarAndroid',
|
||||
});
|
||||
var NativeToolbar = requireNativeComponent('ToolbarAndroid', null);
|
||||
|
||||
module.exports = ToolbarAndroid;
|
||||
|
||||
@@ -21,6 +21,7 @@ var createReactNativeComponentClass = require('createReactNativeComponentClass')
|
||||
var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
|
||||
var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
|
||||
var onlyChild = require('onlyChild');
|
||||
var processColor = require('processColor');
|
||||
|
||||
var rippleBackgroundPropType = createStrictShapeTypeChecker({
|
||||
type: React.PropTypes.oneOf(['RippleAndroid']),
|
||||
@@ -112,7 +113,7 @@ var TouchableNativeFeedback = React.createClass({
|
||||
return {type: 'ThemeAttrAndroid', attribute: 'selectableItemBackgroundBorderless'};
|
||||
},
|
||||
Ripple: function(color, borderless) {
|
||||
return {type: 'RippleAndroid', color: color, borderless: borderless};
|
||||
return {type: 'RippleAndroid', color: processColor(color), borderless: borderless};
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -77,15 +77,34 @@ var NativeMethodsMixin = {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var style = precomputeStyle(flattenStyle(nativeProps.style));
|
||||
|
||||
var validAttributes = this.viewConfig.validAttributes;
|
||||
var hasProcessedProps = false;
|
||||
var processedProps = {};
|
||||
for (var key in nativeProps) {
|
||||
var process = validAttributes[key] && validAttributes[key].process;
|
||||
if (process) {
|
||||
hasProcessedProps = true;
|
||||
processedProps[key] = process(nativeProps[key]);
|
||||
}
|
||||
}
|
||||
|
||||
var style = precomputeStyle(
|
||||
flattenStyle(processedProps.style || nativeProps.style),
|
||||
this.viewConfig.validAttributes
|
||||
);
|
||||
|
||||
var props = null;
|
||||
if (hasOnlyStyle) {
|
||||
props = style;
|
||||
} else if (!style) {
|
||||
props = nativeProps;
|
||||
} else {
|
||||
props = mergeFast(nativeProps, style);
|
||||
props = nativeProps;
|
||||
if (hasProcessedProps) {
|
||||
props = mergeFast(props, processedProps);
|
||||
}
|
||||
if (style) {
|
||||
props = mergeFast(props, style);
|
||||
}
|
||||
}
|
||||
|
||||
RCTUIManager.updateView(
|
||||
|
||||
@@ -18,6 +18,7 @@ var createReactNativeComponentClass = require('createReactNativeComponentClass')
|
||||
var insetsDiffer = require('insetsDiffer');
|
||||
var pointsDiffer = require('pointsDiffer');
|
||||
var matricesDiffer = require('matricesDiffer');
|
||||
var processColor = require('processColor');
|
||||
var sizesDiffer = require('sizesDiffer');
|
||||
var verifyPropTypes = require('verifyPropTypes');
|
||||
var warning = require('warning');
|
||||
@@ -57,8 +58,22 @@ function requireNativeComponent(
|
||||
viewConfig.validAttributes = {};
|
||||
viewConfig.propTypes = componentInterface && componentInterface.propTypes;
|
||||
for (var key in nativeProps) {
|
||||
var useAttribute = false;
|
||||
var attribute = {};
|
||||
|
||||
var differ = TypeToDifferMap[nativeProps[key]];
|
||||
viewConfig.validAttributes[key] = differ ? {diff: differ} : true;
|
||||
if (differ) {
|
||||
attribute.diff = differ;
|
||||
useAttribute = true;
|
||||
}
|
||||
|
||||
var processor = TypeToProcessorMap[nativeProps[key]];
|
||||
if (processor) {
|
||||
attribute.process = processor;
|
||||
useAttribute = true;
|
||||
}
|
||||
|
||||
viewConfig.validAttributes[key] = useAttribute ? attribute : true;
|
||||
}
|
||||
if (__DEV__) {
|
||||
componentInterface && verifyPropTypes(
|
||||
@@ -80,4 +95,14 @@ var TypeToDifferMap = {
|
||||
// (not yet implemented)
|
||||
};
|
||||
|
||||
var TypeToProcessorMap = {
|
||||
// iOS Types
|
||||
CGColor: processColor,
|
||||
CGColorArray: processColor,
|
||||
UIColor: processColor,
|
||||
UIColorArray: processColor,
|
||||
// Android Types
|
||||
Color: processColor,
|
||||
};
|
||||
|
||||
module.exports = requireNativeComponent;
|
||||
|
||||
@@ -158,13 +158,23 @@ ReactNativeBaseComponent.Mixin = {
|
||||
validAttributes
|
||||
);
|
||||
|
||||
for (var key in updatePayload) {
|
||||
var process = validAttributes[key] && validAttributes[key].process;
|
||||
if (process) {
|
||||
updatePayload[key] = process(updatePayload[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// The style property is a deeply nested element which includes numbers
|
||||
// to represent static objects. Most of the time, it doesn't change across
|
||||
// renders, so it's faster to spend the time checking if it is different
|
||||
// before actually doing the expensive flattening operation in order to
|
||||
// compute the diff.
|
||||
if (styleDiffer(nextProps.style, prevProps.style)) {
|
||||
var nextFlattenedStyle = precomputeStyle(flattenStyle(nextProps.style));
|
||||
var nextFlattenedStyle = precomputeStyle(
|
||||
flattenStyle(nextProps.style),
|
||||
this.viewConfig.validAttributes
|
||||
);
|
||||
updatePayload = diffRawProperties(
|
||||
updatePayload,
|
||||
this.previousFlattenedStyle,
|
||||
|
||||
@@ -18,6 +18,7 @@ var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
var keyMirror = require('keyMirror');
|
||||
var matricesDiffer = require('matricesDiffer');
|
||||
var processColor = require('processColor');
|
||||
var sizesDiffer = require('sizesDiffer');
|
||||
|
||||
var ReactNativeStyleAttributes = {
|
||||
@@ -32,4 +33,16 @@ ReactNativeStyleAttributes.shadowOffset = { diff: sizesDiffer };
|
||||
// Do not rely on this attribute.
|
||||
ReactNativeStyleAttributes.decomposedMatrix = 'decomposedMatrix';
|
||||
|
||||
var colorAttributes = { process: processColor };
|
||||
ReactNativeStyleAttributes.backgroundColor = colorAttributes;
|
||||
ReactNativeStyleAttributes.borderBottomColor = colorAttributes;
|
||||
ReactNativeStyleAttributes.borderColor = colorAttributes;
|
||||
ReactNativeStyleAttributes.borderLeftColor = colorAttributes;
|
||||
ReactNativeStyleAttributes.borderRightColor = colorAttributes;
|
||||
ReactNativeStyleAttributes.borderTopColor = colorAttributes;
|
||||
ReactNativeStyleAttributes.color = colorAttributes;
|
||||
ReactNativeStyleAttributes.shadowColor = colorAttributes;
|
||||
ReactNativeStyleAttributes.textDecorationColor = colorAttributes;
|
||||
ReactNativeStyleAttributes.tintColor = colorAttributes;
|
||||
|
||||
module.exports = ReactNativeStyleAttributes;
|
||||
|
||||
118
Libraries/StyleSheet/__tests__/processColor-test.js
Normal file
118
Libraries/StyleSheet/__tests__/processColor-test.js
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
jest.autoMockOff();
|
||||
|
||||
var processColor = require('processColor');
|
||||
|
||||
describe('processColor', () => {
|
||||
|
||||
describe('predefined color names', () => {
|
||||
|
||||
it('should convert red', () => {
|
||||
var colorFromString = processColor('red');
|
||||
var expectedInt = 0xFFFF0000;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
it('should convert white', () => {
|
||||
var colorFromString = processColor('white');
|
||||
var expectedInt = 0xFFFFFFFF;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
it('should convert black', () => {
|
||||
var colorFromString = processColor('black');
|
||||
var expectedInt = 0xFF000000;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
it('should convert transparent', () => {
|
||||
var colorFromString = processColor('transparent');
|
||||
var expectedInt = 0x00000000;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RGB strings', () => {
|
||||
|
||||
it('should convert rgb(x, y, z)', () => {
|
||||
var colorFromString = processColor('rgb(10, 20, 30)');
|
||||
var expectedInt = 0xFF0A141E;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
it('should convert rgb x, y, z', () => {
|
||||
var colorFromString = processColor('rgb 10, 20, 30');
|
||||
var expectedInt = 0xFF0A141E;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('RGBA strings', () => {
|
||||
|
||||
it('should convert rgba(x, y, z, a)', () => {
|
||||
var colorFromString = processColor('rgba(10, 20, 30, 0.4)');
|
||||
var expectedInt = 0x660A141E;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
it('should convert rgba x, y, z, a', () => {
|
||||
var colorFromString = processColor('rgba 10, 20, 30, 0.4');
|
||||
var expectedInt = 0x660A141E;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('HSL strings', () => {
|
||||
|
||||
it('should convert hsl(x, y%, z%)', () => {
|
||||
var colorFromString = processColor('hsl(318, 69%, 55%)');
|
||||
var expectedInt = 0xFFDB3DAC;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
it('should convert hsl x, y%, z%', () => {
|
||||
var colorFromString = processColor('hsl 318, 69%, 55%');
|
||||
var expectedInt = 0xFFDB3DAC;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('HSL strings', () => {
|
||||
|
||||
it('should convert hsl(x, y%, z%)', () => {
|
||||
var colorFromString = processColor('hsla(318, 69%, 55%, 0.25)');
|
||||
var expectedInt = 0x40DB3DAC;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
it('should convert hsl x, y%, z%', () => {
|
||||
var colorFromString = processColor('hsla 318, 69%, 55%, 0.25');
|
||||
var expectedInt = 0x40DB3DAC;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('hex strings', () => {
|
||||
|
||||
it('should convert #xxxxxx', () => {
|
||||
var colorFromString = processColor('#1e83c9');
|
||||
var expectedInt = 0xFF1E83C9;
|
||||
expect(colorFromString).toEqual(expectedInt);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -12,6 +12,7 @@
|
||||
'use strict';
|
||||
|
||||
var MatrixMath = require('MatrixMath');
|
||||
var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
|
||||
var Platform = require('Platform');
|
||||
|
||||
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
|
||||
@@ -22,19 +23,57 @@ var stringifySafe = require('stringifySafe');
|
||||
* This method provides a hook where flattened styles may be precomputed or
|
||||
* otherwise prepared to become better input data for native code.
|
||||
*/
|
||||
function precomputeStyle(style: ?Object): ?Object {
|
||||
if (!style || !style.transform) {
|
||||
function precomputeStyle(style: ?Object, validAttributes: Object): ?Object {
|
||||
if (!style) {
|
||||
return style;
|
||||
}
|
||||
invariant(
|
||||
!style.transformMatrix,
|
||||
'transformMatrix and transform styles cannot be used on the same component'
|
||||
);
|
||||
var newStyle = _precomputeTransforms({...style});
|
||||
|
||||
var hasPreprocessKeys = false;
|
||||
for (var i = 0, keys = Object.keys(style); i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
if (_processor(key, validAttributes)) {
|
||||
hasPreprocessKeys = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPreprocessKeys && !style.transform) {
|
||||
return style;
|
||||
}
|
||||
|
||||
var newStyle = {...style};
|
||||
for (var i = 0, keys = Object.keys(style); i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var process = _processor(key, validAttributes);
|
||||
if (process) {
|
||||
newStyle[key] = process(newStyle[key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (style.transform) {
|
||||
invariant(
|
||||
!style.transformMatrix,
|
||||
'transformMatrix and transform styles cannot be used on the same component'
|
||||
);
|
||||
|
||||
newStyle = _precomputeTransforms(newStyle);
|
||||
}
|
||||
|
||||
deepFreezeAndThrowOnMutationInDev(newStyle);
|
||||
return newStyle;
|
||||
}
|
||||
|
||||
function _processor(key: string, validAttributes: Object) {
|
||||
var process = validAttributes[key] && validAttributes[key].process;
|
||||
if (!process) {
|
||||
process =
|
||||
ReactNativeStyleAttributes[key] &&
|
||||
ReactNativeStyleAttributes[key].process;
|
||||
}
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a transform matrix based on the provided transforms, and use that
|
||||
* within the style object instead.
|
||||
|
||||
26
Libraries/StyleSheet/processColor.js
Normal file
26
Libraries/StyleSheet/processColor.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule processColor
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var tinycolor = require('tinycolor2');
|
||||
|
||||
function processColor(color) {
|
||||
if (!color || typeof color === 'number') {
|
||||
return color;
|
||||
} else if (color instanceof Array) {
|
||||
return color.map(processColor);
|
||||
} else {
|
||||
var hexString = tinycolor(color).toHex8();
|
||||
return parseInt(hexString, 16);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = processColor;
|
||||
1
Libraries/react-native/react-native.js
vendored
1
Libraries/react-native/react-native.js
vendored
@@ -78,6 +78,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
|
||||
NativeAppEventEmitter: require('RCTNativeAppEventEmitter'),
|
||||
NativeModules: require('NativeModules'),
|
||||
Platform: require('Platform'),
|
||||
processColor: require('processColor'),
|
||||
requireNativeComponent: require('requireNativeComponent'),
|
||||
|
||||
// Prop Types
|
||||
|
||||
Reference in New Issue
Block a user