From c38369ac0ff930bd6e52f9cc0b3a40f3fb5f8eb6 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Sun, 30 Apr 2017 13:35:06 -0700 Subject: [PATCH] [fix] RTL style registration and resolution * Lazy-register RTL variants to generate class names * Don't RTL-flip translateX --- .../apis/PanResponder/PanResponderExample.js | 1 - src/apis/StyleSheet/StyleRegistry.js | 56 +++++++++++-------- .../__snapshots__/StyleRegistry-test.js.snap | 13 ++--- src/apis/StyleSheet/i18nStyle.js | 13 ----- 4 files changed, 40 insertions(+), 43 deletions(-) diff --git a/examples/apis/PanResponder/PanResponderExample.js b/examples/apis/PanResponder/PanResponderExample.js index 5d4f19a2..2b9bcc34 100644 --- a/examples/apis/PanResponder/PanResponderExample.js +++ b/examples/apis/PanResponder/PanResponderExample.js @@ -104,7 +104,6 @@ var styles = StyleSheet.create({ height: CIRCLE_SIZE, borderRadius: CIRCLE_SIZE / 2, position: 'absolute', - left: 0, top: 0, }, container: { diff --git a/src/apis/StyleSheet/StyleRegistry.js b/src/apis/StyleSheet/StyleRegistry.js index d8b780ef..42aa0ff8 100644 --- a/src/apis/StyleSheet/StyleRegistry.js +++ b/src/apis/StyleSheet/StyleRegistry.js @@ -7,13 +7,14 @@ import flattenArray from '../../modules/flattenArray'; import flattenStyle from './flattenStyle'; import I18nManager from '../I18nManager'; import i18nStyle from './i18nStyle'; -import mapKeyValue from '../../modules/mapKeyValue'; import { prefixInlineStyles } from '../../modules/prefixStyles'; import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry'; import StyleManager from './StyleManager'; +const emptyObject = {}; + const createCacheKey = id => { - const prefix = I18nManager.isRTL ? 'rtl' : 'ltr'; + const prefix = 'rn'; return `${prefix}-${id}`; }; @@ -21,7 +22,7 @@ const classListToString = list => list.join(' ').trim(); class StyleRegistry { constructor() { - this.cache = {}; + this.cache = { ltr: {}, rtl: {} }; this.styleManager = new StyleManager(); } @@ -34,30 +35,38 @@ class StyleRegistry { */ register(flatStyle) { const id = ReactNativePropRegistry.register(flatStyle); - const key = createCacheKey(id); - const style = createReactDOMStyle(i18nStyle(flatStyle)); - const classList = mapKeyValue(style, (prop, value) => { - if (value != null) { - return this.styleManager.setDeclaration(prop, value); - } - }); - const className = classList.join(' ').trim(); - this.cache[key] = { classList, className }; + this._registerById(id); return id; } + _registerById(id) { + const dir = I18nManager.isRTL ? 'rtl' : 'ltr'; + if (!this.cache[dir][id]) { + const style = flattenStyle(id); + const domStyle = createReactDOMStyle(i18nStyle(style)); + Object.keys(domStyle).forEach(styleProp => { + const value = domStyle[styleProp]; + if (value != null) { + this.styleManager.setDeclaration(styleProp, value); + } + }); + this.cache[dir][id] = true; + } + } + /** * Resolves a React Native style object to DOM attributes */ - resolve(reactNativeStyle, options) { + resolve(reactNativeStyle, options = emptyObject) { if (!reactNativeStyle) { return undefined; } // fast and cachable if (typeof reactNativeStyle === 'number') { + this._registerById(reactNativeStyle); const key = createCacheKey(reactNativeStyle); - return this._resolveStyleIfNeeded(reactNativeStyle, { key, ...options }); + return this._resolveStyleIfNeeded(reactNativeStyle, options, key); } // resolve a plain RN style object @@ -71,13 +80,15 @@ class StyleRegistry { const flatArray = flattenArray(reactNativeStyle); let isArrayOfNumbers = true; for (let i = 0; i < flatArray.length; i++) { - if (typeof flatArray[i] !== 'number') { + const id = flatArray[i]; + if (typeof id !== 'number') { isArrayOfNumbers = false; - break; + } else { + this._registerById(id); } } const key = isArrayOfNumbers ? createCacheKey(flatArray.join('-')) : null; - return this._resolveStyleIfNeeded(flatArray, { key, ...options }); + return this._resolveStyleIfNeeded(flatArray, options, key); } /** @@ -166,15 +177,16 @@ class StyleRegistry { /** * Caching layer over 'resolveStyle' */ - _resolveStyleIfNeeded(style, { key, ...rest }) { + _resolveStyleIfNeeded(style, options, key) { + const dir = I18nManager.isRTL ? 'rtl' : 'ltr'; if (key) { - if (!this.cache[key]) { + if (!this.cache[dir][key]) { // slow: convert style object to props and cache - this.cache[key] = this._resolveStyle(style, rest); + this.cache[dir][key] = this._resolveStyle(style, options); } - return this.cache[key]; + return this.cache[dir][key]; } - return this._resolveStyle(style, rest); + return this._resolveStyle(style, options); } } diff --git a/src/apis/StyleSheet/__tests__/__snapshots__/StyleRegistry-test.js.snap b/src/apis/StyleSheet/__tests__/__snapshots__/StyleRegistry-test.js.snap index 62fb7cf8..de475793 100644 --- a/src/apis/StyleSheet/__tests__/__snapshots__/StyleRegistry-test.js.snap +++ b/src/apis/StyleSheet/__tests__/__snapshots__/StyleRegistry-test.js.snap @@ -2,13 +2,12 @@ exports[`apis/StyleSheet/StyleRegistry resolve with register before RTL, resolves to className 1`] = ` Object { - "classList": Array [], - "className": "", - "style": Object { - "marginRight": "10px", - "right": "12.34%", - "textAlign": "right", - }, + "classList": Array [ + "rn-marginRight-zso239", + "rn-right-1bnbe1j", + "rn-textAlign-1ff274t", + ], + "className": "rn-marginRight-zso239 rn-right-1bnbe1j rn-textAlign-1ff274t", } `; diff --git a/src/apis/StyleSheet/i18nStyle.js b/src/apis/StyleSheet/i18nStyle.js index 21f773ad..7e2e06f1 100644 --- a/src/apis/StyleSheet/i18nStyle.js +++ b/src/apis/StyleSheet/i18nStyle.js @@ -43,17 +43,6 @@ const flipProperty = (prop: String): String => { return PROPERTIES_TO_SWAP.hasOwnProperty(prop) ? PROPERTIES_TO_SWAP[prop] : prop; }; -/** - * BiDi flip translateX - */ -const flipTransform = (transform: Object): Object => { - const translateX = transform.translateX; - if (translateX != null) { - transform.translateX = additiveInverse(translateX); - } - return transform; -}; - const swapLeftRight = (value: String): String => { return value === 'left' ? 'right' : value === 'right' ? 'left' : value; }; @@ -81,8 +70,6 @@ const i18nStyle = originalStyle => { } else if (prop === 'textShadowOffset') { 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]; }