Compare commits

...

8 Commits

Author SHA1 Message Date
Nicolas Gallagher
5f69c8e8b8 0.0.92 2017-04-29 12:19:16 -07:00
Nicolas Gallagher
21550db5f2 [fix] stop propagation of ScrollView 'onScroll' event
Fix #440
2017-04-29 12:15:19 -07:00
Nicolas Gallagher
1cae5d55a1 [fix] setNativeProps DOM style copying
The 'style' object of an HTML node is a 'CSSStyleDeclaration'. Use the
'CSSStyleDeclaration' API to copy the inline styles, rather than
treating it like a plain object. This avoids errors that were resulting
from indices and property names being used a key-value pairs in the
resulting style copy.

Fix #460
Ref #454
2017-04-29 11:09:43 -07:00
Nicolas Gallagher
11d23f850a 0.0.91 2017-04-28 15:40:12 -07:00
Nicolas Gallagher
d994a25017 0.0.90 2017-04-28 15:17:44 -07:00
Nicolas Gallagher
756df70154 [fix] check 'transform' style is array before mapping 2017-04-28 15:15:57 -07:00
Nicolas Gallagher
f0b06419f9 Move prefixStyles module 2017-04-27 16:27:45 -07:00
Nicolas Gallagher
60ff75705e [fix] remove stray 'length' property from style object
Fix #454
2017-04-27 15:10:03 -07:00
11 changed files with 53 additions and 39 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "react-native-web",
"version": "0.0.89",
"version": "0.0.92",
"description": "React Native for Web",
"main": "dist/index.js",
"files": [

View File

@@ -7,12 +7,10 @@ import flattenArray from '../../modules/flattenArray';
import flattenStyle from './flattenStyle';
import I18nManager from '../I18nManager';
import mapKeyValue from '../../modules/mapKeyValue';
import prefixInlineStyles from './prefixInlineStyles';
import { prefixInlineStyles } from '../../modules/prefixStyles';
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
import StyleManager from './StyleManager';
const vendorPrefixPattern = /^(webkit|moz|ms)/;
const createCacheKey = id => {
const prefix = I18nManager.isRTL ? 'rtl' : 'ltr';
return `${prefix}-${id}`;
@@ -88,10 +86,10 @@ class StyleRegistry {
* To determine the next style, some of the existing DOM state must be
* converted back into React Native styles.
*/
resolveStateful(rnStyleNext, { classList: domClassList, style: domStyle }) {
resolveStateful(rnStyleNext, { classList: rdomClassList, style: rdomStyle }) {
// Convert the DOM classList back into a React Native form
// Preserves unrecognized class names.
const { classList: rnClassList, style: rnStyle } = domClassList.reduce(
const { classList: rnClassList, style: rnStyle } = rdomClassList.reduce(
(styleProps, className) => {
const { prop, value } = this.styleManager.getDeclaration(className);
if (prop) {
@@ -104,24 +102,12 @@ class StyleRegistry {
{ classList: [], style: {} }
);
// DOM style may include vendor prefixes and properties set by other libraries.
// Preserve it but transform back into React DOM style.
const rdomStyle = Object.keys(domStyle).reduce((acc, styleName) => {
const value = domStyle[styleName];
if (value !== '') {
const reactStyleName = vendorPrefixPattern.test(styleName)
? styleName.charAt(0).toUpperCase() + styleName.slice(1)
: styleName;
acc[reactStyleName] = value;
}
return acc;
}, {});
// Create next DOM style props from current and next RN styles
const { classList: rdomClassListNext, style: rdomStyleNext } = this.resolve([
rnStyle,
rnStyleNext
]);
// Next class names take priority over current inline styles
const style = { ...rdomStyle };
rdomClassListNext.forEach(className => {
@@ -130,8 +116,10 @@ class StyleRegistry {
style[prop] = '';
}
});
// Next inline styles take priority over current inline styles
Object.assign(style, rdomStyleNext);
// Add the current class names not managed by React Native
const className = classListToString(rdomClassListNext.concat(rnClassList));

View File

@@ -82,7 +82,7 @@ describe('apis/StyleSheet/StyleRegistry', () => {
// note: this also checks for correctly uppercasing the first letter of DOM vendor prefixes
const domStyleProps = {
classList: [],
style: { opacity: 0.5, webkitTransform: 'scale(1)', transform: 'scale(1)' }
style: { opacity: 0.5, WebkitTransform: 'scale(1)', transform: 'scale(1)' }
};
const domStyleNextProps = styleRegistry.resolveStateful(
{ opacity: 1, transform: [{ scale: 2 }] },

View File

@@ -3,7 +3,18 @@
import resolveTransform from '../resolveTransform';
describe('apis/StyleSheet/resolveTransform', () => {
test('transform', () => {
// passthrough if transform value is ever a string
test('transform string', () => {
const resolvedStyle = {};
const transform = 'perspective(50px) scaleX(20) translateX(20px) rotate(20deg)';
const style = { transform };
resolveTransform(resolvedStyle, style);
expect(resolvedStyle).toEqual({ transform });
});
test('transform array', () => {
const resolvedStyle = {};
const style = {
transform: [{ perspective: 50 }, { scaleX: 20 }, { translateX: 20 }, { rotate: '20deg' }]

View File

@@ -1,7 +1,7 @@
import hyphenateStyleName from 'hyphenate-style-name';
import mapKeyValue from '../../modules/mapKeyValue';
import normalizeValue from './normalizeValue';
import prefixAll from 'inline-style-prefixer/static';
import prefixStyles from '../../modules/prefixStyles';
const createDeclarationString = (prop, val) => {
const name = hyphenateStyleName(prop);
@@ -19,6 +19,6 @@ const createDeclarationString = (prop, val) => {
* // => 'color:blue;width:20px'
*/
const generateCss = style =>
mapKeyValue(prefixAll(style), createDeclarationString).sort().join(';');
mapKeyValue(prefixStyles(style), createDeclarationString).sort().join(';');
module.exports = generateCss;

View File

@@ -71,15 +71,17 @@ const i18nStyle = originalStyle => {
continue;
}
const value = style[prop];
if (PROPERTIES_TO_SWAP[prop]) {
const newProp = flipProperty(prop);
nextStyle[newProp] = style[prop];
nextStyle[newProp] = value;
} else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
nextStyle[prop] = swapLeftRight(style[prop]);
nextStyle[prop] = swapLeftRight(value);
} else if (prop === 'textShadowOffset') {
nextStyle[prop] = style[prop];
nextStyle[prop].width = additiveInverse(style[prop].width);
} else if (prop === 'transform') {
nextStyle[prop] = value;
nextStyle[prop].width = additiveInverse(value.width);
} else if (prop === 'transform' && Array.isArray(value)) {
nextStyle[prop] = style[prop].map(flipTransform);
} else {
nextStyle[prop] = style[prop];

View File

@@ -15,13 +15,13 @@ const convertTransformMatrix = transformMatrix => {
};
const resolveTransform = (resolvedStyle, style) => {
let transform = style.transform;
if (Array.isArray(style.transform)) {
const transform = style.transform.map(mapTransform).join(' ');
resolvedStyle.transform = transform;
transform = style.transform.map(mapTransform).join(' ');
} else if (style.transformMatrix) {
const transform = convertTransformMatrix(style.transformMatrix);
resolvedStyle.transform = transform;
transform = convertTransformMatrix(style.transformMatrix);
}
resolvedStyle.transform = transform;
};
module.exports = resolveTransform;

View File

@@ -87,6 +87,7 @@ export default class ScrollViewBase extends Component {
_handleScroll = e => {
e.persist();
e.stopPropagation();
const { scrollEventThrottle } = this.props;
// A scroll happened, so the scroll bumps the debounce.
this._debouncedOnScrollEnd(e);

View File

@@ -11,6 +11,9 @@ import findNodeHandle from '../findNodeHandle';
import StyleRegistry from '../../apis/StyleSheet/registry';
import UIManager from '../../apis/UIManager';
const hyphenPattern = /-([a-z])/g;
const toCamelCase = str => str.replace(hyphenPattern, m => m[1].toUpperCase());
const NativeMethodsMixin = {
/**
* Removes focus from an input or view. This is the opposite of `focus()`.
@@ -69,8 +72,17 @@ const NativeMethodsMixin = {
setNativeProps(nativeProps: Object) {
// Copy of existing DOM state
const node = findNodeHandle(this);
const nodeStyle = node.style;
const classList = Array.prototype.slice.call(node.classList);
const style = { ...node.style };
const style = {};
// DOM style is a CSSStyleDeclaration
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration
for (let i = node.style.length; i > 0; i -= 1) {
const property = nodeStyle.item(i);
// DOM style uses hyphenated prop names and may include vendor prefixes
// Transform back into React DOM style.
style[toCamelCase(property)] = nodeStyle.getPropertyValue(property);
}
const domStyleProps = { classList, style };
// Next DOM state

View File

@@ -1,9 +1,9 @@
/* eslint-env jasmine, jest */
import prefixInlineStyles from '../prefixInlineStyles';
import { prefixInlineStyles } from '..';
describe('apis/StyleSheet/prefixInlineStyles', () => {
test('handles array values', () => {
describe('modules/prefixStyles', () => {
test('handles array values for inline styles', () => {
const style = {
display: ['-webkit-flex', 'flex']
};

View File

@@ -1,6 +1,8 @@
import prefixAll from 'inline-style-prefixer/static';
const prefixInlineStyles = style => {
export default prefixAll;
export const prefixInlineStyles = style => {
const prefixedStyles = prefixAll(style);
// React@15 removed undocumented support for fallback values in
@@ -14,5 +16,3 @@ const prefixInlineStyles = style => {
return prefixedStyles;
};
module.exports = prefixInlineStyles;