Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve REM calculation #180

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 12 additions & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"plugins": [
"react",
"react-native",
"import"
"import",
"@typescript-eslint"
],

"rules": {
Expand Down Expand Up @@ -58,5 +59,14 @@
"react/jsx-wrap-multilines": 1,
"react-native/no-unused-styles": 2,
"react-native/split-platform-components": 2
}
},
"overrides": [
{
"files": ["*.d.ts"],
"parser": "@typescript-eslint/parser",
"rules": {
"no-unused-vars": "off"
}
}
]
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
"@babel/core": "^7.5.0",
"@babel/runtime": "^7.5.0",
"@types/react-native": "^0.60.0",
"@typescript-eslint/eslint-plugin": "^5.52.0",
"@typescript-eslint/parser": "^5.52.0",
"babel-eslint": "^10.0.2",
"babel-plugin-runtyper": "^0.4.0",
"coveralls": "^3.0.4",
Expand Down
15 changes: 14 additions & 1 deletion src/__mocks__/react-native.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,22 @@ export let StyleSheet = {
hairlineWidth: 1
};

export let PixelRatio = {
get: jest.fn(() => 1),
roundToNearestPixel(layoutSize) {
const minPixel = 1 / PixelRatio.get();
const integerPixels = Math.floor(layoutSize);
const remainder = layoutSize % integerPixels;
const roundedPixel = Math.round(remainder / minPixel) * minPixel;

return integerPixels + roundedPixel;
}
};

export default {
Dimensions,
Platform,
StyleSheet,
I18nManager
I18nManager,
PixelRatio
};
18 changes: 18 additions & 0 deletions src/replacers/__tests__/rem.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

import {PixelRatio} from 'react-native';

import rem from '../rem';

describe('rem', function () {
Expand All @@ -10,6 +12,22 @@ describe('rem', function () {
expect(rem.calc('1.5rem', 10)).toBe(15);
expect(rem.calc('rem', 10)).toBe(10);
});
it('should calc rem-string with pixel ratio 1.5', () => {
PixelRatio.get.mockReturnValueOnce(1.5);
expect(rem.calc('18rem', 1.104)).toBe(19.666666666666668);
});
it('should calc rem-string with pixel ratio 2', () => {
PixelRatio.get.mockReturnValueOnce(2);
expect(rem.calc('18rem', 1.104)).toBe(20);
});
it('should calc rem-string with pixel ratio 3', () => {
PixelRatio.get.mockReturnValueOnce(3);
expect(rem.calc('18rem', 1.104)).toBe(20);
});
it('should calc rem-string with pixel ratio 3.5', () => {
PixelRatio.get.mockReturnValueOnce(3.5);
expect(rem.calc('18rem', 1.104)).toBe(19.857142857142858);
});
it('should throw error for invalid koef', function () {
expect(() => {rem.calc('abcrem', 10);}).toThrowError('Invalid rem value: abcrem');
});
Expand Down
3 changes: 2 additions & 1 deletion src/replacers/rem.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* Calculation of REM strings
*/
import {PixelRatio} from 'react-native';

const SUFFIX = 'rem';
const DEFAULT_REM = 16;
Expand Down Expand Up @@ -31,5 +32,5 @@ function calc(str, rem = DEFAULT_REM) {
if (isNaN(koef)) {
throw new Error('Invalid rem value: ' + str);
}
return rem * koef;
return PixelRatio.roundToNearestPixel(rem * koef);
}
40 changes: 30 additions & 10 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,45 @@
* - media queries (started with "@media...")
* - underscored output keys (started with "_...")
*
* Adding key augmention is tracked here: https://github.com/Microsoft/TypeScript/issues/12754
* Adding key augmentation is tracked here: https://github.com/Microsoft/TypeScript/issues/12754
*/

import {StyleSheet} from 'react-native';

export = EStyleSheet;
import {StyleSheet, ImageStyle, TextStyle, ViewStyle} from 'react-native';

declare namespace EStyleSheet {
type AnyObject<T = {}> = T & {[key: string]: any};
type Event = 'build';
type Function<K> = () => K
type Value<T> = T | string & {}
type Variable<T> = Value<T> | Function<Value<T>>
type Extended<T> = { [K in keyof T]: Variable<T[K]> }

type AnyStyle = ImageStyle & TextStyle & ViewStyle
type AnyStyleSet = { [key: string]: AnyStyle }

type EStyleSet<T = any> = { [K in keyof T]:
T[K] extends Variable<number> ? T[K] :
T[K] extends MediaQuery ? T[K] :
Extended<AnyStyle>
}

type StyleSet<T = any> = { [K in keyof T]:
T[K] extends number ? T[K] :
T[K] extends string ? T[K] :
T[K] extends Function<number> ? number :
T[K] extends Function<string> ? string :
T[K] extends MediaQuery ? AnyStyleSet :
AnyStyle
}

export function create<T>(styles: AnyObject<T>): AnyObject<T>;
export type MediaQuery = { [key: string]: Extended<AnyStyle> }
type Event = 'build';

export function create<T = EStyleSet>(styles: EStyleSet<T>): StyleSet<T>;
export function build<T>(rawGlobalVars?: T): void;
export function value<T>(expr: any, prop?: string): any;
export function value(expr: any, prop?: string): any;
export function child<T>(styles: T, styleName: string, index: number, count: number): T;
export function subscribe(event: Event, listener: () => any): void;
export function clearCache(): void;

// inherited from StyleSheet
export const flatten: typeof StyleSheet.flatten;
export const setStyleAttributePreprocessor: typeof StyleSheet.setStyleAttributePreprocessor;
Expand All @@ -34,4 +54,4 @@ declare namespace EStyleSheet {
export const absoluteFill: typeof StyleSheet.absoluteFill;
}


export default EStyleSheet;
9 changes: 6 additions & 3 deletions types/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
* Type definition tests.
*/

import {StyleSheet} from 'react-native';
import React from 'react';
import {StyleSheet, View} from 'react-native';
import EStyleSheet from '..';

const eStyles = EStyleSheet.create({
$var: 10,
button1: {
width: () => '100%',
// todo: fix it
// @ts-ignore
'@media (min-width: 350)': {
width: '$var'
}
Expand Down Expand Up @@ -37,8 +40,8 @@ EStyleSheet.value('100%');
EStyleSheet.value('100%', 'width');
EStyleSheet.subscribe('build', () => {});
EStyleSheet.clearCache();
const x = EStyleSheet.absoluteFill;
EStyleSheet.flatten([eStyles.button1, eStyles.button2]);
EStyleSheet.flatten([eStyles.button1, eStyles.button2, EStyleSheet.absoluteFill]);
EStyleSheet.flatten(styles.button1);
EStyleSheet.flatten([styles.button1, styles.button2]);
EStyleSheet.setStyleAttributePreprocessor('color', () => 'red');
React.createElement(View, { style: eStyles.button1 })