- π Description
- π Features
- β Installation
- π Getting Started
- π‘ Usage
- π¨ Creating Designs
- π Moving Between Designs
- π§ Creating Designs with Variants
- π Categorized List View
- π Draggable Floating Button
- β Configuration
- π
main.js
- π
index.js
- π
designer.requires.js
- π
preview.js
- π Contributing
- π License
- π§ Contact
React Native Design Mode is a developer-friendly package that streamlines the process of creating views without the need to navigate through the entire app flow. If you've found Storybook to be a bit heavy for your simple projects, this package offers a lightweight alternative with all the features you need.
Heavily inspired by storybook project so most things are similar.
- Effortless design mode toggle with a floating button
- Allows developer to focus more on quickly designing views
- Lightweight and efficient implementation
- Familiar structure that is inspired by Storybook
You can install the package via npm or yarn:
npm install react-native-design-mode
# or
yarn add react-native-design-mode
Run CLI to quickly install designer into your project.
designer install
It does two things:
- Creates a
.designer
folder in your project root with required files in it. - Adds
designer update
command to the prestart script.
- Note:
You can use
-c
flag to change the designer folder. Rundesigner help install
for details.
After running the command you will have the following folder structure
βββ project root
β βββ π .designer
β βββ π designer.requires.js
β βββ π index.js
β βββ π main.js
β βββ π preview.js
Import the designer file
import Designer from "./.designer";
Add Designer
component in your App.tsx
const App = () => {
return (
<>
<SafeAreaProvider>
<AppContainer />
</SafeAreaProvider>
<Designer />
</>
);
}
Or use it directly in your index.js
file
AppRegistry.registerComponent(appName, () => Designer);
Imagine you have a Login.tsx
screen that you want to design.
To achieve this, all you have to do is create a new file named Login.design.tsx
right next to the Login.tsx
.
// src/Login.design.tsx
import Login from './Login';
export default {
title: 'Login',
component: Login,
}
Once you've added the new design file, you'll need to update the design list.
You can do this in two ways:
- Use the command-line interface (CLI) to manually update the list. (Recommended)
designer update
- Restart the bundler, which will automatically trigger the prestart script
npm start
Great news! You're all set! Open the app, and you'll see the Login screen right in design mode. Now you can start designing and refining the layout with ease.
While we are on the design selection screen, floating button works like a toggle to switch design mode on/off.
After you select a design, we can click on floating button to go back to design list.
We can easily create different variants of a design by exporting more design objects.
// src/Login.design.tsx
import Login from './Login';
export default {
title: 'Login',
component: Login,
}
// export default variant
export const Basic = {}
// export another variant
export const Dark = () => <Login theme={'dark'} />
We can categorize our views infinitely by adding group names in titles
// src/Login.design.tsx
import Login from './Login';
export default {
title: 'Authentication/Login',
component: Login,
}
We have the flexibility to position the floating button on the screen edges, ensuring it won't obstruct our view design process.
- Note: To make the floating button draggable on android,
make sure you use either
GestureHandlerRootView
orgestureHandlerRootHOC
. Check installation docs for RNGH
module.exports = {
designs: ["../src/**/*.design.@(js|jsx|ts|tsx)"],
};
designs
: This is an array that defines the location of our design files. By default, we use a glob pattern to load all *.design.js files inside the src directory and its subdirectories. You may need to adjust the path based on your project structure.excludePaths
: This is an array of path patterns that will be excluded from loading. By default it is['**/node_modules']
import { getDesignModeUI } from "react-native-design-mode";
if (__DEV__) {
require('./designer.requires');
}
const Designer = getDesignModeUI();
export default Designer;
All designs are imported here. Designs are stripped out by bundler when building for production so you dont have to worry about it.
/* do not change this file, it is auto generated by design mode. */
import { context } from "react-native-design-mode";
context.initialize();
// ...
This is an auto generated file by design update
command which will be automatically executed on every npm run start
.
It is imported in .designer/index.js
and contains all designs of your project.
You shouldn't modify this file as it will be overwritten.
import React from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
export const decorators = [
// Add SafeAreaProvider to all designs
(Component, ctx) => (
<SafeAreaProvider>
<Component />
</SafeAreaProvider>
),
];
This file is completely optional but it will help us create global declarations for all of our designs.
decorators
: This is an array of functions of Elements or Components that will be applied on every design. We can use it to create wrappers likeSafeAreaProvider
orNavigator
Check this example where we apply navigator conditionally.
// .designer/preview.js
const Stack = createStackNavigator();
export const decorators = [
(Component, ctx) => {
if (ctx.parameters.withNavigation)
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="design" screenOptions={{headerShown: false}}>
<Stack.Screen name="design" component={Component} />
</Stack.Navigator>
</NavigationContainer>
);
return Component;
},
];
// src/Login.design.tsx
export default {
title: "Login",
component: Login,
parameters: {
withNavigation: true
}
};
parameters
: Global parameters that will be applied on all designs.
This is a special parameter which can config features of our designer. Currently there is only one feature:
To enable theme switcher feature, add a themeSwitcher
parameter like in example:
export const parameters = {
designer: {
themeSwitcher: {
set: (ctx, value) => {
// here you can set your theme
// value is true for dark, false for light
},
value: false, // initial value
}
}
}
loaders
: This is an object of promise functions that will be executed before displaying any design. The loaded results can be accessed fromctx.loaded
field.
Example
// .designer/preview.js
export const loaders = {
stores: async () => getStores(),
};
// example of accesing "loaded" field in decorators
export const decorators = [
(Component, ctx) => {
return (
<Provider {...ctx.loaded.stores}> {/* <-- */}
<Component />
</Provider>
);
},
];
// src/Login.design.tsx
// example of accessing "loaded" field in designs
export default {
title: "Login",
component: Login,
prepare: (ctx) => {
// Do something with ctx.loaded.stores
}
};
Contributions are welcome! If you find a bug or want to add a new feature, feel free to submit a pull request. For major changes, please open an issue first to discuss the proposed changes.
This project is licensed under the MIT License - see the LICENSE file for details.
If you have any questions or need assistance, feel free to open an issue.
Happy coding!