diff --git a/.eslintrc b/.eslintrc index 9a5dac9..ff5e25c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,6 +14,10 @@ "node": true, "jest": true }, + + "globals": { + "window": true + }, "plugins": [ "react", diff --git a/README.md b/README.md index 2df70b8..efa25d2 100644 --- a/README.md +++ b/README.md @@ -263,6 +263,45 @@ const styles = EStyleSheet.create({ } }); ``` + +Here is an example of the orientation change: + +```js +var styles = EStyleSheet.create({ + card: { + height: 200, + backgroundColor: 'green' + }, + '@media all and (orientation: portrait)': { + card: { + width: '42%' + } + }, + '@media all and (orientation: landscape)': { + card: { + width: '23%' + } + } +}); + +class example extends React.Component { + onLayoutChange(event){ + var updatedStyles = EStyleSheet.orientationUpdate(event, styles); + if(updatedStyles){ + styles = updatedStyles; + this.forceUpdate(); + } + } + + render() { + console.warn('render'); + return ( + ... + ) + } +} +``` + See full example [here](examples/media-queries). \[[top](#)\] diff --git a/src/__tests__/api.test.js b/src/__tests__/api.test.js index 8713985..de5bfdb 100644 --- a/src/__tests__/api.test.js +++ b/src/__tests__/api.test.js @@ -120,4 +120,24 @@ describe('EStyleSheet API', function () { const fn = () => api.subscribe('build', null); expect(fn).toThrowError('Listener should be a function.'); }); + + it('should update styles in orientation change', function () { + api.build({}); + let defaultStyles = api.create({ + card: { + width: '50%', + } + }); + + var layout = {nativeEvent:{layout:{width:50, height: 100}}}; + let landscapeStyles = api.orientationUpdate(layout, defaultStyles); + expect(defaultStyles).not.toEqual(landscapeStyles); + + layout = {nativeEvent:{layout:{width:100, height: 50}}}; + let portraitStyles = api.orientationUpdate(layout, defaultStyles); + expect(defaultStyles).toEqual(portraitStyles); + + let portraitStyles2 = api.orientationUpdate(layout, landscapeStyles); + expect(portraitStyles2).toEqual(false); + }); }); diff --git a/src/api.js b/src/api.js index 9bab280..f5064f0 100644 --- a/src/api.js +++ b/src/api.js @@ -8,6 +8,8 @@ import Value from './value'; import vars from './replacers/vars'; import memoize from './memoize'; import child from './child'; +import utils from './utils'; + const BUILD_EVENT = 'build'; @@ -37,9 +39,27 @@ export default class { } else { this.sheets.push(sheet); } + this._cacheSheetSource(sheet.getResult(), sheet); + return sheet.getResult(); } + /** + * Updates a specific stylesheet when the orientation changes + * @param {orientation} string + * @param {originalObj} obj + * @returns {Object} + */ + orientationUpdate(event, originalObj) { + var dimensions = utils.setDimensions(event.nativeEvent.layout); + if(dimensions.updated == false){ + return false; + } + var source = this._cacheSheetSource(originalObj); + let sheet = new Sheet(source); + sheet.calc(this.globalVars); + return sheet.getResult(); + } /** * Builds all created stylesheets with passed variables * @param {Object} [gVars] @@ -99,4 +119,17 @@ export default class { this.listeners[event].forEach(listener => listener()); } } + + _cacheSheetSource(key, sheet){ + key = JSON.stringify(Object.keys(key)); + if (!memoize.cache) { + memoize.cache = {}; + } + if (!memoize.cache[key]) { + if(sheet){ + memoize.cache[key] = sheet.source; + } + } + return memoize.cache[key]; + } } diff --git a/src/replacers/media-queries.js b/src/replacers/media-queries.js index 4b0d1c1..5d68746 100644 --- a/src/replacers/media-queries.js +++ b/src/replacers/media-queries.js @@ -8,7 +8,7 @@ * - aspect-ratio */ -import {Dimensions, Platform} from 'react-native'; +import {Platform} from 'react-native'; import mediaQuery from 'css-mediaquery'; import utils from '../utils'; @@ -64,11 +64,11 @@ function process(obj) { * @returns {Object} */ function getMatchObject() { - const win = Dimensions.get('window'); + const win = utils.getDimensions(); return { width: win.width, height: win.height, - orientation: win.width > win.height ? 'landscape' : 'portrait', + orientation: win.orientation, 'aspect-ratio': win.width / win.height, type: Platform.OS, }; diff --git a/src/replacers/percent.js b/src/replacers/percent.js index d070a44..40afb84 100644 --- a/src/replacers/percent.js +++ b/src/replacers/percent.js @@ -1,10 +1,8 @@ /** * Calculation of percent strings */ +import utils from '../utils'; -import {Dimensions} from 'react-native'; - -const {width, height} = Dimensions.get('window'); const V_PROPS = [ 'height', 'top', @@ -44,8 +42,9 @@ function isPercent(str) { * @returns {number} */ function calc(str, prop) { + const win = utils.getDimensions(); let percent = parseInt(str.substring(0, str.length - 1), 10); - let base = isVertical(prop) ? height : width; + let base = isVertical(prop) ? win.height : win.width; return base * percent / 100; } diff --git a/src/utils.js b/src/utils.js index e4d59ff..b0f3dd2 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,10 +1,13 @@ /** * Utils */ +import {Dimensions} from 'react-native'; export default { excludeKeys, isObject, + setDimensions, + getDimensions }; /** @@ -31,3 +34,27 @@ function excludeKeys(obj, keys) { function isObject(obj) { return typeof obj === 'object' && obj !== null; } + +function setDimensions(layout, defaultLayout){ + defaultLayout = defaultLayout || false; + var updated = false; + if(!defaultLayout){ + if(window.dimensions.width !== layout.width){ + updated = true; + } + } + return window.dimensions = { + orientation: (layout.width < layout.height ? 'portrait' : 'landscape'), + width: layout.width, + height: layout.height, + default: defaultLayout, + updated: updated + } +} + +function getDimensions(){ + if(!window.dimensions){ + setDimensions(Dimensions.get('window'), true); + } + return window.dimensions; +}