react-native-dynamic-responsive 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # react-native-dynamic-responsive
2
+
3
+ The **best responsive package** for React Native! A **super lightweight**, production-ready responsive styling library built for the modern era of mobile apps.
4
+
5
+ Whether you are using **Expo** or **React Native CLI**, this package works seamlessly out of the box to handle dynamic orientation changes, foldable devices (inner/outer screen swapping), and tablets seamlessly—all without breaking a sweat!
6
+
7
+ If you are looking for the ultimate `react-native-size-matters` alternative that fully supports dynamic screen sizes and hooks, you've found it.
8
+
9
+ ## 🌟 Features
10
+ - **Universal Compatibility**: 100% compatible with both **Expo** (managed & bare workflows) and **React Native CLI**.
11
+ - **Ultra Lightweight**: Zero dependencies (only peer dependencies on React & React Native).
12
+ - **Dynamic & Reactive**: Styles instantly recalculate when screen dimensions change (e.g., when a user unfolds a device or rotates their screen).
13
+ - **Familiar API**: Uses industry-standard scaling terminology (`ms`, `s`, `vs`) inspired by `react-native-size-matters`.
14
+ - **Hooks-First Architecture**: Built for modern React Native apps using a `useStyles` pattern to avoid stale `StyleSheet.create` evaluations.
15
+
16
+ ---
17
+
18
+ ## 🚀 Installation
19
+
20
+ ```bash
21
+ npm install react-native-dynamic-responsive
22
+ # or
23
+ yarn add react-native-dynamic-responsive
24
+ ```
25
+
26
+ ---
27
+
28
+ ## 📖 Quick Start
29
+
30
+ The best way to use this package is via the `useStyles` hook. This ensures your styles re-render instantly on fold/unfold or screen rotation.
31
+
32
+ ```tsx
33
+ import React from 'react';
34
+ import { View, Text } from 'react-native';
35
+ import { useStyles, useResponsive, ResponsiveUtils } from 'react-native-dynamic-responsive';
36
+
37
+ export const MyComponent = () => {
38
+ // Optional: Pull device status if you need logic inside your component
39
+ const { isTablet, isFold } = useResponsive();
40
+
41
+ // 1. Pass the createStyles function to the hook
42
+ const styles = useStyles(createStyles);
43
+
44
+ return (
45
+ <View style={styles.container}>
46
+ <Text style={styles.title}>
47
+ {isTablet ? 'Tablet View' : 'Phone View'}
48
+ </Text>
49
+ </View>
50
+ );
51
+ };
52
+
53
+ // 2. Define your styles outside the component to keep things clean.
54
+ // The `r` parameter (ResponsiveUtils) gives you access to real-time scaling functions!
55
+ const createStyles = (r: ResponsiveUtils) => ({
56
+ container: {
57
+ // scale (s): Standard scaling based on width
58
+ padding: r.s(16),
59
+
60
+ // moderateScale (ms): Smart scaling that prevents things from getting too big on tablets
61
+ marginTop: r.ms(20),
62
+
63
+ // width/height percentages (wp/hp)
64
+ width: r.isTablet ? r.wp(50) : r.wp(100),
65
+
66
+ backgroundColor: '#fff',
67
+ },
68
+ title: {
69
+ // Use ms() for typography!
70
+ fontSize: r.ms(24),
71
+ fontWeight: 'bold',
72
+ }
73
+ });
74
+ ```
75
+
76
+ ---
77
+
78
+ ## 🛠 Advanced Usage
79
+
80
+ ### Available Scaling Functions
81
+
82
+ When using `useStyles((r) => { ... })` or `const r = useResponsive()`, you have access to the following utilities on the `r` object:
83
+
84
+ | Function | Description | Best Used For |
85
+ | :--- | :--- | :--- |
86
+ | **`r.ms(size, factor?)`** | Moderate Scale. Scales based on width but less aggressively. | **Typography, icons, padding/margins** |
87
+ | **`r.s(size)`** | Standard Scale. Scales directly proportional to screen width. | Widths, horizontal spacing |
88
+ | **`r.vs(size)`** | Vertical Scale. Scales directly proportional to screen height. | Heights, vertical spacing |
89
+ | **`r.wp(percent)`** | Width Percentage. e.g., `r.wp(50)` = 50% of screen width | Containers, Modals |
90
+ | **`r.hp(percent)`** | Height Percentage. e.g., `r.hp(50)` = 50% of screen height | Containers, Modals |
91
+
92
+ ### Available Device Flags
93
+
94
+ You can easily trigger different UI logic without importing `Platform` or `Dimensions` manually:
95
+
96
+ - `r.isTablet` (Width >= 768)
97
+ - `r.isFold` (Width >= 600 & < 768)
98
+ - `r.isPhone` (Width < 600)
99
+ - `r.isSmallPhone` (Width <= 360)
100
+ - `r.isLandscape` (Width > Height)
101
+
102
+ ### Legacy / Static Usage (Not Recommended for Foldables)
103
+
104
+ If you have an older codebase and need to use the scaling utilities inside standard, static `StyleSheet.create`, you can still import them directly.
105
+
106
+ *Note: These will evaluate only once when the file loads, so they will not update dynamically if a foldable device unfolds.*
107
+
108
+ ```tsx
109
+ import { StyleSheet, View } from 'react-native';
110
+ import { ms, s, vs } from 'react-native-dynamic-responsive';
111
+
112
+ const StaticComponent = () => <View style={styles.box} />;
113
+
114
+ const styles = StyleSheet.create({
115
+ box: {
116
+ width: s(100),
117
+ height: vs(100),
118
+ padding: ms(10),
119
+ }
120
+ });
121
+ ```
122
+
123
+ ---
124
+
125
+ ## 👤 Author
126
+
127
+ **Dharmendra**
128
+ App Developer
129
+ [LinkedIn Profile](https://www.linkedin.com/in/dharmendra-appdeveloper)
130
+
131
+ ---
132
+
133
+ ## 📝 License
134
+
135
+ MIT License.
@@ -0,0 +1 @@
1
+ export * from './responsive';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./responsive"), exports);
@@ -0,0 +1,51 @@
1
+ import { StyleSheet } from 'react-native';
2
+ export declare const SCREEN_WIDTH: () => number;
3
+ export declare const SCREEN_HEIGHT: () => number;
4
+ export declare const IS_TABLET: () => boolean;
5
+ export declare const IS_FOLD: () => boolean;
6
+ export declare const IS_PHONE: () => boolean;
7
+ export declare const IS_SMALL_PHONE: () => boolean;
8
+ export declare const IS_LANDSCAPE: () => boolean;
9
+ export declare const scale: (size: number) => number;
10
+ export declare const s: (size: number) => number;
11
+ export declare const verticalScale: (size: number) => number;
12
+ export declare const vs: (size: number) => number;
13
+ export declare const moderateScale: (size: number, factor?: number) => number;
14
+ export declare const ms: (size: number, factor?: number) => number;
15
+ export declare const wp: (percent: number | string) => number;
16
+ export declare const hp: (percent: number | string) => number;
17
+ /**
18
+ * ==========================================================
19
+ * Dynamic React Hooks (Production-Ready)
20
+ * Automatically updates on:
21
+ * - Rotation
22
+ * - Fold / Unfold
23
+ * - Multi Window
24
+ * ==========================================================
25
+ */
26
+ export type ResponsiveUtils = {
27
+ s: (size: number) => number;
28
+ scale: (size: number) => number;
29
+ vs: (size: number) => number;
30
+ verticalScale: (size: number) => number;
31
+ ms: (size: number, factor?: number) => number;
32
+ moderateScale: (size: number, factor?: number) => number;
33
+ wp: (percent: number | string) => number;
34
+ hp: (percent: number | string) => number;
35
+ width: number;
36
+ height: number;
37
+ isTablet: boolean;
38
+ isFold: boolean;
39
+ isPhone: boolean;
40
+ isSmallPhone: boolean;
41
+ isLandscape: boolean;
42
+ };
43
+ export declare const useResponsive: () => ResponsiveUtils;
44
+ /**
45
+ * Hook to create dynamic stylesheets that recalculate on dimension changes.
46
+ * Usage:
47
+ * const styles = useStyles((r) => ({
48
+ * container: { padding: r.ms(16) }
49
+ * }));
50
+ */
51
+ export declare function useStyles<T extends StyleSheet.NamedStyles<T> | StyleSheet.NamedStyles<any>>(createStyles: (utils: ResponsiveUtils) => T | StyleSheet.NamedStyles<T>): T;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useResponsive = exports.hp = exports.wp = exports.ms = exports.moderateScale = exports.vs = exports.verticalScale = exports.s = exports.scale = exports.IS_LANDSCAPE = exports.IS_SMALL_PHONE = exports.IS_PHONE = exports.IS_FOLD = exports.IS_TABLET = exports.SCREEN_HEIGHT = exports.SCREEN_WIDTH = void 0;
4
+ exports.useStyles = useStyles;
5
+ const react_1 = require("react");
6
+ const react_native_1 = require("react-native");
7
+ /**
8
+ * ==========================================================
9
+ * Base Design Size (iPhone 15 / Modern Design Reference)
10
+ * ==========================================================
11
+ */
12
+ const BASE_WIDTH = 390;
13
+ const BASE_HEIGHT = 844;
14
+ /**
15
+ * ==========================================================
16
+ * Prevent excessive scaling on Tablets / Fold Open
17
+ * ==========================================================
18
+ */
19
+ const MAX_SCALE_WIDTH = 420;
20
+ const MAX_SCALE_HEIGHT = 932;
21
+ /**
22
+ * ==========================================================
23
+ * Current Window (Static - Evaluated Once)
24
+ * ==========================================================
25
+ */
26
+ const getWindow = () => react_native_1.Dimensions.get('window');
27
+ const SCREEN_WIDTH = () => getWindow().width;
28
+ exports.SCREEN_WIDTH = SCREEN_WIDTH;
29
+ const SCREEN_HEIGHT = () => getWindow().height;
30
+ exports.SCREEN_HEIGHT = SCREEN_HEIGHT;
31
+ const IS_TABLET = () => (0, exports.SCREEN_WIDTH)() >= 768;
32
+ exports.IS_TABLET = IS_TABLET;
33
+ const IS_FOLD = () => (0, exports.SCREEN_WIDTH)() >= 600 && (0, exports.SCREEN_WIDTH)() < 768;
34
+ exports.IS_FOLD = IS_FOLD;
35
+ const IS_PHONE = () => (0, exports.SCREEN_WIDTH)() < 600;
36
+ exports.IS_PHONE = IS_PHONE;
37
+ const IS_SMALL_PHONE = () => (0, exports.SCREEN_WIDTH)() <= 360;
38
+ exports.IS_SMALL_PHONE = IS_SMALL_PHONE;
39
+ const IS_LANDSCAPE = () => (0, exports.SCREEN_WIDTH)() > (0, exports.SCREEN_HEIGHT)();
40
+ exports.IS_LANDSCAPE = IS_LANDSCAPE;
41
+ /**
42
+ * ==========================================================
43
+ * Static Responsive Scale (For backward compatibility)
44
+ * ==========================================================
45
+ */
46
+ const effectiveWidth = () => Math.min((0, exports.SCREEN_WIDTH)(), MAX_SCALE_WIDTH);
47
+ const effectiveHeight = () => Math.min((0, exports.SCREEN_HEIGHT)(), MAX_SCALE_HEIGHT);
48
+ const scale = (size) => (effectiveWidth() / BASE_WIDTH) * size;
49
+ exports.scale = scale;
50
+ exports.s = exports.scale;
51
+ const verticalScale = (size) => (effectiveHeight() / BASE_HEIGHT) * size;
52
+ exports.verticalScale = verticalScale;
53
+ exports.vs = exports.verticalScale;
54
+ const moderateScale = (size, factor = 0.25) => size + ((0, exports.scale)(size) - size) * factor;
55
+ exports.moderateScale = moderateScale;
56
+ exports.ms = exports.moderateScale;
57
+ const wp = (percent) => {
58
+ const value = typeof percent === 'number' ? percent : parseFloat(percent);
59
+ return react_native_1.PixelRatio.roundToNearestPixel(((0, exports.SCREEN_WIDTH)() * value) / 100);
60
+ };
61
+ exports.wp = wp;
62
+ const hp = (percent) => {
63
+ const value = typeof percent === 'number' ? percent : parseFloat(percent);
64
+ return react_native_1.PixelRatio.roundToNearestPixel(((0, exports.SCREEN_HEIGHT)() * value) / 100);
65
+ };
66
+ exports.hp = hp;
67
+ const useResponsive = () => {
68
+ const { width, height } = (0, react_native_1.useWindowDimensions)();
69
+ return (0, react_1.useMemo)(() => {
70
+ const eWidth = Math.min(width, MAX_SCALE_WIDTH);
71
+ const eHeight = Math.min(height, MAX_SCALE_HEIGHT);
72
+ const _s = (size) => (eWidth / BASE_WIDTH) * size;
73
+ const _vs = (size) => (eHeight / BASE_HEIGHT) * size;
74
+ const _ms = (size, factor = 0.25) => size + (_s(size) - size) * factor;
75
+ const _wp = (percent) => {
76
+ const value = typeof percent === 'number' ? percent : parseFloat(percent);
77
+ return react_native_1.PixelRatio.roundToNearestPixel((width * value) / 100);
78
+ };
79
+ const _hp = (percent) => {
80
+ const value = typeof percent === 'number' ? percent : parseFloat(percent);
81
+ return react_native_1.PixelRatio.roundToNearestPixel((height * value) / 100);
82
+ };
83
+ return {
84
+ s: _s,
85
+ scale: _s,
86
+ vs: _vs,
87
+ verticalScale: _vs,
88
+ ms: _ms,
89
+ moderateScale: _ms,
90
+ wp: _wp,
91
+ hp: _hp,
92
+ width,
93
+ height,
94
+ isSmallPhone: width <= 360,
95
+ isPhone: width < 600,
96
+ isFold: width >= 600 && width < 768,
97
+ isTablet: width >= 768,
98
+ isLandscape: width > height,
99
+ };
100
+ }, [width, height]);
101
+ };
102
+ exports.useResponsive = useResponsive;
103
+ /**
104
+ * Hook to create dynamic stylesheets that recalculate on dimension changes.
105
+ * Usage:
106
+ * const styles = useStyles((r) => ({
107
+ * container: { padding: r.ms(16) }
108
+ * }));
109
+ */
110
+ function useStyles(createStyles) {
111
+ const responsive = (0, exports.useResponsive)();
112
+ // We only want to recreate the stylesheet if responsive changes (width/height), NOT on every render.
113
+ // Assuming createStyles is a pure function that relies ONLY on the 'utils' parameter.
114
+ return (0, react_1.useMemo)(() => react_native_1.StyleSheet.create(createStyles(responsive)), [responsive.width, responsive.height]);
115
+ }
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "react-native-dynamic-responsive",
3
+ "version": "1.0.0",
4
+ "description": "Production-ready dynamic responsive setup for React Native apps.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "prepublishOnly": "npm run build"
10
+ },
11
+ "keywords": [
12
+ "react-native",
13
+ "react-native-responsive",
14
+ "expo",
15
+ "react-native-cli",
16
+ "best-responsive-package",
17
+ "responsive-design",
18
+ "scale",
19
+ "tablet",
20
+ "foldable",
21
+ "dynamic",
22
+ "size-matters",
23
+ "react-native-size-matters"
24
+ ],
25
+ "author": "Dharmendra (https://www.linkedin.com/in/dharmendra-appdeveloper)",
26
+ "license": "MIT",
27
+ "peerDependencies": {
28
+ "react": "*",
29
+ "react-native": "*"
30
+ },
31
+ "devDependencies": {
32
+ "@types/react": "^18.0.0",
33
+ "@types/react-native": "^0.72.0",
34
+ "typescript": "^5.0.0"
35
+ }
36
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './responsive';
@@ -0,0 +1,146 @@
1
+ import { useMemo } from 'react';
2
+ import { Dimensions, PixelRatio, useWindowDimensions, StyleSheet } from 'react-native';
3
+
4
+ /**
5
+ * ==========================================================
6
+ * Base Design Size (iPhone 15 / Modern Design Reference)
7
+ * ==========================================================
8
+ */
9
+ const BASE_WIDTH = 390;
10
+ const BASE_HEIGHT = 844;
11
+
12
+ /**
13
+ * ==========================================================
14
+ * Prevent excessive scaling on Tablets / Fold Open
15
+ * ==========================================================
16
+ */
17
+ const MAX_SCALE_WIDTH = 420;
18
+ const MAX_SCALE_HEIGHT = 932;
19
+
20
+ /**
21
+ * ==========================================================
22
+ * Current Window (Static - Evaluated Once)
23
+ * ==========================================================
24
+ */
25
+ const getWindow = () => Dimensions.get('window');
26
+
27
+ export const SCREEN_WIDTH = () => getWindow().width;
28
+ export const SCREEN_HEIGHT = () => getWindow().height;
29
+
30
+ export const IS_TABLET = () => SCREEN_WIDTH() >= 768;
31
+ export const IS_FOLD = () => SCREEN_WIDTH() >= 600 && SCREEN_WIDTH() < 768;
32
+ export const IS_PHONE = () => SCREEN_WIDTH() < 600;
33
+ export const IS_SMALL_PHONE = () => SCREEN_WIDTH() <= 360;
34
+ export const IS_LANDSCAPE = () => SCREEN_WIDTH() > SCREEN_HEIGHT();
35
+
36
+ /**
37
+ * ==========================================================
38
+ * Static Responsive Scale (For backward compatibility)
39
+ * ==========================================================
40
+ */
41
+ const effectiveWidth = () => Math.min(SCREEN_WIDTH(), MAX_SCALE_WIDTH);
42
+ const effectiveHeight = () => Math.min(SCREEN_HEIGHT(), MAX_SCALE_HEIGHT);
43
+
44
+ export const scale = (size: number) => (effectiveWidth() / BASE_WIDTH) * size;
45
+ export const s = scale;
46
+
47
+ export const verticalScale = (size: number) => (effectiveHeight() / BASE_HEIGHT) * size;
48
+ export const vs = verticalScale;
49
+
50
+ export const moderateScale = (size: number, factor: number = 0.25) =>
51
+ size + (scale(size) - size) * factor;
52
+ export const ms = moderateScale;
53
+
54
+ export const wp = (percent: number | string) => {
55
+ const value = typeof percent === 'number' ? percent : parseFloat(percent);
56
+ return PixelRatio.roundToNearestPixel((SCREEN_WIDTH() * value) / 100);
57
+ };
58
+
59
+ export const hp = (percent: number | string) => {
60
+ const value = typeof percent === 'number' ? percent : parseFloat(percent);
61
+ return PixelRatio.roundToNearestPixel((SCREEN_HEIGHT() * value) / 100);
62
+ };
63
+
64
+ /**
65
+ * ==========================================================
66
+ * Dynamic React Hooks (Production-Ready)
67
+ * Automatically updates on:
68
+ * - Rotation
69
+ * - Fold / Unfold
70
+ * - Multi Window
71
+ * ==========================================================
72
+ */
73
+
74
+ export type ResponsiveUtils = {
75
+ s: (size: number) => number;
76
+ scale: (size: number) => number;
77
+ vs: (size: number) => number;
78
+ verticalScale: (size: number) => number;
79
+ ms: (size: number, factor?: number) => number;
80
+ moderateScale: (size: number, factor?: number) => number;
81
+ wp: (percent: number | string) => number;
82
+ hp: (percent: number | string) => number;
83
+ width: number;
84
+ height: number;
85
+ isTablet: boolean;
86
+ isFold: boolean;
87
+ isPhone: boolean;
88
+ isSmallPhone: boolean;
89
+ isLandscape: boolean;
90
+ };
91
+
92
+ export const useResponsive = (): ResponsiveUtils => {
93
+ const { width, height } = useWindowDimensions();
94
+
95
+ return useMemo(() => {
96
+ const eWidth = Math.min(width, MAX_SCALE_WIDTH);
97
+ const eHeight = Math.min(height, MAX_SCALE_HEIGHT);
98
+
99
+ const _s = (size: number) => (eWidth / BASE_WIDTH) * size;
100
+ const _vs = (size: number) => (eHeight / BASE_HEIGHT) * size;
101
+ const _ms = (size: number, factor = 0.25) => size + (_s(size) - size) * factor;
102
+ const _wp = (percent: number | string) => {
103
+ const value = typeof percent === 'number' ? percent : parseFloat(percent);
104
+ return PixelRatio.roundToNearestPixel((width * value) / 100);
105
+ };
106
+ const _hp = (percent: number | string) => {
107
+ const value = typeof percent === 'number' ? percent : parseFloat(percent);
108
+ return PixelRatio.roundToNearestPixel((height * value) / 100);
109
+ };
110
+
111
+ return {
112
+ s: _s,
113
+ scale: _s,
114
+ vs: _vs,
115
+ verticalScale: _vs,
116
+ ms: _ms,
117
+ moderateScale: _ms,
118
+ wp: _wp,
119
+ hp: _hp,
120
+ width,
121
+ height,
122
+ isSmallPhone: width <= 360,
123
+ isPhone: width < 600,
124
+ isFold: width >= 600 && width < 768,
125
+ isTablet: width >= 768,
126
+ isLandscape: width > height,
127
+ };
128
+ }, [width, height]);
129
+ };
130
+
131
+ /**
132
+ * Hook to create dynamic stylesheets that recalculate on dimension changes.
133
+ * Usage:
134
+ * const styles = useStyles((r) => ({
135
+ * container: { padding: r.ms(16) }
136
+ * }));
137
+ */
138
+ export function useStyles<T extends StyleSheet.NamedStyles<T> | StyleSheet.NamedStyles<any>>(
139
+ createStyles: (utils: ResponsiveUtils) => T | StyleSheet.NamedStyles<T>
140
+ ): T {
141
+ const responsive = useResponsive();
142
+
143
+ // We only want to recreate the stylesheet if responsive changes (width/height), NOT on every render.
144
+ // Assuming createStyles is a pure function that relies ONLY on the 'utils' parameter.
145
+ return useMemo(() => StyleSheet.create(createStyles(responsive) as any), [responsive.width, responsive.height]);
146
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES6",
4
+ "module": "CommonJS",
5
+ "lib": ["ES6", "DOM"],
6
+ "declaration": true,
7
+ "outDir": "./dist",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "jsx": "react-native"
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }