diff --git a/docs/components/Text.md b/docs/components/Text.md
index 06cd3631..b8f65e2a 100644
--- a/docs/components/Text.md
+++ b/docs/components/Text.md
@@ -68,22 +68,19 @@ Lets the user select the text.
+ `fontWeight`
+ `letterSpacing`
+ `lineHeight`
-+ `textAlign`‡
++ `textAlign`
+ `textAlignVertical`
+ `textDecorationLine`
+ `textOverflow`
+ `textRendering`
+ `textShadowColor`
-+ `textShadowOffset`‡
++ `textShadowOffset`
+ `textShadowRadius`
+ `textTransform`
+ `unicodeBidi`
+ `whiteSpace`
+ `wordWrap`
-+ `writingDirection`‡
-
-‡ This property can be suffixed with `$noI18n` to prevent automatic
-bidi-flipping in RTL mode. This is only supported if `Platform.OS === 'web'`.
++ `writingDirection`
**testID**: string
diff --git a/docs/components/View.md b/docs/components/View.md
index 94ce9443..28c6a896 100644
--- a/docs/components/View.md
+++ b/docs/components/View.md
@@ -119,22 +119,22 @@ from `style`.
+ `borderColor` (single value)
+ `borderTopColor`
+ `borderBottomColor`
-+ `borderRightColor`‡
-+ `borderLeftColor`‡
++ `borderRightColor`
++ `borderLeftColor`
+ `borderRadius` (single value)
-+ `borderTopLeftRadius`‡
-+ `borderTopRightRadius`‡
-+ `borderBottomLeftRadius`‡
-+ `borderBottomRightRadius`‡
++ `borderTopLeftRadius`
++ `borderTopRightRadius`
++ `borderBottomLeftRadius`
++ `borderBottomRightRadius`
+ `borderStyle` (single value)
+ `borderTopStyle`
-+ `borderRightStyle`‡
++ `borderRightStyle`
+ `borderBottomStyle`
-+ `borderLeftStyle`‡
++ `borderLeftStyle`
+ `borderWidth` (single value)
+ `borderBottomWidth`
-+ `borderLeftWidth`‡
-+ `borderRightWidth`‡
++ `borderLeftWidth`
++ `borderRightWidth`
+ `borderTopWidth`
+ `bottom`
+ `boxShadow`
@@ -148,12 +148,12 @@ from `style`.
+ `flexWrap`
+ `height`
+ `justifyContent`
-+ `left`‡
++ `left`
+ `margin` (single value)
+ `marginBottom`
+ `marginHorizontal`
-+ `marginLeft`‡
-+ `marginRight`‡
++ `marginLeft`
++ `marginRight`
+ `marginTop`
+ `marginVertical`
+ `maxHeight`
@@ -168,14 +168,14 @@ from `style`.
+ `padding` (single value)
+ `paddingBottom`
+ `paddingHorizontal`
-+ `paddingLeft`‡
-+ `paddingRight`‡
++ `paddingLeft`
++ `paddingRight`
+ `paddingTop`
+ `paddingVertical`
+ `perspective`
+ `perspectiveOrigin`
+ `position`
-+ `right`‡
++ `right`
+ `top`
+ `transform`
+ `transformOrigin`
@@ -188,9 +188,6 @@ from `style`.
+ `width`
+ `zIndex`
-‡ This property can be suffixed with `$noI18n` to prevent automatic
-bidi-flipping in RTL mode. This is only supported if `Platform.OS === 'web'`.
-
Default:
```js
diff --git a/docs/guides/internationalization.md b/docs/guides/internationalization.md
index b7b511c7..2a7eee13 100644
--- a/docs/guides/internationalization.md
+++ b/docs/guides/internationalization.md
@@ -4,11 +4,6 @@ To support right-to-left languages, application layout can be automatically
flipped from LTR to RTL. The `I18nManager` API can be used to help with more
fine-grained control and testing of RTL layouts.
-React Native for Web provides an experimental feature to support "true left"
-and "true right" styles. For example, `left` will be flipped to `right` in RTL
-mode, but `left$noI18n` will not. More information is available in the `Text`
-and `View` documentation.
-
## Working with icons and images
Icons and images that must match the LTR or RTL layout of the app need to be manually flipped.
diff --git a/examples/apis/I18nManager/I18nManagerExample.js b/examples/apis/I18nManager/I18nManagerExample.js
index b14348a7..c0cdc5a7 100644
--- a/examples/apis/I18nManager/I18nManagerExample.js
+++ b/examples/apis/I18nManager/I18nManagerExample.js
@@ -14,14 +14,22 @@ class I18nManagerExample extends Component {
LTR/RTL layout example!
- This is sample text. The writing direction can be changed by pressing the button below.
-
-
- This is text that will always display LTR.
+ The writing direction of text is automatically determined by the browser, independent of the global writing direction of the app.
- This is text that will always display RTL.
+ أحب اللغة العربية
+
+ textAlign toggles
+
+
+
+ One
+
+
+ Two
+
+
{
- this._isRTL = !this._isRTL
- I18nManager.setPreferredLanguageRTL(this._isRTL)
+ I18nManager.setPreferredLanguageRTL(!I18nManager.isRTL)
+ this.forceUpdate();
}
}
@@ -55,13 +63,16 @@ const styles = StyleSheet.create({
fontSize: 18,
marginBottom: 5
},
- ltrText: {
- textAlign$noI18n: 'left',
- writingDirection$noI18n: 'ltr'
+ textAlign: {
+ textAlign: 'left'
},
- rtlText: {
- textAlign$noI18n: 'right',
- writingDirection$noI18n: 'rtl'
+ horizontal: {
+ flexDirection: 'row',
+ marginVertical: 10
+ },
+ box: {
+ borderWidth: 1,
+ flex: 1
},
toggle: {
alignSelf: 'center',
diff --git a/examples/components/Text/TextExample.js b/examples/components/Text/TextExample.js
index 9259cfa8..b43826b9 100644
--- a/examples/components/Text/TextExample.js
+++ b/examples/components/Text/TextExample.js
@@ -271,7 +271,7 @@ const examples = [
auto (default) - english LTR
-
+
أحب اللغة العربية auto (default) - arabic RTL
diff --git a/src/apis/StyleSheet/__tests__/__snapshots__/i18nStyle-test.js.snap b/src/apis/StyleSheet/__tests__/__snapshots__/i18nStyle-test.js.snap
index 52be129b..2f1ea7e6 100644
--- a/src/apis/StyleSheet/__tests__/__snapshots__/i18nStyle-test.js.snap
+++ b/src/apis/StyleSheet/__tests__/__snapshots__/i18nStyle-test.js.snap
@@ -25,33 +25,6 @@ Object {
}
`;
-exports[`apis/StyleSheet/i18nStyle LTR mode normalizes properties 1`] = `
-Object {
- "borderBottomLeftRadius": 20,
- "borderBottomRightRadius": "2rem",
- "borderLeftColor": "red",
- "borderLeftStyle": "solid",
- "borderLeftWidth": 5,
- "borderRightColor": "blue",
- "borderRightStyle": "dotted",
- "borderRightWidth": 6,
- "borderTopLeftRadius": 10,
- "borderTopRightRadius": "1rem",
- "left": 1,
- "marginLeft": 7,
- "marginRight": 8,
- "paddingLeft": 9,
- "paddingRight": 10,
- "right": 2,
- "textAlign": "left",
- "textShadowOffset": Object {
- "height": 10,
- "width": "1rem",
- },
- "writingDirection": "ltr",
-}
-`;
-
exports[`apis/StyleSheet/i18nStyle RTL mode does auto-flip 1`] = `
Object {
"borderBottomLeftRadius": "2rem",
@@ -78,30 +51,3 @@ Object {
"writingDirection": "rtl",
}
`;
-
-exports[`apis/StyleSheet/i18nStyle RTL mode normalizes properties 1`] = `
-Object {
- "borderBottomLeftRadius": 20,
- "borderBottomRightRadius": "2rem",
- "borderLeftColor": "red",
- "borderLeftStyle": "solid",
- "borderLeftWidth": 5,
- "borderRightColor": "blue",
- "borderRightStyle": "dotted",
- "borderRightWidth": 6,
- "borderTopLeftRadius": 10,
- "borderTopRightRadius": "1rem",
- "left": 1,
- "marginLeft": 7,
- "marginRight": 8,
- "paddingLeft": 9,
- "paddingRight": 10,
- "right": 2,
- "textAlign": "left",
- "textShadowOffset": Object {
- "height": 10,
- "width": "-1rem",
- },
- "writingDirection": "ltr",
-}
-`;
diff --git a/src/apis/StyleSheet/__tests__/i18nStyle-test.js b/src/apis/StyleSheet/__tests__/i18nStyle-test.js
index 5350f84d..81a53a4e 100644
--- a/src/apis/StyleSheet/__tests__/i18nStyle-test.js
+++ b/src/apis/StyleSheet/__tests__/i18nStyle-test.js
@@ -21,16 +21,9 @@ const style = {
paddingRight: 10,
right: 2,
textAlign: 'left',
- textShadowOffset: { width: '1rem', height: 10 },
- writingDirection: 'ltr'
+ textShadowOffset: { width: '1rem', height: 10 }
};
-const styleNoI18n = Object.keys(style).reduce((acc, prop) => {
- const newProp = `${prop}$noI18n`;
- acc[newProp] = style[prop];
- return acc;
-}, {});
-
describe('apis/StyleSheet/i18nStyle', () => {
describe('LTR mode', () => {
beforeEach(() => {
@@ -44,9 +37,6 @@ describe('apis/StyleSheet/i18nStyle', () => {
test('does not auto-flip', () => {
expect(i18nStyle(style)).toMatchSnapshot();
});
- test('normalizes properties', () => {
- expect(i18nStyle(styleNoI18n)).toMatchSnapshot();
- });
});
describe('RTL mode', () => {
@@ -61,8 +51,5 @@ describe('apis/StyleSheet/i18nStyle', () => {
test('does auto-flip', () => {
expect(i18nStyle(style)).toMatchSnapshot();
});
- test('normalizes properties', () => {
- expect(i18nStyle(styleNoI18n)).toMatchSnapshot();
- });
});
});
diff --git a/src/apis/StyleSheet/expandStyle.js b/src/apis/StyleSheet/expandStyle.js
index 9e628ccb..5ffa8ba3 100644
--- a/src/apis/StyleSheet/expandStyle.js
+++ b/src/apis/StyleSheet/expandStyle.js
@@ -37,14 +37,11 @@ const alphaSortProps = (propsArray) => propsArray.sort((a, b) => {
return 0;
});
-const expandStyle = (style) => {
- if (!style) { return emptyObject; }
- const styleProps = Object.keys(style);
- const sortedStyleProps = alphaSortProps(styleProps);
+const createReducer = (style, styleProps) => {
let hasResolvedBoxShadow = false;
let hasResolvedTextShadow = false;
- const reducer = (resolvedStyle, prop) => {
+ return (resolvedStyle, prop) => {
const value = normalizeValue(prop, style[prop]);
if (value == null) { return resolvedStyle; }
@@ -105,7 +102,13 @@ const expandStyle = (style) => {
return resolvedStyle;
};
+};
+const expandStyle = (style) => {
+ if (!style) { return emptyObject; }
+ const styleProps = Object.keys(style);
+ const sortedStyleProps = alphaSortProps(styleProps);
+ const reducer = createReducer(style, styleProps);
const resolvedStyle = sortedStyleProps.reduce(reducer, {});
return resolvedStyle;
};
diff --git a/src/apis/StyleSheet/i18nStyle.js b/src/apis/StyleSheet/i18nStyle.js
index af57184d..dc8cb679 100644
--- a/src/apis/StyleSheet/i18nStyle.js
+++ b/src/apis/StyleSheet/i18nStyle.js
@@ -31,10 +31,6 @@ const PROPERTIES_SWAP_LEFT_RIGHT = {
'textAlign': true
};
-const PROPERTIES_SWAP_LTR_RTL = {
- 'writingDirection': true
-};
-
/**
* Invert the sign of a numeric-like value
*/
@@ -43,7 +39,7 @@ const additiveInverse = (value: String | Number) => multiplyStyleLengthValue(val
/**
* BiDi flip the given property.
*/
-const flipProperty = (prop:String): String => {
+const flipProperty = (prop: String): String => {
return PROPERTIES_TO_SWAP.hasOwnProperty(prop) ? PROPERTIES_TO_SWAP[prop] : prop;
};
@@ -62,49 +58,35 @@ const swapLeftRight = (value:String): String => {
return value === 'left' ? 'right' : value === 'right' ? 'left' : value;
};
-const swapLtrRtl = (value:String): String => {
- return value === 'ltr' ? 'rtl' : value === 'rtl' ? 'ltr' : value;
-};
+const i18nStyle = (originalStyle) => {
+ if (!I18nManager.isRTL) {
+ return originalStyle;
+ }
+
+ const style = originalStyle || emptyObject;
+ const nextStyle = {};
-const i18nStyle = (style = emptyObject) => {
- const newStyle = {};
for (const prop in style) {
if (!Object.prototype.hasOwnProperty.call(style, prop)) {
continue;
}
- const indexOfNoFlip = prop.indexOf('$noI18n');
-
- if (I18nManager.isRTL) {
- if (PROPERTIES_TO_SWAP[prop]) {
- const newProp = flipProperty(prop);
- newStyle[newProp] = style[prop];
- } else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
- newStyle[prop] = swapLeftRight(style[prop]);
- } else if (PROPERTIES_SWAP_LTR_RTL[prop]) {
- newStyle[prop] = swapLtrRtl(style[prop]);
- } else if (prop === 'textShadowOffset') {
- newStyle[prop] = style[prop];
- newStyle[prop].width = additiveInverse(style[prop].width);
- } else if (prop === 'transform') {
- newStyle[prop] = style[prop].map(flipTransform);
- } else if (indexOfNoFlip > -1) {
- const newProp = prop.substring(0, indexOfNoFlip);
- newStyle[newProp] = style[prop];
- } else {
- newStyle[prop] = style[prop];
- }
+ if (PROPERTIES_TO_SWAP[prop]) {
+ const newProp = flipProperty(prop);
+ nextStyle[newProp] = style[prop];
+ } else if (PROPERTIES_SWAP_LEFT_RIGHT[prop]) {
+ nextStyle[prop] = swapLeftRight(style[prop]);
+ } else if (prop === 'textShadowOffset') {
+ nextStyle[prop] = style[prop];
+ nextStyle[prop].width = additiveInverse(style[prop].width);
+ } else if (prop === 'transform') {
+ nextStyle[prop] = style[prop].map(flipTransform);
} else {
- if (indexOfNoFlip > -1) {
- const newProp = prop.substring(0, indexOfNoFlip);
- newStyle[newProp] = style[prop];
- } else {
- newStyle[prop] = style[prop];
- }
+ nextStyle[prop] = style[prop];
}
}
- return newStyle;
+ return nextStyle;
};
module.exports = i18nStyle;
diff --git a/src/apis/StyleSheet/registry.js b/src/apis/StyleSheet/registry.js
index 9682a064..193a6930 100644
--- a/src/apis/StyleSheet/registry.js
+++ b/src/apis/StyleSheet/registry.js
@@ -7,15 +7,20 @@ import createReactDOMStyle from './createReactDOMStyle';
import flattenArray from '../../modules/flattenArray';
import flattenStyle from './flattenStyle';
import generateCss from './generateCss';
+import I18nManager from '../I18nManager';
import injector from './injector';
import mapKeyValue from '../../modules/mapKeyValue';
import prefixInlineStyles from './prefixInlineStyles';
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
-const prefix = 'r-';
const SPACE_REGEXP = /\s/g;
const ESCAPE_SELECTOR_CHARS_REGEXP = /[(),":?.%\\$#*]/g;
+const createCacheKey = (id) => {
+ const prefix = I18nManager.isRTL ? 'rtl' : 'ltr';
+ return `${prefix}-${id}`;
+};
+
/**
* Creates an HTML class name for use on elements
*/
@@ -64,7 +69,7 @@ const registerStyle = (id, flatStyle) => {
}
});
- const key = `${prefix}${id}`;
+ const key = createCacheKey(id);
resolvedPropsCache[key] = { className };
return id;
@@ -166,7 +171,7 @@ const StyleRegistry = {
// fast and cachable
if (typeof reactNativeStyle === 'number') {
- const key = `${prefix}${reactNativeStyle}`;
+ const key = createCacheKey(reactNativeStyle);
return resolvePropsIfNeeded(key, reactNativeStyle);
}
@@ -187,30 +192,8 @@ const StyleRegistry = {
}
}
- // TODO: determine when/if to cache unregistered styles. This produces 2x
- // faster benchmark results for unregistered styles. However, the cache
- // could be filled with props that are never used again.
- //
- // let hasValidKey = true;
- // let key = flatArray.reduce((keyParts, element) => {
- // if (typeof element === 'number') {
- // keyParts.push(element);
- // } else {
- // if (element.transform) {
- // hasValidKey = false;
- // } else {
- // const objectAsKey = Object.keys(element).map((prop) => `${prop}:${element[prop]}`).join(';');
- // if (objectAsKey !== '') {
- // keyParts.push(objectAsKey);
- // }
- // }
- // }
- // return keyParts;
- // }, [ prefix ]).join('-');
- // if (!hasValidKey) { key = null; }
-
// cache resolved props when all styles are registered
- const key = isArrayOfNumbers ? `${prefix}${flatArray.join('-')}` : null;
+ const key = isArrayOfNumbers ? createCacheKey(flatArray.join('-')) : null;
return resolvePropsIfNeeded(key, flatArray);
}
diff --git a/src/components/Text/TextStylePropTypes.js b/src/components/Text/TextStylePropTypes.js
index 02fa2883..54c4150c 100644
--- a/src/components/Text/TextStylePropTypes.js
+++ b/src/components/Text/TextStylePropTypes.js
@@ -32,11 +32,7 @@ const TextOnlyStylePropTypes = {
whiteSpace: string,
wordWrap: string,
MozOsxFontSmoothing: string,
- WebkitFontSmoothing: string,
- // opt-out of RTL flipping
- textAlign$noI18n: TextAlignPropType,
- textShadowOffset$noI18n: ShadowOffsetPropType,
- writingDirection$noI18n: WritingDirectionPropType
+ WebkitFontSmoothing: string
};
module.exports = {
diff --git a/src/propTypes/BorderPropTypes.js b/src/propTypes/BorderPropTypes.js
index a63d87bc..997dff9e 100644
--- a/src/propTypes/BorderPropTypes.js
+++ b/src/propTypes/BorderPropTypes.js
@@ -19,16 +19,7 @@ const BorderPropTypes = {
borderTopStyle: BorderStylePropType,
borderRightStyle: BorderStylePropType,
borderBottomStyle: BorderStylePropType,
- borderLeftStyle: BorderStylePropType,
- /* Props to opt-out of RTL flipping */
- borderLeftColor$noI18n: ColorPropType,
- borderRightColor$noI18n: ColorPropType,
- borderTopLeftRadius$noI18n: numberOrString,
- borderTopRightRadius$noI18n: numberOrString,
- borderBottomLeftRadius$noI18n: numberOrString,
- borderBottomRightRadius$noI18n: numberOrString,
- borderLeftStyle$noI18n: BorderStylePropType,
- borderRightStyle$noI18n: BorderStylePropType
+ borderLeftStyle: BorderStylePropType
};
module.exports = BorderPropTypes;
diff --git a/src/propTypes/LayoutPropTypes.js b/src/propTypes/LayoutPropTypes.js
index 5739f21d..e5c72701 100644
--- a/src/propTypes/LayoutPropTypes.js
+++ b/src/propTypes/LayoutPropTypes.js
@@ -48,16 +48,7 @@ const LayoutPropTypes = {
left: numberOrString,
position: oneOf([ 'absolute', 'fixed', 'relative', 'static' ]),
right: numberOrString,
- top: numberOrString,
- // opt-out of RTL flipping
- borderLeftWidth$noI18n: numberOrString,
- borderRightWidth$noI18n: numberOrString,
- left$noI18n: numberOrString,
- marginLeft$noI18n: numberOrString,
- marginRight$noI18n: numberOrString,
- paddingLeft$noI18n: numberOrString,
- paddingRight$noI18n: numberOrString,
- right$noI18n: numberOrString
+ top: numberOrString
};
module.exports = LayoutPropTypes;