Skip to content

Commit

Permalink
Added moderateVerticalScale (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
SrBrahma authored Sep 3, 2020
1 parent e988f3a commit ac33ee0
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 58 deletions.
38 changes: 23 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ yarn add react-native-size-matters
```

## Motivation
When developing with react-native, you need to manually adjust your app to look great on a variety of different screen sizes. That's a tedious job.
react-native-size-matters provides some simple tooling to make your scaling a whole lot easier.
The idea is to develop once on a standard ~5" screen mobile device and then simply apply the provided utils.
When developing with react-native, you need to manually adjust your app to look great on a variety of different screen sizes. That's a tedious job.
react-native-size-matters provides some simple tooling to make your scaling a whole lot easier.
The idea is to develop once on a standard ~5" screen mobile device and then simply apply the provided utils.
📖 You can read more about what led to this library on my blog post, which can be found in [this repo](./examples/BlogPost) or at [Medium](https://medium.com/soluto-engineering/size-matters-5aeeb462900a).

## Api
Expand All @@ -37,22 +37,24 @@ const Component = props =>
```


* `scale(size: number)`
* `scale(size: number)`
Will return a linear scaled result of the provided size, based on your device's screen width.
* `verticalScale(size: number)`
* `verticalScale(size: number)`
Will return a linear scaled result of the provided size, based on your device's screen height.

* `moderateScale(size: number, factor?: number)`
Sometimes you don't want to scale everything in a linear manner, that's where moderateScale comes in.
The cool thing about it is that you can control the resize factor (default is 0.5).
If normal scale will increase your size by +2X, moderateScale will only increase it by +X, for example:
➡️ scale(10) = 20
➡️ moderateScale(10) = 15
➡️ moderateScale(10, 0.1) = 11
* `moderateScale(size: number, factor?: number)`
Sometimes you don't want to scale everything in a linear manner, that's where moderateScale comes in.
The cool thing about it is that you can control the resize factor (default is 0.5).
If normal scale will increase your size by +2X, moderateScale will only increase it by +X, for example:
➡️ scale(10) = 20
➡️ moderateScale(10) = 15
➡️ moderateScale(10, 0.1) = 11
* `moderateVerticalScale(size: number, factor?: number)`
Same as moderateScale, but using verticalScale instead of scale.

All scale functions can be imported using their shorthand alias as well:
```js
import { s, vs, ms } from 'react-native-size-matters';
import { s, vs, ms, mvs } from 'react-native-size-matters';
```


Expand All @@ -67,9 +69,11 @@ ScaleSheet will take the same stylesObject a regular StyleSheet will take, plus
* `<size>@s` - will apply `scale` function on `size`.
* `<size>@vs` - will apply `verticalScale` function on `size`.
* `<size>@ms` - will apply `moderateScale` function with resize factor of 0.5 on `size`.
* `<size>@mvs` - will apply `moderateVerticalScale` function with resize factor of 0.5 on `size`.
* `<size>@ms<factor>` - will apply `moderateScale` function with resize factor of `factor` on size.
* `<size>@mvs<factor>` - will apply `moderateVerticalScale` function with resize factor of `factor` on size.

ScaledSheet also supports rounding the result, simply add `r` at the end of the annotation.
ScaledSheet also supports rounding the result, simply add `r` at the end of the annotation.

Example:
```js
Expand All @@ -85,12 +89,16 @@ const styles = ScaledSheet.create({
row: {
padding: '[email protected]', // = moderateScale(10, 0.3)
height: '50@ms' // = moderateScale(50)
},
titleBar: {
paddingBottom: '[email protected]', // = moderateVerticalScale(30, 0.3)
height: '30@mvs'
}
});
```

<hr/>

* [Changing the Default Guideline Sizes](./examples/change-guideline-sizes.md)
* [Examples](./examples/README.md)
* [Examples](./examples/README.md)

52 changes: 38 additions & 14 deletions __tests__/ScaledSheet.spec.js
Original file line number Diff line number Diff line change
@@ -1,54 +1,72 @@
jest.mock('react-native');
import { ScaledSheet, scale, verticalScale, moderateScale } from '..';
import { ScaledSheet, scale, verticalScale, moderateScale, moderateVerticalScale } from '..';

const getRandomInt = (min = 1, max = 100) => Math.floor(Math.random() * (max - min + 1)) + min;

describe('ScaledSheet', () => {
test('Scale works', () => {
const number = getRandomInt();
const input = { test: `${number}@s` }
const input = { test: `${number}@s` };
expect(ScaledSheet.create(input).test).toBe(scale(number));
});

test('verticalScale works', () => {
const number = getRandomInt();
const input = { test: `${number}@vs` }
const input = { test: `${number}@vs` };
expect(ScaledSheet.create(input).test).toBe(verticalScale(number));
});

test('moderateScale with default factor works', () => {
const number = getRandomInt();
const input = { test: `${number}@ms` }
const input = { test: `${number}@ms` };
expect(ScaledSheet.create(input).test).toBe(moderateScale(number));
});

test('moderateVerticalScale with default factor works', () => {
const number = getRandomInt();
const input = { test: `${number}@mvs` };
expect(ScaledSheet.create(input).test).toBe(moderateVerticalScale(number));
});

test('moderateScale with custom factor works', () => {
const number = getRandomInt();
const input = { test: `${number}@ms0.7` }
const input = { test: `${number}@ms0.7` };
expect(ScaledSheet.create(input).test).toBe(moderateScale(number, 0.7));
});

test('moderateVerticalScale with custom factor works', () => {
const number = getRandomInt();
const input = { test: `${number}@mvs0.7` };
expect(ScaledSheet.create(input).test).toBe(moderateVerticalScale(number, 0.7));
});

test('Scale works with a negative value', () => {
const number = getRandomInt(-100, -1);
const input = { test: `${number}@s` }
const input = { test: `${number}@s` };
expect(ScaledSheet.create(input).test).toBe(scale(number));
});

test('moderateScale works with a negative value', () => {
const number = getRandomInt(-100, -1);
const input = { test: `${number}@ms0.3` }
const input = { test: `${number}@ms0.3` };
expect(ScaledSheet.create(input).test).toBe(moderateScale(number, 0.3));
});

test('moderateVerticalScale works with a negative value', () => {
const number = getRandomInt(-100, -1);
const input = { test: `${number}@mvs0.3` };
expect(ScaledSheet.create(input).test).toBe(moderateVerticalScale(number, 0.3));
});

test('Scale works on a deeply nested object', () => {
const number = getRandomInt();
const input = { test: { test: { test: `${number}@s` } } }
const input = { test: { test: { test: `${number}@s` } } };
expect(ScaledSheet.create(input).test.test.test).toBe(scale(number));
});

test('No special annotation should leave the number intact', () => {
const number = getRandomInt();
const input = { test: number }
const input = { test: number };
expect(ScaledSheet.create(input).test).toBe(number);
});

Expand All @@ -60,11 +78,13 @@ describe('ScaledSheet', () => {
margin: {
width: 12,
height: '12@s',
paddingTop: '6.3@mvs',
paddingBottom: -1
}
},
row: {
padding: '[email protected]',
paddingLeft: '[email protected]',
paddingBottom: '[email protected]',
height: '34@ms',
marginRight: '[email protected]',
marginLeft: '[email protected]',
Expand All @@ -75,7 +95,8 @@ describe('ScaledSheet', () => {
top: '11.3@sr',
bottom: '22.75@vsr',
left: '35.1@msr',
right: '[email protected]'
right: '[email protected]',
height: '[email protected]'
}
};

Expand All @@ -86,11 +107,13 @@ describe('ScaledSheet', () => {
margin: {
width: 12,
height: scale(12),
paddingTop: moderateVerticalScale(6.3),
paddingBottom: -1
}
},
row: {
padding: moderateScale(10, 0.3),
paddingLeft: moderateScale(10, 0.3),
paddingBottom: moderateVerticalScale(10, 0.4),
height: moderateScale(34),
marginRight: moderateScale(0.5, 0.9),
marginLeft: moderateScale(-0.5, 0.9),
Expand All @@ -101,10 +124,11 @@ describe('ScaledSheet', () => {
top: Math.round(scale(11.3)),
bottom: Math.round(verticalScale(22.75)),
left: Math.round(moderateScale(35.1)),
right: Math.round(moderateScale(-20.19, 0.3))
right: Math.round(moderateScale(-20.19, 0.3)),
height: Math.round(moderateVerticalScale(-14.13, 0.4))
}
};

expect(JSON.stringify(ScaledSheet.create(input))).toBe(JSON.stringify(expectedOutput));
});
})
});
13 changes: 11 additions & 2 deletions __tests__/scaling-utils-alias.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
jest.mock('react-native');
import { s, vs, ms } from '..';
import { s, vs, ms, mvs } from '..';

describe('scaling-utils', () => {
test('scale returns the expected result based on mocked Dimensions', () => {
Expand All @@ -22,4 +22,13 @@ describe('scaling-utils', () => {
expect(ms(100, 0.9)).toBe(190);
expect(ms(100, 2)).toBe(300);
});
})

test('moderateVerticalScale returns the expected result based on mocked Dimensions', () => {
expect(mvs(100)).toBe(125);
expect(mvs(100, 0.1)).toBe(105);
expect(mvs(100, 0.3)).toBe(115);
expect(mvs(100, 0.6)).toBe(130);
expect(mvs(100, 0.9)).toBe(145);
expect(mvs(100, 2)).toBe(200);
});
});
13 changes: 11 additions & 2 deletions __tests__/scaling-utils.extend.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
jest.mock('react-native');
jest.mock('react-native-dotenv');
import { scale, verticalScale, moderateScale } from '../extend';
import { scale, verticalScale, moderateScale, moderateVerticalScale } from '../extend';

describe('scaling-utils when guideline sizes are set using react-native-dotenv', () => {
test('scale returns the expected result based on mocked Dimensions and mocked guideline sizes', () => {
Expand All @@ -23,4 +23,13 @@ describe('scaling-utils when guideline sizes are set using react-native-dotenv',
expect(Math.floor(moderateScale(100, 0.9))).toBe(129);
expect(Math.floor(moderateScale(100, 2))).toBe(166);
});
})

test('moderateVerticalScale returns the expected result based on mocked Dimensions and mocked guideline sizes', () => {
expect(Math.floor(moderateVerticalScale(100))).toBe(100);
expect(Math.floor(moderateVerticalScale(100, 0.1))).toBe(100);
expect(Math.floor(moderateVerticalScale(100, 0.3))).toBe(100);
expect(Math.floor(moderateVerticalScale(100, 0.6))).toBe(100);
expect(Math.floor(moderateVerticalScale(100, 0.9))).toBe(100);
expect(Math.floor(moderateVerticalScale(100, 2))).toBe(100);
});
});
13 changes: 11 additions & 2 deletions __tests__/scaling-utils.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
jest.mock('react-native');
import { scale, verticalScale, moderateScale } from '..';
import { scale, verticalScale, moderateScale, moderateVerticalScale } from '..';

describe('scaling-utils', () => {
test('scale returns the expected result based on mocked Dimensions', () => {
Expand All @@ -22,4 +22,13 @@ describe('scaling-utils', () => {
expect(moderateScale(100, 0.9)).toBe(190);
expect(moderateScale(100, 2)).toBe(300);
});
})

test('moderateVerticalScale returns the expected result based on mocked Dimensions', () => {
expect(moderateVerticalScale(100)).toBe(125);
expect(moderateVerticalScale(100, 0.1)).toBe(105);
expect(moderateVerticalScale(100, 0.3)).toBe(115);
expect(moderateVerticalScale(100, 0.6)).toBe(130);
expect(moderateVerticalScale(100, 0.9)).toBe(145);
expect(moderateVerticalScale(100, 2)).toBe(200);
});
});
6 changes: 4 additions & 2 deletions extend.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ declare module "react-native-size-matters/extend" {
export function scale(size: number): number;
export function verticalScale(size: number): number;
export function moderateScale(size: number, factor?: number): number;
export function moderateVerticalScale(size: number, factor?: number): number;
export function s(size: number): number;
export function vs(size: number): number;
export function ms(size: number, factor?: number): number;
export function mvs(size: number, factor?: number): number;

export namespace ScaledSheet {
export function create<T extends NamedStyles<T> | NamedStyles<any>>(stylesObject: T): {
[P in keyof T]: RN.RegisteredStyle<T[P] & Record<Extract<keyof T[P], keyof StringifiedStyles>, number>>
export function create<T extends NamedStyles<T> | NamedStyles<any>>(stylesObject: T): {
[P in keyof T]: RN.RegisteredStyle<T[P] & Record<Extract<keyof T[P], keyof StringifiedStyles>, number>>
};
}
}
4 changes: 2 additions & 2 deletions extend.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import scaledSheetCreator from './lib/ScaledSheet';
import { scale, verticalScale, moderateScale } from './lib/extend/scaling-utils.extend';
import { scale, verticalScale, moderateScale, moderateVerticalScale } from './lib/extend/scaling-utils.extend';

export const ScaledSheet = scaledSheetCreator(scale, verticalScale, moderateScale);
export const ScaledSheet = scaledSheetCreator(scale, verticalScale, moderateScale, moderateVerticalScale);
export * from './lib/extend/scaling-utils.extend';
6 changes: 4 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ declare module "react-native-size-matters" {
export function scale(size: number): number;
export function verticalScale(size: number): number;
export function moderateScale(size: number, factor?: number): number;
export function moderateVerticalScale(size: number, factor?: number): number;
export function s(size: number): number;
export function vs(size: number): number;
export function ms(size: number, factor?: number): number;
export function mvs(size: number, factor?: number): number;

type NamedStyles<T> = { [P in keyof T]: RN.ViewStyle | RN.TextStyle | RN.ImageStyle | StringifiedStyles };

export namespace ScaledSheet {
export function create<T extends NamedStyles<T> | NamedStyles<any>>(stylesObject: T): {
[P in keyof T]: RN.RegisteredStyle<T[P] & Record<Extract<keyof T[P], keyof StringifiedStyles>, number>>
export function create<T extends NamedStyles<T> | NamedStyles<any>>(stylesObject: T): {
[P in keyof T]: RN.RegisteredStyle<T[P] & Record<Extract<keyof T[P], keyof StringifiedStyles>, number>>
};
}
}
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import scaledSheetCreator from './lib/ScaledSheet';
import { scale, verticalScale, moderateScale } from './lib/scaling-utils';
import { scale, verticalScale, moderateScale, moderateVerticalScale } from './lib/scaling-utils';

export const ScaledSheet = scaledSheetCreator(scale, verticalScale, moderateScale);
export const ScaledSheet = scaledSheetCreator(scale, verticalScale, moderateScale, moderateVerticalScale);
export * from './lib/scaling-utils';
Loading

0 comments on commit ac33ee0

Please sign in to comment.