├── .circleci └── config.yml ├── .gitignore ├── .npmignore ├── README.md ├── __tests__ └── exception.js ├── assets ├── for-readme-1.png └── for-readme-2.png ├── babel.config.js ├── example └── YourComponent.js ├── package-lock.json ├── package.json └── src ├── Responsive.js ├── exception └── index.js ├── type └── index.js └── util └── index.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/node:7.10 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/mongo:3.4.4 16 | 17 | working_directory: ~/repo 18 | 19 | steps: 20 | - checkout 21 | 22 | # Download and cache dependencies 23 | - restore_cache: 24 | keys: 25 | - v1-dependencies-{{ checksum "package.json" }} 26 | # fallback to using the latest cache if no exact match is found 27 | - v1-dependencies- 28 | 29 | - run: yarn install 30 | 31 | - save_cache: 32 | paths: 33 | - node_modules 34 | key: v1-dependencies-{{ checksum "package.json" }} 35 | 36 | # run tests! 37 | - run: yarn test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Node.js 6 | node_modules/ 7 | npm-debug.log 8 | jsconfig.json 9 | dump.rdb 10 | .vscode -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Node.js 6 | node_modules/ 7 | npm-debug.log 8 | 9 | # Images and extras 10 | .github/ 11 | example/ 12 | .eslintrc 13 | yarn.lock 14 | 15 | # tests 16 | __tests__/ 17 | 18 | # assets 19 | assets/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-lightweight-responsive 2 | 3 | `react-native-lightweight-responsive` can change the size of your component into optimized size, based on the default UI size of design prototype. 4 | 5 | If you have UI prototype design and the default size of prototype is 375 X 812, some devices is OK, but others have problems like below. 6 | 7 | 8 | 9 | *What's on the right is not what you want.* 10 | 11 | 12 | ## Simple Usage 13 | 14 | **install** 15 | 16 | ``` 17 | npm install --save react-native-lightweight-responsive 18 | ``` 19 | 20 | **usage** 21 | 22 | ``` 23 | import Responsive from 'react-native-lightweight-responsive'; 24 | 25 | 29 | 32 | Hello. 33 | 34 | 35 | ``` 36 | 37 | **and then?** 38 | 39 | 40 | 41 | 42 | ## API 43 | 44 | | Name | Type | Param | Description | 45 | | ------------- |:-------------:| -----:| -----: | 46 | | setOptions | func | `{width: 360, height: 640, enableOnlySmallSize: false}` | `width`, `height` sets the default size. `enableOnlySmallSize` will apply `Responsive`'s features to smaller than default size if `true`. | 47 | | width | func | `width`: number | The size (`width`) that will be changed, based on the default size (`width`) that you set using `setOptions`. | 48 | | height | func | `height`: number | The size (`height`) that will be changed, based on the default size (`height`) that you set using `setOptions`. | 49 | | font | func | `font`: number | The size (`font`) that will be changed, based on the default size (`width`) that you set using `setOptions`. | 50 | 51 | ## Example 52 | 53 | [Example](https://github.com/7772/react-native-lightweight-responsive/blob/master/example/YourComponent.js) 54 | -------------------------------------------------------------------------------- /__tests__/exception.js: -------------------------------------------------------------------------------- 1 | import Exception from '../src/exception'; 2 | 3 | describe('Exception module', () => { 4 | const exception = new Exception("Test Exception", "Exception instance"); 5 | it('can make instance.', () => { 6 | expect(exception).toBeInstanceOf(Exception); 7 | }); 8 | }); -------------------------------------------------------------------------------- /assets/for-readme-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7772/react-native-lightweight-responsive/36a903a68cdfdc25fddf03de2fc3f919a3994b74/assets/for-readme-1.png -------------------------------------------------------------------------------- /assets/for-readme-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/7772/react-native-lightweight-responsive/36a903a68cdfdc25fddf03de2fc3f919a3994b74/assets/for-readme-2.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | targets: { 7 | node: 'current', 8 | }, 9 | }, 10 | ], 11 | ], 12 | }; -------------------------------------------------------------------------------- /example/YourComponent.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View} from 'react-native'; 3 | import Responsive from 'react-native-lightweight-responsive'; 4 | 5 | /** 6 | * YourComponentFirstExample 7 | * 8 | * If you are using default viewport size (360 X 640) 9 | * and applying Responsive Design to all Smartphone size 10 | * 11 | * Use like this. 12 | */ 13 | const YourComponentFirstExample = () => { 14 | return ( 15 | 20 | ); 21 | }; 22 | 23 | 24 | /** 25 | * YourComponentSecondExample 26 | * 27 | * If you want to use customized options 28 | * 29 | * Use like this. 30 | */ 31 | Responsive.setOptions({width: 375, height: 812, enableOnlySmallSize: true}); 32 | const YourComponentSecondExample = () => { 33 | return ( 34 | 39 | ); 40 | }; 41 | 42 | export { 43 | YourComponentFirstExample, 44 | YourComponentSecondExample, 45 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-lightweight-responsive", 3 | "version": "0.0.6", 4 | "description": "Support responsive UI for react-native", 5 | "main": "src/Responsive.js", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "keywords": [ 10 | "react-native-lightweight-responsive", 11 | "react-native", 12 | "react", 13 | "responsive" 14 | ], 15 | "author": "7772", 16 | "license": "ISC", 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/7772/react-native-lightweight-responsive.git" 20 | }, 21 | "peerDependencies": { 22 | "react": "*", 23 | "react-native": "*" 24 | }, 25 | "devDependencies": { 26 | "@babel/core": "^7.4.5", 27 | "@babel/preset-env": "^7.4.5", 28 | "babel-jest": "^24.8.0", 29 | "jest": "^24.8.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Responsive.js: -------------------------------------------------------------------------------- 1 | import Exception from './exception'; 2 | import { RESPONSIVE_TYPE } from './type'; 3 | import { getDefaultSize, getResponsiveValue } from './util'; 4 | 5 | 6 | const setOptions = (options) => { 7 | if (!options) { 8 | throw new Exception( 9 | "Responsive.setOptions() ERROR", 10 | "`options` is neccessary parameter, Not to be null or undefined." 11 | ); 12 | } 13 | if (typeof options.width !== 'number') { 14 | throw new Exception( 15 | "Responsive.setOptions() ERROR", 16 | "`width` property in `options` object is not number." 17 | ); 18 | } 19 | if (typeof options.height !== 'number') { 20 | throw new Exception( 21 | "Responsive.setOptions() ERROR", 22 | "`height` property in `options` object is not number." 23 | ); 24 | } 25 | if (typeof options.enableOnlySmallSize !== 'boolean') { 26 | throw new Exception( 27 | "Responsive.setOptions() ERROR", 28 | "`enableOnlySmallSize` property in `options` object is not boolean." 29 | ); 30 | } 31 | 32 | if (!this.defaultSize) { 33 | this.defaultSize = {}; 34 | } 35 | 36 | this.defaultSize.width = options.width; 37 | this.defaultSize.height = options.height; 38 | this.enableOnlySmallSize = options.enableOnlySmallSize; 39 | }; 40 | 41 | const width = (width) => { 42 | if (!this.defaultSize) { 43 | this.defaultSize = getDefaultSize(); 44 | } 45 | 46 | const ratio = (width / this.defaultSize.width) * 100; 47 | const responsiveWidth = getResponsiveValue(RESPONSIVE_TYPE['WIDTH'], ratio); 48 | 49 | if (this.enableOnlySmallSize && responsiveWidth > width) { 50 | return width; 51 | } 52 | 53 | return responsiveWidth; 54 | }; 55 | 56 | const height = (height) => { 57 | if (!this.defaultSize) { 58 | this.defaultSize = getDefaultSize(); 59 | } 60 | 61 | const ratio = (height / this.defaultSize.height) * 100; 62 | const responsiveHeight = getResponsiveValue(RESPONSIVE_TYPE['HEIGHT'], ratio); 63 | 64 | if (this.enableOnlySmallSize && responsiveHeight > height) { 65 | return height; 66 | } 67 | 68 | return responsiveHeight; 69 | }; 70 | 71 | const font = (font) => { 72 | if (!this.defaultSize) { 73 | this.defaultSize = getDefaultSize(); 74 | } 75 | 76 | const ratio = ((font / this.defaultSize.width) * 100); 77 | const responsiveFont = getResponsiveValue(RESPONSIVE_TYPE['FONT'], ratio); 78 | 79 | if (this.enableOnlySmallSize && responsiveFont > font) { 80 | return font; 81 | } 82 | 83 | return responsiveFont; 84 | }; 85 | 86 | export default Responsive = { 87 | defaultSize: getDefaultSize(), 88 | enableOnlySmallSize: false, 89 | setOptions: setOptions, 90 | width: width, 91 | height: height, 92 | font: font, 93 | }; 94 | -------------------------------------------------------------------------------- /src/exception/index.js: -------------------------------------------------------------------------------- 1 | function Exception(name, message) { 2 | this.name = name; 3 | this.message = message; 4 | } 5 | 6 | Exception.prototype.toString = () => { 7 | return this.name + ': "' + this.message + '"'; 8 | }; 9 | 10 | export default Exception; -------------------------------------------------------------------------------- /src/type/index.js: -------------------------------------------------------------------------------- 1 | const RESPONSIVE_TYPE = { 2 | 'WIDTH': 'WIDTH', 3 | 'HEIGHT': 'HEIGHT', 4 | 'FONT': 'FONT', 5 | }; 6 | 7 | export { 8 | RESPONSIVE_TYPE, 9 | }; -------------------------------------------------------------------------------- /src/util/index.js: -------------------------------------------------------------------------------- 1 | import { Dimensions, PixelRatio } from 'react-native'; 2 | import Exception from '../exception'; 3 | import { RESPONSIVE_TYPE } from '../type'; 4 | 5 | const appScreen = {width, height} = Dimensions.get('window'); 6 | 7 | export const getDefaultSize = () => { 8 | return { 9 | width: 360, 10 | height: 640, 11 | }; 12 | }; 13 | 14 | export const getResponsiveValue = (type, ratio = null) => { 15 | let screenValue; 16 | 17 | if (type === RESPONSIVE_TYPE['WIDTH']) { 18 | screenValue = appScreen.width; 19 | } else if (type === RESPONSIVE_TYPE['HEIGHT']) { 20 | screenValue = appScreen.height; 21 | } else if (type === RESPONSIVE_TYPE['FONT']) { 22 | screenValue = appScreen.width; 23 | } else { 24 | throw new Exception( 25 | "Responsive Library ERROR", 26 | "getResponsiveValue() supports only 'WIDTH', 'HEIGHT', 'FONT'." 27 | ); 28 | } 29 | 30 | if (!ratio || typeof ratio !== 'number') { 31 | throw new Exception( 32 | "Responsive Library ERROR", 33 | "The `ratio` parameter of getResponsive() must be `number` type." 34 | ); 35 | } 36 | 37 | return PixelRatio.roundToNearestPixel(screenValue * ratio / 100); 38 | }; --------------------------------------------------------------------------------