diff --git a/docs/apis/StyleSheet.md b/docs/apis/StyleSheet.md
index c85a64e0..654a151a 100644
--- a/docs/apis/StyleSheet.md
+++ b/docs/apis/StyleSheet.md
@@ -11,12 +11,18 @@ outside of the render loop and are applied as inline styles. Read more about to
Each key of the object passed to `create` must define a style object.
+**flatten**: function
+
+Flattens an array of styles into a single style object.
+
+**renderToString**: function
+
+Returns a string of CSS used to style the application.
+
## Properties
**hairlineWidth**: number
-**flatten**: function
-
## Example
```js
diff --git a/src/apis/AppRegistry/renderApplication.js b/src/apis/AppRegistry/renderApplication.js
index ada932d4..39fadd05 100644
--- a/src/apis/AppRegistry/renderApplication.js
+++ b/src/apis/AppRegistry/renderApplication.js
@@ -13,7 +13,7 @@ import ReactDOMServer from 'react-dom/server'
import ReactNativeApp from './ReactNativeApp'
import StyleSheet from '../../apis/StyleSheet'
-const renderStyleSheetToString = () => StyleSheet._renderToString()
+const renderStyleSheetToString = () => StyleSheet.renderToString()
const styleAsElement = (style) =>
const styleAsTagString = (style) => ``
diff --git a/src/apis/StyleSheet/Store.js b/src/apis/StyleSheet/Store.js
deleted file mode 100644
index 72d12b90..00000000
--- a/src/apis/StyleSheet/Store.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import prefixAll from 'inline-style-prefix-all'
-import hyphenate from './hyphenate'
-
-class Store {
- constructor(
- initialState:Object = {},
- options:Object = { obfuscateClassNames: false }
- ) {
- this._counter = 0
- this._classNames = { ...initialState.classNames }
- this._declarations = { ...initialState.declarations }
- this._options = options
- }
-
- get(property, value) {
- const key = this._getDeclarationKey(property, value)
- return this._classNames[key]
- }
-
- set(property, value) {
- if (value != null) {
- const values = this._getPropertyValues(property) || []
- if (values.indexOf(value) === -1) {
- values.push(value)
- this._setClassName(property, value)
- this._setPropertyValues(property, values)
- }
- }
- }
-
- toString() {
- const obfuscate = this._options.obfuscateClassNames
-
- // sort the properties to ensure shorthands are first in the cascade
- const properties = Object.keys(this._declarations).sort()
-
- // transform the class name to a valid CSS selector
- const getCssSelector = (property, value) => {
- let className = this.get(property, value)
- if (!obfuscate && className) {
- className = className.replace(/[(),":?.%\\$#]/g, '\\$&')
- }
- return className
- }
-
- // transform the declarations into CSS rules with vendor-prefixes
- const buildCSSRules = (property, values) => {
- return values.reduce((cssRules, value) => {
- const declarations = prefixAll({ [property]: value })
- const cssDeclarations = Object.keys(declarations).reduce((str, prop) => {
- const value = declarations[prop]
- str += `${hyphenate(prop)}:${value};`
- return str
- }, '')
- const selector = getCssSelector(property, value)
-
- cssRules += `\n.${selector}{${cssDeclarations}}`
-
- return cssRules
- }, '')
- }
-
- const css = properties.reduce((css, property) => {
- const values = this._declarations[property]
- css += buildCSSRules(property, values)
- return css
- }, '')
-
- return (`/* ${this._counter} unique declarations */${css}`)
- }
-
- _getDeclarationKey(property, value) {
- return `${property}:${value}`
- }
-
- _getPropertyValues(property) {
- return this._declarations[property]
- }
-
- _setPropertyValues(property, values) {
- this._declarations[property] = values.map(value => value)
- }
-
- _setClassName(property, value) {
- const key = this._getDeclarationKey(property, value)
- const exists = !!this._classNames[key]
- if (!exists) {
- this._counter += 1
- if (this._options.obfuscateClassNames) {
- this._classNames[key] = `_s_${this._counter}`
- } else {
- const val = `${value}`.replace(/\s/g, '-')
- this._classNames[key] = `${property}:${val}`
- }
- }
- }
-}
-
-module.exports = Store
diff --git a/src/apis/StyleSheet/StyleSheetRegistry.js b/src/apis/StyleSheet/StyleSheetRegistry.js
index 90e00ef1..97b01d87 100644
--- a/src/apis/StyleSheet/StyleSheetRegistry.js
+++ b/src/apis/StyleSheet/StyleSheetRegistry.js
@@ -7,42 +7,94 @@
*/
import prefixAll from 'inline-style-prefix-all'
+import hyphenate from './hyphenate'
+import expandStyle from './expandStyle'
import flattenStyle from './flattenStyle'
import processTransform from './processTransform'
+import { predefinedClassNames } from './predefs'
+
+let stylesCache = {}
+let uniqueID = 0
+
+const getCacheKey = (prop, value) => `${prop}:${value}`
+
+const normalizeStyle = (style) => {
+ return processTransform(expandStyle(flattenStyle(style)))
+}
+
+const createCssDeclarations = (style) => {
+ return Object.keys(style).map((prop) => {
+ const property = hyphenate(prop)
+ const value = style[prop]
+ return `${property}:${value};`
+ }).sort().join('')
+}
class StyleSheetRegistry {
- static registerStyle(style: Object, store): number {
+ /* for testing */
+ static _reset() {
+ stylesCache = {}
+ uniqueID = 0
+ }
+
+ static renderToString() {
+ let str = `/* ${uniqueID} unique declarations */`
+
+ return Object.keys(stylesCache).reduce((str, key) => {
+ const id = stylesCache[key].id
+ const style = stylesCache[key].style
+ const declarations = createCssDeclarations(style)
+ const rule = `\n.${id}{${declarations}}`
+ str += rule
+ return str
+ }, str)
+ }
+
+ static registerStyle(style: Object): number {
if (process.env.NODE_ENV !== 'production') {
Object.freeze(style)
}
- const normalizedStyle = processTransform(flattenStyle(style))
+ const normalizedStyle = normalizeStyle(style)
+
Object.keys(normalizedStyle).forEach((prop) => {
- // add each declaration to the store
- store.set(prop, normalizedStyle[prop])
+ const value = normalizedStyle[prop]
+ const cacheKey = getCacheKey(prop, value)
+ const exists = stylesCache[cacheKey] && stylesCache[cacheKey].id
+ if (!exists) {
+ const id = ++uniqueID
+ // add new declaration to the store
+ stylesCache[cacheKey] = {
+ id: `__style${id}`,
+ style: prefixAll({ [prop]: value })
+ }
+ }
})
+
+ return style
}
- static getStyleAsNativeProps(style, store) {
- let _className
- let _style = {}
+ static getStyleAsNativeProps(styleSheetObject, canUseCSS = false) {
const classList = []
- const normalizedStyle = processTransform(flattenStyle(style))
+ const normalizedStyle = normalizeStyle(styleSheetObject)
+ let style = {}
for (const prop in normalizedStyle) {
- let styleClass = store.get(prop, normalizedStyle[prop])
+ const value = normalizedStyle[prop]
+ const cacheKey = getCacheKey(prop, value)
+ let selector = stylesCache[cacheKey] && stylesCache[cacheKey].id || predefinedClassNames[cacheKey]
- if (styleClass) {
- classList.push(styleClass)
+ if (selector && canUseCSS) {
+ classList.push(selector)
} else {
- _style[prop] = normalizedStyle[prop]
+ style[prop] = normalizedStyle[prop]
}
}
- _className = classList.join(' ')
- _style = prefixAll(_style)
-
- return { className: _className, style: _style }
+ return {
+ className: classList.join(' '),
+ style: prefixAll(style)
+ }
}
}
diff --git a/src/apis/StyleSheet/StyleSheetValidation.js b/src/apis/StyleSheet/StyleSheetValidation.js
index d792f26d..86655265 100644
--- a/src/apis/StyleSheet/StyleSheetValidation.js
+++ b/src/apis/StyleSheet/StyleSheetValidation.js
@@ -63,8 +63,7 @@ StyleSheetValidation.addValidStylePropTypes({
direction: PropTypes.string, /* @private */
float: PropTypes.oneOf([ 'left', 'none', 'right' ]),
font: PropTypes.string, /* @private */
- listStyle: PropTypes.string,
- verticalAlign: PropTypes.string
+ listStyle: PropTypes.string
})
module.exports = StyleSheetValidation
diff --git a/src/apis/StyleSheet/__tests__/Store-test.js b/src/apis/StyleSheet/__tests__/Store-test.js
deleted file mode 100644
index f2ca4c78..00000000
--- a/src/apis/StyleSheet/__tests__/Store-test.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/* eslint-env mocha */
-
-import assert from 'assert'
-import Store from '../Store'
-
-suite('apis/StyleSheet/Store', () => {
- suite('the constructor', () => {
- test('initialState', () => {
- const initialState = { classNames: { 'textAlign:center': '__classname__' } }
- const store = new Store(initialState)
- assert.deepEqual(store._classNames['textAlign:center'], '__classname__')
- })
- })
-
- suite('#get', () => {
- test('returns a declaration-specific className', () => {
- const initialState = {
- classNames: {
- 'textAlign:center': '__expected__',
- 'textAlign:left': '__error__'
- }
- }
- const store = new Store(initialState)
- assert.deepEqual(store.get('textAlign', 'center'), '__expected__')
- })
- })
-
- suite('#set', () => {
- test('stores declarations', () => {
- const store = new Store()
- store.set('textAlign', 'center')
- store.set('marginTop', 0)
- store.set('marginTop', 1)
- store.set('marginTop', 2)
- assert.deepEqual(store._declarations, {
- textAlign: [ 'center' ],
- marginTop: [ 0, 1, 2 ]
- })
- })
-
- test('human-readable classNames', () => {
- const store = new Store()
- store.set('textAlign', 'center')
- store.set('marginTop', 0)
- store.set('marginTop', 1)
- store.set('marginTop', 2)
- assert.deepEqual(store._classNames, {
- 'textAlign:center': 'textAlign:center',
- 'marginTop:0': 'marginTop:0',
- 'marginTop:1': 'marginTop:1',
- 'marginTop:2': 'marginTop:2'
- })
- })
-
- test('obfuscated classNames', () => {
- const store = new Store({}, { obfuscateClassNames: true })
- store.set('textAlign', 'center')
- store.set('marginTop', 0)
- store.set('marginTop', 1)
- store.set('marginTop', 2)
- assert.deepEqual(store._classNames, {
- 'textAlign:center': '_s_1',
- 'marginTop:0': '_s_2',
- 'marginTop:1': '_s_3',
- 'marginTop:2': '_s_4'
- })
- })
-
- test('replaces space characters', () => {
- const store = new Store()
-
- store.set('backgroundPosition', 'top left')
- assert.equal(store.get('backgroundPosition', 'top left'), 'backgroundPosition\:top-left')
- })
- })
-
- suite('#toString', () => {
- test('human-readable style sheet', () => {
- const store = new Store()
- store.set('textAlign', 'center')
- store.set('backgroundColor', 'rgba(0,0,0,0)')
- store.set('color', '#fff')
- store.set('fontFamily', '"Helvetica Neue", Arial, sans-serif')
- store.set('marginBottom', '0px')
- store.set('width', '100%')
-
- const expected = '/* 6 unique declarations */\n' +
- '.backgroundColor\\:rgba\\(0\\,0\\,0\\,0\\){background-color:rgba(0,0,0,0);}\n' +
- '.color\\:\\#fff{color:#fff;}\n' +
- '.fontFamily\\:\\"Helvetica-Neue\\"\\,-Arial\\,-sans-serif{font-family:"Helvetica Neue", Arial, sans-serif;}\n' +
- '.marginBottom\\:0px{margin-bottom:0px;}\n' +
- '.textAlign\\:center{text-align:center;}\n' +
- '.width\\:100\\%{width:100%;}'
-
- assert.equal(store.toString(), expected)
- })
-
- test('obfuscated style sheet', () => {
- const store = new Store({}, { obfuscateClassNames: true })
- store.set('textAlign', 'center')
- store.set('marginBottom', '0px')
- store.set('margin', '1px')
- store.set('margin', '2px')
- store.set('margin', '3px')
-
- const expected = '/* 5 unique declarations */\n' +
- '._s_3{margin:1px;}\n' +
- '._s_4{margin:2px;}\n' +
- '._s_5{margin:3px;}\n' +
- '._s_2{margin-bottom:0px;}\n' +
- '._s_1{text-align:center;}'
-
- assert.equal(store.toString(), expected)
- })
- })
-})
diff --git a/src/apis/StyleSheet/__tests__/StyleSheetRegistry-test.js b/src/apis/StyleSheet/__tests__/StyleSheetRegistry-test.js
new file mode 100644
index 00000000..44581302
--- /dev/null
+++ b/src/apis/StyleSheet/__tests__/StyleSheetRegistry-test.js
@@ -0,0 +1,55 @@
+/* eslint-env mocha */
+
+/**
+ * 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.
+ */
+
+import assert from 'assert'
+import StyleSheetRegistry from '../StyleSheetRegistry'
+
+suite('apis/StyleSheet/StyleSheetRegistry', () => {
+ setup(() => {
+ StyleSheetRegistry._reset()
+ })
+
+ test('static renderToString', () => {
+ const style1 = { alignItems: 'center', opacity: 1 }
+ const style2 = { alignItems: 'center', opacity: 1 }
+ StyleSheetRegistry.registerStyle(style1)
+ StyleSheetRegistry.registerStyle(style2)
+
+ const actual = StyleSheetRegistry.renderToString()
+ const expected = `/* 2 unique declarations */
+.__style1{-ms-flex-align:center;-webkit-align-items:center;-webkit-box-align:center;align-items:center;}
+.__style2{opacity:1;}`
+
+ assert.equal(actual, expected)
+ })
+
+ test('static getStyleAsNativeProps', () => {
+ const style = { borderColorTop: 'white', opacity: 1 }
+ const style1 = { opacity: 1 }
+ StyleSheetRegistry.registerStyle(style1)
+
+ // canUseCSS = false
+ const actual1 = StyleSheetRegistry.getStyleAsNativeProps(style)
+ const expected1 = {
+ className: '',
+ style: { borderColorTop: 'white', opacity: 1 }
+ }
+ assert.deepEqual(actual1, expected1)
+
+ // canUseCSS = true
+ const actual2 = StyleSheetRegistry.getStyleAsNativeProps(style, true)
+ const expected2 = {
+ className: '__style1',
+ style: { borderColorTop: 'white' }
+ }
+ assert.deepEqual(actual2, expected2)
+ })
+})
diff --git a/src/apis/StyleSheet/__tests__/index-test.js b/src/apis/StyleSheet/__tests__/index-test.js
index cfbbad37..fa8de14a 100644
--- a/src/apis/StyleSheet/__tests__/index-test.js
+++ b/src/apis/StyleSheet/__tests__/index-test.js
@@ -4,7 +4,7 @@ import { resetCSS, predefinedCSS } from '../predefs'
import assert from 'assert'
import StyleSheet from '..'
-const styles = { root: { borderWidth: 1 } }
+const styles = { root: { opacity: 1 } }
suite('apis/StyleSheet', () => {
setup(() => {
@@ -12,55 +12,40 @@ suite('apis/StyleSheet', () => {
})
suite('create', () => {
- const div = document.createElement('div')
-
- setup(() => {
- document.body.appendChild(div)
- StyleSheet.create(styles)
- div.innerHTML = ``
- })
-
- teardown(() => {
- document.body.removeChild(div)
- })
-
test('returns styles object', () => {
assert.equal(StyleSheet.create(styles), styles)
})
test('updates already-rendered style sheet', () => {
- StyleSheet.create({ root: { color: 'red' } })
+ // setup
+ const div = document.createElement('div')
+ document.body.appendChild(div)
+ StyleSheet.create(styles)
+ div.innerHTML = ``
+ // test
+ StyleSheet.create({ root: { color: 'red' } })
assert.equal(
document.getElementById(StyleSheet.elementId).textContent,
`${resetCSS}\n${predefinedCSS}\n` +
- `/* 5 unique declarations */\n` +
- `.borderBottomWidth\\:1px{border-bottom-width:1px;}\n` +
- `.borderLeftWidth\\:1px{border-left-width:1px;}\n` +
- `.borderRightWidth\\:1px{border-right-width:1px;}\n` +
- `.borderTopWidth\\:1px{border-top-width:1px;}\n` +
- `.color\\:red{color:red;}`
+ `/* 2 unique declarations */\n` +
+ `.__style1{opacity:1;}\n` +
+ `.__style2{color:red;}`
)
+
+ // teardown
+ document.body.removeChild(div)
})
})
- test('resolve', () => {
- const props = { style: styles.root }
- const expected = { className: 'borderTopWidth:1px borderRightWidth:1px borderBottomWidth:1px borderLeftWidth:1px', style: {} }
+ test('renderToString', () => {
StyleSheet.create(styles)
- assert.deepEqual(StyleSheet.resolve(props), expected)
- })
- test('_renderToString', () => {
- StyleSheet.create(styles)
assert.equal(
- StyleSheet._renderToString(),
+ StyleSheet.renderToString(),
`${resetCSS}\n${predefinedCSS}\n` +
- `/* 4 unique declarations */\n` +
- `.borderBottomWidth\\:1px{border-bottom-width:1px;}\n` +
- `.borderLeftWidth\\:1px{border-left-width:1px;}\n` +
- `.borderRightWidth\\:1px{border-right-width:1px;}\n` +
- `.borderTopWidth\\:1px{border-top-width:1px;}`
+ `/* 1 unique declarations */\n` +
+ `.__style1{opacity:1;}`
)
})
})
diff --git a/src/apis/StyleSheet/__tests__/processTransform-test.js b/src/apis/StyleSheet/__tests__/processTransform-test.js
new file mode 100644
index 00000000..35d5966e
--- /dev/null
+++ b/src/apis/StyleSheet/__tests__/processTransform-test.js
@@ -0,0 +1,31 @@
+/* eslint-env mocha */
+
+import assert from 'assert'
+import processTransform from '../processTransform'
+
+suite('apis/StyleSheet/processTransform', () => {
+ test('transform', () => {
+ const style = {
+ transform: [
+ { scaleX: 20 },
+ { rotate: '20deg' }
+ ]
+ }
+
+ assert.deepEqual(
+ processTransform(style),
+ { transform: 'scaleX(20) rotate(20deg)' }
+ )
+ })
+
+ test('transformMatrix', () => {
+ const style = {
+ transformMatrix: [ 1, 2, 3, 4, 5, 6 ]
+ }
+
+ assert.deepEqual(
+ processTransform(style),
+ { transform: 'matrix3d(1,2,3,4,5,6)' }
+ )
+ })
+})
diff --git a/src/apis/StyleSheet/expandStyle.js b/src/apis/StyleSheet/expandStyle.js
index 2287b2ff..7899d327 100644
--- a/src/apis/StyleSheet/expandStyle.js
+++ b/src/apis/StyleSheet/expandStyle.js
@@ -8,16 +8,19 @@ const styleShortHands = {
margin: [ 'marginTop', 'marginRight', 'marginBottom', 'marginLeft' ],
marginHorizontal: [ 'marginRight', 'marginLeft' ],
marginVertical: [ 'marginTop', 'marginBottom' ],
+ overflow: [ 'overflowX', 'overflowY' ],
padding: [ 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft' ],
paddingHorizontal: [ 'paddingRight', 'paddingLeft' ],
paddingVertical: [ 'paddingTop', 'paddingBottom' ],
+ textDecorationLine: [ 'textDecoration' ],
writingDirection: [ 'direction' ]
}
/**
- * Alpha-sort properties, apart from shorthands which appear before the
- * properties they expand into. This ensures that more specific styles override
- * the shorthands, whatever the order in which they were originally declared.
+ * Alpha-sort properties, apart from shorthands – they must appear before the
+ * longhand properties that they expand into. This lets more specific styles
+ * override less specific styles, whatever the order in which they were
+ * originally declared.
*/
const sortProps = (propsArray) => propsArray.sort((a, b) => {
const expandedA = styleShortHands[a]
@@ -41,14 +44,17 @@ const expandStyle = (style) => {
const expandedProps = styleShortHands[key]
const value = normalizeValue(key, style[key])
- if (expandedProps) {
- expandedProps.forEach((prop, i) => {
- resolvedStyle[expandedProps[i]] = value
- })
- } else if (key === 'flex') {
+ // React Native treats `flex:1` like `flex:1 1 auto`
+ if (key === 'flex') {
resolvedStyle.flexGrow = value
resolvedStyle.flexShrink = 1
resolvedStyle.flexBasis = 'auto'
+ } else if (key === 'textAlignVertical') {
+ resolvedStyle.verticalAlign = (value === 'center' ? 'middle' : value)
+ } else if (expandedProps) {
+ expandedProps.forEach((prop, i) => {
+ resolvedStyle[expandedProps[i]] = value
+ })
} else {
resolvedStyle[key] = value
}
diff --git a/src/apis/StyleSheet/flattenStyle.js b/src/apis/StyleSheet/flattenStyle.js
index 1e89d53e..4794b6ac 100644
--- a/src/apis/StyleSheet/flattenStyle.js
+++ b/src/apis/StyleSheet/flattenStyle.js
@@ -6,7 +6,6 @@
* @flow
*/
import invariant from 'fbjs/lib/invariant'
-import expandStyle from './expandStyle'
module.exports = function flattenStyle(style): ?Object {
if (!style) {
@@ -16,9 +15,7 @@ module.exports = function flattenStyle(style): ?Object {
invariant(style !== true, 'style may be false but not true')
if (!Array.isArray(style)) {
- // we must expand styles during the flattening because expanded styles
- // override shorthands
- return expandStyle(style)
+ return style
}
const result = {}
diff --git a/src/apis/StyleSheet/index.js b/src/apis/StyleSheet/index.js
index dd7d22d9..c17c80c1 100644
--- a/src/apis/StyleSheet/index.js
+++ b/src/apis/StyleSheet/index.js
@@ -1,6 +1,5 @@
-import { resetCSS, predefinedCSS, predefinedClassNames } from './predefs'
+import { resetCSS, predefinedCSS } from './predefs'
import flattenStyle from './flattenStyle'
-import Store from './Store'
import StyleSheetRegistry from './StyleSheetRegistry'
import StyleSheetValidation from './StyleSheetValidation'
@@ -12,65 +11,61 @@ let lastStyleSheet = ''
* Initialize the store with pointer-event styles mapping to our custom pointer
* event classes
*/
-const initialState = { classNames: predefinedClassNames }
-const options = { obfuscateClassNames: !(process.env.NODE_ENV !== 'production') }
-const createStore = () => new Store(initialState, options)
-let store = createStore()
/**
* Destroy existing styles
*/
const _destroy = () => {
- store = createStore()
isRendered = false
-}
-
-/**
- * Render the styles as a CSS style sheet
- */
-const _renderToString = () => {
- const css = store.toString()
- isRendered = true
- return `${resetCSS}\n${predefinedCSS}\n${css}`
+ StyleSheetRegistry._reset()
}
const create = (styles: Object): Object => {
for (const key in styles) {
StyleSheetValidation.validateStyle(key, styles)
- StyleSheetRegistry.registerStyle(styles[key], store)
+ StyleSheetRegistry.registerStyle(styles[key])
}
// update the style sheet in place
if (isRendered) {
const stylesheet = document.getElementById(ELEMENT_ID)
if (stylesheet) {
- const newStyleSheet = _renderToString()
+ const newStyleSheet = renderToString()
if (lastStyleSheet !== newStyleSheet) {
stylesheet.textContent = newStyleSheet
lastStyleSheet = newStyleSheet
}
} else if (process.env.NODE_ENV !== 'production') {
- console.error('ReactNative: cannot find "react-stylesheet" element')
+ console.error(`ReactNative: cannot find "${ELEMENT_ID}" element`)
}
}
return styles
}
+/**
+ * Render the styles as a CSS style sheet
+ */
+const renderToString = () => {
+ const css = StyleSheetRegistry.renderToString()
+ isRendered = true
+ return `${resetCSS}\n${predefinedCSS}\n${css}`
+}
+
/**
* Accepts React props and converts inline styles to single purpose classes
* where possible.
*/
const resolve = ({ style = {} }) => {
- return StyleSheetRegistry.getStyleAsNativeProps(style, store)
+ return StyleSheetRegistry.getStyleAsNativeProps(style, isRendered)
}
module.exports = {
_destroy,
- _renderToString,
create,
elementId: ELEMENT_ID,
hairlineWidth: 1,
flatten: flattenStyle,
+ renderToString,
resolve
}
diff --git a/src/apis/StyleSheet/predefs.js b/src/apis/StyleSheet/predefs.js
index 4913716f..9506c54a 100644
--- a/src/apis/StyleSheet/predefs.js
+++ b/src/apis/StyleSheet/predefs.js
@@ -2,23 +2,23 @@
* Reset unwanted styles beyond the control of React inline styles
*/
export const resetCSS =
-`/* React Native Web */
+`/* React Native for Web */
html {font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}
body {margin:0}
button::-moz-focus-inner, input::-moz-focus-inner {border:0;padding:0}
-input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {-webkit-appearance:none}`
+input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {display:none}`
/**
* Custom pointer event styles
*/
export const predefinedCSS =
`/* pointer-events */
-._s_pe-a, ._s_pe-bo, ._s_pe-bn * {pointer-events:auto}
-._s_pe-n, ._s_pe-bo *, ._s_pe-bn {pointer-events:none}`
+.__style_pea, .__style_pebo, .__style_pebn * {pointer-events:auto}
+.__style_pen, .__style_pebo *, .__style_pebn {pointer-events:none}`
export const predefinedClassNames = {
- 'pointerEvents:auto': '_s_pe-a',
- 'pointerEvents:box-none': '_s_pe-bn',
- 'pointerEvents:box-only': '_s_pe-bo',
- 'pointerEvents:none': '_s_pe-n'
+ 'pointerEvents:auto': '__style_pea',
+ 'pointerEvents:box-none': '__style_pebn',
+ 'pointerEvents:box-only': '__style_pebo',
+ 'pointerEvents:none': '__style_pen'
}
diff --git a/src/apis/StyleSheet/processTransform.js b/src/apis/StyleSheet/processTransform.js
index 177e3188..41f33208 100644
--- a/src/apis/StyleSheet/processTransform.js
+++ b/src/apis/StyleSheet/processTransform.js
@@ -15,7 +15,8 @@ const processTransform = (style) => {
if (style.transform) {
style.transform = style.transform.map(mapTransform).join(' ')
} else if (style.transformMatrix) {
- style.transformMatrix = convertTransformMatrix(style.transformMatrix)
+ style.transform = convertTransformMatrix(style.transformMatrix)
+ delete style.transformMatrix
}
}
return style
diff --git a/src/components/Text/TextStylePropTypes.js b/src/components/Text/TextStylePropTypes.js
index 5be12d90..71f464a2 100644
--- a/src/components/Text/TextStylePropTypes.js
+++ b/src/components/Text/TextStylePropTypes.js
@@ -15,14 +15,17 @@ module.exports = {
letterSpacing: numberOrString,
lineHeight: numberOrString,
textAlign: oneOf([ 'center', 'inherit', 'justify', 'justify-all', 'left', 'right' ]),
- /**
- * @platform web
- */
- textDecoration: string,
+ textAlignVertical: oneOf([ 'auto', 'bottom', 'center', 'top' ]),
+ textDecorationLine: string,
+ /* @platform web */
textOverflow: string,
+ /* @platform web */
textShadow: string,
+ /* @platform web */
textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
+ /* @platform web */
whiteSpace: string,
+ /* @platform web */
wordWrap: string,
- writingDirection: string
+ writingDirection: oneOf([ 'auto', 'ltr', 'rtl' ])
}
diff --git a/src/components/Text/index.js b/src/components/Text/index.js
index be52666f..afe110bb 100644
--- a/src/components/Text/index.js
+++ b/src/components/Text/index.js
@@ -56,7 +56,7 @@ const styles = StyleSheet.create({
font: 'inherit',
margin: 0,
padding: 0,
- textDecoration: 'none',
+ textDecorationLine: 'none',
wordWrap: 'break-word'
},
singleLineStyle: {
diff --git a/src/components/View/index.js b/src/components/View/index.js
index 89a12f88..4f95cba5 100644
--- a/src/components/View/index.js
+++ b/src/components/View/index.js
@@ -40,7 +40,8 @@ class View extends Component {
};
static defaultProps = {
- accessible: true
+ accessible: true,
+ style: {}
};
constructor(props, context) {
@@ -55,6 +56,7 @@ class View extends Component {
...other
} = this.props
+ const flattenedStyle = StyleSheet.flatten(style)
const pointerEventsStyle = pointerEvents && { pointerEvents }
return (
@@ -73,6 +75,8 @@ class View extends Component {
style={[
styles.initial,
style,
+ // 'View' needs to use 'flexShrink' in its reset when there is no 'flex' style provided
+ flattenedStyle.flex == null && styles.flexReset,
pointerEventsStyle
]}
/>
@@ -104,7 +108,6 @@ const styles = StyleSheet.create({
display: 'flex',
flexBasis: 'auto',
flexDirection: 'column',
- flexShrink: 0,
margin: 0,
padding: 0,
position: 'relative',
@@ -113,13 +116,16 @@ const styles = StyleSheet.create({
color: 'inherit',
font: 'inherit',
textAlign: 'inherit',
- textDecoration: 'none',
+ textDecorationLine: 'none',
// list reset
listStyle: 'none',
// fix flexbox bugs
maxWidth: '100%',
minHeight: 0,
minWidth: 0
+ },
+ flexReset: {
+ flexShrink: 0
}
})