[MM-28845]: Add storybook to mobile repo (#4870)

*Summary*
- This PR adds storybook into the mobile repo, and adds a sample story for the existing "loading" component.
- In the root of the repo run `npm run storybook`. This step automatically scans and loads all stories. A new browser tab will open with the storybook interface. You can configure the storybook host url by updating the .env file in the root of the repo. This might be required if you're using a real device. When running in an emulator, the code tries to use the default network values.
- Then run the usual `npm run android` (or `npm run ios`) and `npm run start` commands
- Storybook has been integrated into the react-native-dev-menu. When the app is running in the emulator press CTRL+M or CMD+M to open the dev menu and select "Storybook". If running on a real device, shaking the device will bring up the react-native dev menu. You can also press d in the terminal where you ran npm run start to get the app running.
- The storybook interface will open in the mobile app. The stories can be controlled either through the desktop browser storybook UI or the mobile browser storybook UI. Both will render the component on the device.

*Ticket Link*
https://mattermost.atlassian.net/browse/MM-28845

*Device Information*
This PR was tested on:
Iphone 11 emulator running ios 13.7
Pixel 3XL emulator running Android 10
This commit is contained in:
Ashish Bhate 2020-11-02 10:11:07 +00:00 committed by GitHub
parent 4e53683a3a
commit 1914b770e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 7858 additions and 38 deletions

2
.env Normal file
View file

@ -0,0 +1,2 @@
STORYBOOK_PORT=
STORYBOOK_HOST=

2
.gitignore vendored
View file

@ -5,6 +5,8 @@ build-ios
server.PID
mattermost.keystore
tmp/
.env
env.d.ts
# OSX
#

6
.storybook/main.js Normal file
View file

@ -0,0 +1,6 @@
module.exports = {
"stories": [
"../app/components/**/*.stories.mdx",
"../app/components/**/*.stories.@(js|jsx|ts|tsx)"
],
}

5
.storybook/preview.js Normal file
View file

@ -0,0 +1,5 @@
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
}

View file

@ -0,0 +1,17 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {storiesOf} from '@storybook/react-native';
import {withKnobs, select} from '@storybook/addon-knobs';
import Loading from './loading';
storiesOf('Loading Icon Story', module).
addDecorator(withKnobs).
add('loading icon', () => (
<Loading
size={select('size', {Large: 'large', Small: 'small'}, 'large')}
color={select('color', {Red: 'red', Blue: 'blue', Yellow: 'yellow', Black: 'black'}, 'red')}
/>
));

View file

@ -28,6 +28,14 @@ module.exports = {
'@websocket': './app/client/websocket',
},
}],
['module:react-native-dotenv', {
moduleName: '@env',
path: '.env',
blacklist: null,
whitelist: null,
safe: false,
allowUndefined: true,
}],
],
exclude: ['**/*.png', '**/*.jpg', '**/*.gif'],
};

8
env.d.ts vendored Normal file
View file

@ -0,0 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// So that typescript doesn't complain about importing `@env` through react-native-dotenv
declare module '@env' {
export const STORYBOOK_HOST: string;
export const STORYBOOK_PORT: number;
}

View file

@ -26,6 +26,7 @@ if (__DEV__) {
'Require cycle: node_modules/react-native/Libraries/Network/fetch.js',
'Warning: Cannot update a component from inside the function body of a different component',
]);
require('storybook/mattermost_storybook.ts');
}
const setFontFamily = () => {

7770
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -97,6 +97,10 @@
"@babel/preset-env": "7.12.1",
"@babel/register": "7.12.1",
"@react-native-community/eslint-config": "2.0.0",
"@storybook/addon-knobs": "6.0.26",
"@storybook/addon-ondevice-knobs": "5.3.23",
"@storybook/react-native": "5.3.23",
"@storybook/react-native-server": "5.3.23",
"@testing-library/react-native": "7.1.0",
"@types/enzyme": "3.10.7",
"@types/enzyme-adapter-react-16": "1.0.6",
@ -111,6 +115,7 @@
"@typescript-eslint/parser": "3.10.1",
"babel-eslint": "10.1.0",
"babel-jest": "26.6.1",
"babel-loader": "8.1.0",
"babel-plugin-module-resolver": "4.0.0",
"babel-plugin-transform-remove-console": "6.9.4",
"deep-freeze": "0.0.1",
@ -139,6 +144,9 @@
"nyc": "15.1.0",
"patch-package": "6.2.2",
"react-dom": "16.13.1",
"react-native-dev-menu": "4.0.2",
"react-native-dotenv": "2.4.2",
"react-native-storybook-loader": "2.0.2",
"redux-mock-store": "1.5.4",
"redux-persist-node-storage": "2.0.0",
"socketcluster": "16.0.1",
@ -177,6 +185,18 @@
"build:ios-unsigned": "./scripts/build.sh ipa unsigned",
"build:ios-sim": "./scripts/build.sh ipa simulator",
"build:android": "./scripts/build.sh apk",
"build:android-unsigned": "./scripts/build.sh apk unsigned"
"build:android-unsigned": "./scripts/build.sh apk unsigned",
"build-storybook": "build-storybook",
"prestorybook": "rnstl",
"storybook": "start-storybook -p 7007"
},
"config": {
"react-native-storybook-loader": {
"searchDir": [
"./app/components"
],
"pattern": "**/*.stories.@(js|jsx|ts|tsx)",
"outputFile": "./storybook/storyLoader.js"
}
}
}

3
storybook/addons.ts Normal file
View file

@ -0,0 +1,3 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import '@storybook/addon-knobs/register';

31
storybook/index.ts Normal file
View file

@ -0,0 +1,31 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Platform} from 'react-native';
import {STORYBOOK_HOST, STORYBOOK_PORT} from '@env';
import {getStorybookUI, configure} from '@storybook/react-native';
// load react-native addons for storybook rn
import '@storybook/addon-ondevice-knobs/register';
import {loadStories} from './storyLoader';
// import stories
configure(() => {
loadStories();
}, module);
// this seems to be required to get react-native-dotenv to load the env variables
// properly. Possibly something related to babel-loader
const port = STORYBOOK_PORT;
const host = STORYBOOK_HOST;
// Refer to https://github.com/storybookjs/storybook/tree/master/app/react-native#start-command-parameters
// To find allowed options for getStorybookUI
const StorybookUIRoot = getStorybookUI({
port: port || 7007,
host: host || (Platform.OS === 'ios' ? 'localhost' : '10.0.2.2'),
onDeviceUI: true,
resetStorybook: true,
});
export default StorybookUIRoot;

View file

@ -0,0 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Navigation} from 'react-native-navigation';
import {goToScreen} from '@actions/navigation';
import DevMenu from 'react-native-dev-menu';
DevMenu.addItem('StoryBook', () => goToScreen('StoryBook', 'StoryBook'));
Navigation.registerComponent('StoryBook', () => require('../storybook').default, () => require('../storybook').default);

13
storybook/storyLoader.js Normal file
View file

@ -0,0 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
function loadStories() {
require('../app/components/loading.stories');
}
const stories = ['../app/components/loading.stories'];
module.exports = {
loadStories,
stories,
};