├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ ├── lint.yml │ ├── storybook-upload.yml │ └── type-check.yml ├── .gitignore ├── .prettierrc.js ├── .scaffdog ├── atom.md ├── hooks.md ├── molecule.md ├── organism.md ├── screen.md └── template.md ├── .storybook ├── addons.js ├── assets │ ├── AntDesign.ttf │ ├── Entypo.ttf │ ├── EvilIcons.ttf │ ├── Feather.ttf │ ├── FontAwesome.ttf │ ├── FontAwesome5_Brands.ttf │ ├── FontAwesome5_Regular.ttf │ ├── FontAwesome5_Solid.ttf │ ├── Foundation.ttf │ ├── Ionicons.ttf │ ├── MaterialCommunityIcons.ttf │ └── MaterialIcons.ttf ├── config.js ├── preview-head.html └── webpack.config.js ├── .vscode └── settings.json ├── .watchmanconfig ├── @types └── react-navigation.d.ts ├── App.tsx ├── LICENCE ├── README.md ├── __tests__ ├── RoundButton.test.tsx └── __snapshots__ │ └── RoundButton.test.tsx.snap ├── app.json ├── babel.config.js ├── ios └── .expo │ ├── packager-info.json │ └── settings.json ├── package.json ├── regconfig.json ├── scripts └── report-artifact ├── src ├── action │ └── index.ts ├── assets │ ├── .eslintrc.js │ ├── fonts │ │ └── SpaceMono-Regular.ttf │ └── images │ │ ├── icon.png │ │ ├── index.ts │ │ ├── robot-dev.png │ │ ├── robot-prod.png │ │ └── splash.png ├── atoms │ ├── ListItem.story.tsx │ ├── ListItem.tsx │ ├── button │ │ ├── HelloWorld.story.tsx │ │ ├── HelloWorld.tsx │ │ ├── IconButton.story.tsx │ │ ├── IconButton.tsx │ │ ├── RoundButton.story.tsx │ │ ├── RoundButton.tsx │ │ └── index.ts │ └── index.ts ├── components │ ├── StyledText.tsx │ ├── TabBarIcon.tsx │ └── __tests__ │ │ ├── StyledText.test.tsx │ │ └── __snapshots__ │ │ └── StyledText.test.tsx.snap ├── constants │ ├── Colors.ts │ └── Layout.ts ├── molecules │ ├── DialogCloseButton.story.tsx │ ├── DialogCloseButton.tsx │ ├── DismissableDialog.story.tsx │ ├── DismissableDialog.tsx │ ├── IconText.story.tsx │ └── IconText.tsx ├── navigation │ ├── AppNavigator.tsx │ └── MainTabNavigator.tsx ├── organisms │ ├── Appbar.story.tsx │ └── Appbar.tsx ├── reducer │ └── index.ts ├── screens │ ├── HomeScreen.tsx │ ├── MyPageScreen.tsx │ └── SettingsScreen.tsx ├── store │ └── index.ts └── templates │ ├── Modal.story.tsx │ ├── Modal.tsx │ └── StoryContainer.tsx ├── tsconfig.json ├── vercel.json └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | commands: 4 | restore_module_cache: 5 | parameters: 6 | module_path: 7 | type: string 8 | steps: 9 | - restore_cache: 10 | keys: 11 | - v{{ .Environment.CIRCLECI_CACHE_VERSION }}-dependencies-<< parameters.module_path >>-{{ checksum "<< parameters.module_path >>/yarn.lock" }} 12 | save_module_cache: 13 | parameters: 14 | module_path: 15 | type: string 16 | steps: 17 | - save_cache: 18 | key: v{{ .Environment.CIRCLECI_CACHE_VERSION }}-dependencies-<< parameters.module_path >>-{{ checksum "<< parameters.module_path >>/yarn.lock" }} 19 | paths: 20 | - << parameters.module_path >>/node_modules 21 | restore_story_cache: 22 | parameters: 23 | module_path: 24 | type: string 25 | steps: 26 | - restore_cache: 27 | keys: 28 | - v{{ .Environment.CIRCLECI_CACHE_VERSION }}-dependencies-<< parameters.module_path >>-{{ checksum "<< parameters.module_path >>/.cache-loader" }} 29 | save_story_cache: 30 | parameters: 31 | module_path: 32 | type: string 33 | steps: 34 | - save_cache: 35 | key: v{{ .Environment.CIRCLECI_CACHE_VERSION }}-dependencies-<< parameters.module_path >>-{{ checksum "<< parameters.module_path >>/.cache-loader" }} 36 | paths: 37 | - << parameters.module_path >>/.cache-loader 38 | install_fonts: 39 | steps: 40 | - run: 41 | name: Prepare Japanese fonts 42 | command: | 43 | mkdir /tmp/fonts 44 | cd /tmp/fonts 45 | wget https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip 46 | unzip NotoSansCJKjp-hinted.zip 47 | mkdir -p ~/.fonts 48 | cp *otf ~/.fonts 49 | fc-cache -f -v 50 | fc-match --all 51 | type_check: 52 | steps: 53 | - run: 54 | name: "Typecheck" 55 | command: yarn type-check 56 | lint: 57 | steps: 58 | - run: 59 | name: "Lint Check" 60 | command: yarn lint 61 | build_storybook: 62 | steps: 63 | - run: 64 | name: "Build Storybook" 65 | command: yarn storybook:build 66 | visreg_test: 67 | steps: 68 | - run: 69 | name: "Run Visual-Regression test" 70 | command: | 71 | yarn storycap:all 72 | yarn reg-suit 73 | 74 | setup_and_test: 75 | steps: 76 | - checkout 77 | - install_fonts 78 | - run: yarn 79 | - build_storybook 80 | - store_artifacts: 81 | path: storybook-static 82 | - run: 83 | name: "Report storybook URL to Pull Request" 84 | command: npx moxci storybook-static/index.html 85 | - visreg_test 86 | jobs: 87 | test: 88 | docker: 89 | - image: circleci/node:dubnium-browsers 90 | working_directory: ~/app 91 | steps: 92 | - setup_and_test 93 | 94 | workflows: 95 | version: 2.1 96 | test_workflow: 97 | jobs: 98 | - test 99 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | @types -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["@react-native-community"], 3 | globals: { 4 | __DEV__: true 5 | }, 6 | env: { 7 | jest: true 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint files 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node-version: [12.x] 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | - name: Use Node.js ${{ matrix.node-version }} 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - name: Install Dependencies 20 | run: yarn 21 | - name: Run Lint Check 22 | run: yarn lint 23 | -------------------------------------------------------------------------------- /.github/workflows/storybook-upload.yml: -------------------------------------------------------------------------------- 1 | name: Storybook Preview 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node-version: [12.x] 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | - name: Use Node.js ${{ matrix.node-version }} 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - name: Install Dependencies 20 | run: yarn 21 | - name: Build Storybook 22 | run: yarn storybook:build 23 | - name: Upload Storybook 24 | uses: actions/upload-artifact@v1.0.0 25 | with: 26 | name: Storybook 27 | path: storybook-static 28 | -------------------------------------------------------------------------------- /.github/workflows/type-check.yml: -------------------------------------------------------------------------------- 1 | name: Typecheck 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node-version: [12.x] 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | - name: Use Node.js ${{ matrix.node-version }} 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - name: Install Dependencies 20 | run: yarn 21 | - name: Run Typecheck 22 | run: yarn type-check 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | *.jks 5 | *.p12 6 | *.key 7 | *.mobileprovision 8 | storybook-static 9 | .DS_Store 10 | .vscode 11 | .cache-loader 12 | .reg 13 | __screenshots__ 14 | public 15 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports={ 2 | "requirePragma": true, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "bracketSpacing": false, 6 | "jsxBracketSameLine": true, 7 | } -------------------------------------------------------------------------------- /.scaffdog/atom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "atom" 3 | description: "Atom component template" 4 | message: "Please enter the name of component to be created" 5 | root: "./src/atoms" 6 | output: "**/*" 7 | ignore: [] 8 | --- 9 | 10 | # `{{ input }}.tsx` 11 | 12 | ```jsx 13 | import React from 'react' 14 | import { View, StyleSheet } from 'react-native' 15 | 16 | const styles = StyleSheet.create({ 17 | container: { 18 | flex: 1 19 | } 20 | }) 21 | 22 | type Props = {} 23 | 24 | const {{ input }} : React.FC = ({}: Props):JSX.Element => ( 25 | 26 | ) 27 | 28 | export default {{ input }} 29 | 30 | ``` 31 | 32 | # `{{ input }}.story.tsx` 33 | 34 | ```jsx 35 | import React from 'react'; 36 | import { storiesOf } from '@storybook/react'; 37 | import {{ input }} from './{{input}}'; 38 | import { StorybookContainer } from "../templates/StoryContainer"; 39 | 40 | storiesOf("atoms", module) 41 | .addDecorator(StorybookContainer) 42 | .add("{{input}}", () => <{{ input }} />); 43 | ``` 44 | -------------------------------------------------------------------------------- /.scaffdog/hooks.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "hooks" 3 | description: "CustomHooks component template" 4 | message: "Please enter the name of component to be created" 5 | root: "./src/hooks" 6 | output: "**/*" 7 | ignore: [] 8 | --- 9 | 10 | # `{{ input }}.ts` 11 | 12 | ```jsx 13 | import { useState } from 'react' 14 | import { useSelector, useDispatch } from 'react-redux' 15 | 16 | export const {{ input }} = () => {} 17 | 18 | ``` 19 | -------------------------------------------------------------------------------- /.scaffdog/molecule.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "molecule" 3 | description: "molecule component template" 4 | message: "Please enter the name of component to be created" 5 | root: "./src/molecules" 6 | output: "**/*" 7 | ignore: [] 8 | --- 9 | 10 | # `{{ input }}.tsx` 11 | 12 | ```jsx 13 | import React from 'react' 14 | import { View, StyleSheet } from 'react-native' 15 | 16 | const styles = StyleSheet.create({ 17 | container: { 18 | flex: 1 19 | } 20 | }) 21 | 22 | type Props = {} 23 | 24 | const {{ input }} : React.FC= ({}: Props):JSX.Element => ( 25 | 26 | ) 27 | 28 | export default {{ input }} 29 | 30 | ``` 31 | 32 | # `{{ input }}.story.tsx` 33 | 34 | ```jsx 35 | import React from 'react'; 36 | import { storiesOf } from '@storybook/react'; 37 | import {{ input }} from './{{input}}'; 38 | import { StorybookContainer } from "../templates/StoryContainer"; 39 | 40 | storiesOf("molecules", module) 41 | .addDecorator(StorybookContainer) 42 | .add("{{input}}", () => <{{ input }} />); 43 | ``` 44 | -------------------------------------------------------------------------------- /.scaffdog/organism.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "organism" 3 | description: "organism component template" 4 | message: "Please enter the name of component to be created" 5 | root: "./src/organisms" 6 | output: "**/*" 7 | ignore: [] 8 | --- 9 | 10 | # `{{ input }}.tsx` 11 | 12 | ```jsx 13 | import React from 'react' 14 | import { View, StyleSheet } from 'react-native' 15 | 16 | const styles = StyleSheet.create({ 17 | container: { 18 | flex: 1 19 | } 20 | }) 21 | 22 | type Props = {} 23 | 24 | const {{ input }} : React.FC= ({}: Props):JSX.Element => ( 25 | 26 | ) 27 | 28 | export default {{ input }} 29 | 30 | ``` 31 | 32 | # `{{ input }}.story.tsx` 33 | 34 | ```jsx 35 | import React from 'react'; 36 | import { storiesOf } from '@storybook/react'; 37 | import {{ input }} from './{{input}}'; 38 | 39 | storiesOf("organisms", module) 40 | .add("{{input}}", () => <{{ input }} />); 41 | 42 | ``` 43 | -------------------------------------------------------------------------------- /.scaffdog/screen.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "screen" 3 | description: "screen component template" 4 | message: "Please enter the name of component to be created" 5 | root: "./src/screens" 6 | output: "**/*" 7 | ignore: [] 8 | --- 9 | 10 | # `{{ input }}.tsx` 11 | 12 | ```jsx 13 | import React from 'react' 14 | import { View, StyleSheet } from 'react-native' 15 | 16 | const styles = StyleSheet.create({ 17 | container: { 18 | flex: 1 19 | } 20 | }) 21 | 22 | type Props = {} 23 | 24 | const {{ input }} = ({}: Props) => ( 25 | 26 | ) 27 | 28 | export default {{ input }} 29 | 30 | ``` 31 | 32 | # `{{ input }}.story.tsx` 33 | 34 | ```jsx 35 | import * as React from 'react'; 36 | import { storiesOf } from '@storybook/react'; 37 | import {{ input }} from './{{input}}' 38 | 39 | storiesOf("sceens", module) 40 | .add("{{input}}", () => <{{ input }} />); 41 | ``` 42 | -------------------------------------------------------------------------------- /.scaffdog/template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "template" 3 | description: "template component template" 4 | message: "Please enter the name of component to be created" 5 | root: "./src/templates" 6 | output: "**/*" 7 | ignore: [] 8 | --- 9 | 10 | # `{{ input }}.tsx` 11 | 12 | ```jsx 13 | import React from 'react' 14 | import { View, StyleSheet } from 'react-native' 15 | 16 | const styles = StyleSheet.create({ 17 | container: { 18 | flex: 1 19 | } 20 | }) 21 | 22 | type Props = {} 23 | 24 | const {{ input }}: React.FC = ({}: Props):JSX.Element => ( 25 | 26 | ) 27 | 28 | export default {{ input }} 29 | 30 | ``` 31 | 32 | # `{{ input }}.story.tsx` 33 | 34 | ```jsx 35 | import React from 'react'; 36 | import { storiesOf } from '@storybook/react'; 37 | import {{ input }} from './{{input}}' 38 | 39 | storiesOf("templates", module) 40 | .add("{{input}}", () => <{{ input }} />); 41 | ``` 42 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import "@storybook/addon-knobs/register"; 2 | import "@storybook/addon-actions/register"; 3 | import "@storybook/addon-viewport/register"; 4 | -------------------------------------------------------------------------------- /.storybook/assets/AntDesign.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/AntDesign.ttf -------------------------------------------------------------------------------- /.storybook/assets/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/Entypo.ttf -------------------------------------------------------------------------------- /.storybook/assets/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/EvilIcons.ttf -------------------------------------------------------------------------------- /.storybook/assets/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/Feather.ttf -------------------------------------------------------------------------------- /.storybook/assets/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/FontAwesome.ttf -------------------------------------------------------------------------------- /.storybook/assets/FontAwesome5_Brands.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/FontAwesome5_Brands.ttf -------------------------------------------------------------------------------- /.storybook/assets/FontAwesome5_Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/FontAwesome5_Regular.ttf -------------------------------------------------------------------------------- /.storybook/assets/FontAwesome5_Solid.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/FontAwesome5_Solid.ttf -------------------------------------------------------------------------------- /.storybook/assets/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/Foundation.ttf -------------------------------------------------------------------------------- /.storybook/assets/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/Ionicons.ttf -------------------------------------------------------------------------------- /.storybook/assets/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /.storybook/assets/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/.storybook/assets/MaterialIcons.ttf -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure, addParameters } from "@storybook/react"; 2 | import { INITIAL_VIEWPORTS } from "@storybook/addon-viewport"; 3 | function loadStories() { 4 | const req = require.context("../src", true, /\.story\.tsx?$/); 5 | req.keys().forEach(story => req(story)); 6 | } 7 | 8 | addParameters({ 9 | viewport: { 10 | viewports: INITIAL_VIEWPORTS, 11 | defaultViewport: "iphone5" 12 | }, 13 | options: { 14 | addonPanelInRight: true 15 | } 16 | }); 17 | 18 | configure(loadStories, module); 19 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 5 | 9 | 39 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const threadLoader = require("thread-loader"); 3 | const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); 4 | 5 | const jsWorkerCommonOptions = { 6 | workers: 2, 7 | workerParallelJobs: 50, 8 | poolParallelJobs: 50 9 | }; 10 | 11 | const babelWorkerOptions = { 12 | ...jsWorkerCommonOptions, 13 | name: "babel-pool" 14 | }; 15 | 16 | const tsWorkerOptions = { 17 | ...jsWorkerCommonOptions, 18 | name: "ts-pool" 19 | }; 20 | 21 | module.exports = ({ config, mode }) => { 22 | if (mode !== "PRODUCTION") { 23 | threadLoader.warmup(babelWorkerOptions, ["babel-loader"]); 24 | threadLoader.warmup(tsWorkerOptions, ["babel-loader"]); 25 | } 26 | config.module.rules.push({ 27 | test: /\.tsx?$/, 28 | exclude: /node_modules/, 29 | use: [ 30 | { loader: "cache-loader" }, 31 | { loader: "thread-loader", options: tsWorkerOptions }, 32 | { 33 | loader: "babel-loader", 34 | options: { 35 | presets: ["module:metro-react-native-babel-preset"] 36 | } 37 | } 38 | ] 39 | }); 40 | 41 | config.module.rules.push({ 42 | test: /\.jsx?$/, 43 | include: [ 44 | path.resolve(__dirname, "../node_modules/react-native"), 45 | path.resolve(__dirname, "../node_modules/react-native-paper"), 46 | path.resolve(__dirname, "../node_modules/react-native-safe-area-view"), 47 | path.resolve(__dirname, "../node_modules/react-native-vector-icons"), 48 | path.resolve(__dirname, "../node_modules/@expo/vector-icons"), 49 | path.resolve(__dirname, "../node_modules/react-native-ratings"), 50 | path.resolve(__dirname, "../node_modules/react-native-status-bar-height") 51 | ], 52 | use: [ 53 | { loader: "cache-loader" }, 54 | { loader: "thread-loader", options: babelWorkerOptions }, 55 | { 56 | loader: "babel-loader?cacheDirectory?true", 57 | options: { 58 | presets: [ 59 | "module:metro-react-native-babel-preset", 60 | "@babel/preset-flow" 61 | ] 62 | } 63 | } 64 | ] 65 | }); 66 | // convert react-native to react-native-web for storybook 67 | config.resolve.alias["react-native$"] = require.resolve("react-native-web"); 68 | 69 | config.resolve.alias["@expo/vector-icons"] = path.resolve( 70 | __dirname, 71 | "../node_modules/react-native-vector-icons" 72 | ); 73 | 74 | // inlcude .ts and .tsx files 75 | config.resolve.extensions.push(".ts", ".tsx"); 76 | return config; 77 | }; 78 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } 4 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /@types/react-navigation.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-navigation" { 2 | function createAppContainer(options: any): any; 3 | function createSwitchNavigator(options: any): any; 4 | function createStackNavigator(options: any): any; 5 | function createBottomTabNavigator(options: any): any; 6 | } 7 | -------------------------------------------------------------------------------- /App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Platform, StatusBar, StyleSheet, View } from 'react-native'; 3 | import { AppLoading } from 'expo'; 4 | import { Asset } from 'expo-asset'; 5 | import * as Font from 'expo-font'; 6 | import * as Icon from '@expo/vector-icons'; 7 | import { Provider } from 'react-redux'; 8 | import { ActionSheetProvider } from '@expo/react-native-action-sheet'; 9 | import { PersistGate } from 'redux-persist/integration/react'; 10 | import { store, persistor } from './src/store'; 11 | import AppNavigator from './src/navigation/AppNavigator'; 12 | import { RobotDev, RobotProd } from './src/assets/images'; 13 | 14 | const styles = StyleSheet.create({ 15 | container: { 16 | flex: 1, 17 | backgroundColor: '#fff', 18 | }, 19 | }); 20 | 21 | interface Props { 22 | skipLoadingScreen?: boolean; 23 | } 24 | 25 | export default class App extends React.Component { 26 | public state = { 27 | isLoadingComplete: false, 28 | }; 29 | 30 | public loadResourcesAsync = async () => { 31 | return Promise.all([ 32 | Asset.loadAsync([RobotDev, RobotProd]), 33 | Font.loadAsync({ 34 | // This is the font that we are using for our tab bar 35 | ...Icon.Ionicons.font, 36 | // We include SpaceMono because we use it in HomeScreen.js. Feel free 37 | // to remove this if you are not using it in your app 38 | }), 39 | ]); 40 | }; 41 | 42 | public handleLoadingError = (error: Error) => { 43 | // In this case, you might want to report the error to your error 44 | // reporting service, for example Sentry 45 | console.warn(error); 46 | }; 47 | 48 | public handleFinishLoading = () => { 49 | this.setState({ isLoadingComplete: true }); 50 | }; 51 | 52 | public render(): JSX.Element { 53 | const { isLoadingComplete } = this.state; 54 | const { skipLoadingScreen } = this.props; 55 | if (!isLoadingComplete && !skipLoadingScreen) { 56 | return ( 57 | 63 | ); 64 | } 65 | return ( 66 | 67 | } persistor={persistor}> 68 | 69 | 70 | {Platform.OS === 'ios' && } 71 | 72 | 73 | 74 | 75 | 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2019 Naturalclar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # expo-typescript-starter 2 | 3 | [![CircleCI](https://circleci.com/gh/Naturalclar/expo-typescript-starter.svg?style=shield)](https://circleci.com/gh/Naturalclar/expo-typescript-starter) 4 | 5 | This is a boilerplate for [expo]() project with [typescript]() integration. 6 | 7 | Storybook can be viewed [here](https://expo-storybook-web-example.naturalclar.now.sh) 8 | 9 | ## Tech Stack 10 | 11 | - [Expo](https://expo.io/) ([React-Native](https://facebook.github.io/react-native/)) 12 | - [TypeScript](https://www.typescriptlang.org/) 13 | - [Redux](https://redux.js.org/) 14 | - [Storybook](https://storybook.js.org/) ([React-Native for Web](https://github.com/necolas/react-native-web)) 15 | - [eslint](https://eslint.org/) 16 | - [prettier](https://prettier.io/) 17 | - [klank](https://github.com/Naturalclar/klank) 18 | 19 | ## Component Libraries 20 | 21 | - [React-Native-Paper](https://reactnativepaper.com/) 22 | 23 | ## Getting started 24 | 25 | ### Clone the repository 26 | 27 | ```sh 28 | git clone https://github.com/Naturalclar/expo-typescript-starter.git 29 | cd expo-typescript-starter 30 | ``` 31 | 32 | ### Install the dependencies 33 | 34 | ```sh 35 | yarn 36 | ``` 37 | 38 | ### Storybook 39 | 40 | This project utilizes [Storybook](https://storybook.js.org/) with [react-native-web]() to easily implement component without the need to launch the emulator. 41 | 42 | Implementing screen components this way is much easier than implementing them through an emulator, as the loading time is much faster. 43 | 44 | You can view the storybook by running 45 | 46 | ```sh 47 | yarn storybook 48 | ``` 49 | -------------------------------------------------------------------------------- /__tests__/RoundButton.test.tsx: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import renderer from 'react-test-renderer'; 4 | 5 | import { RoundButton } from '../src/atoms'; 6 | 7 | describe('RoundButton snapshot', () => { 8 | it('renders the loading screen', async () => { 9 | const tree = renderer 10 | .create( {}} />) 11 | .toJSON(); 12 | expect(tree).toMatchSnapshot(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/RoundButton.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`RoundButton snapshot renders the loading screen 1`] = ` 4 | 25 | 32 | Hello World! 33 | 34 | 35 | `; 36 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "react-native-typescript", 4 | "slug": "react-native-typescript", 5 | "privacy": "public", 6 | "platforms": [ 7 | "ios", 8 | "android" 9 | ], 10 | "version": "1.0.0", 11 | "orientation": "portrait", 12 | "icon": "./src/assets/images/icon.png", 13 | "splash": { 14 | "image": "./src/assets/images/splash.png", 15 | "resizeMode": "contain", 16 | "backgroundColor": "#ffffff" 17 | }, 18 | "updates": { 19 | "fallbackToCacheTimeout": 0 20 | }, 21 | "assetBundlePatterns": [ 22 | "**/*" 23 | ], 24 | "ios": { 25 | "supportsTablet": true 26 | }, 27 | "description": "Template for expo project with TS, Storybook, Reg-Suit" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /ios/.expo/packager-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "devToolsPort": 19002 3 | } -------------------------------------------------------------------------------- /ios/.expo/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "hostType": "lan", 3 | "lanType": "ip", 4 | "dev": true, 5 | "minify": false, 6 | "urlRandomness": null 7 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "expo-typescript-starter", 3 | "version": "0.1.0", 4 | "description": "Template for expo project with TS, Storybook, Reg-Suit", 5 | "repository": "https://github.com/Naturalclar/expo-typescript-starter.git", 6 | "license": "MIT", 7 | "author": "Jesse Katsumata ", 8 | "main": "node_modules/expo/AppEntry.js", 9 | "scripts": { 10 | "android": "expo start --android", 11 | "build": "yarn storybook:build -o public", 12 | "eject": "expo eject", 13 | "ios": "expo start --ios", 14 | "lint": "eslint . --ext '.ts, .tsx'", 15 | "new": "scaffdog generate", 16 | "reg-suit": "reg-suit run", 17 | "start": "expo start", 18 | "storybook": "start-storybook -p 9001 -c .storybook -s .storybook/assets", 19 | "storybook:build": "build-storybook -c .storybook -s .storybook/assets", 20 | "storycap:all": "rm -rf ./__screenshots__ && yarn storycap --serverCmd 'yarn storybook --ci' --viewport '414x736' --serverTimeout '200000'", 21 | "test": "node ./node_modules/jest/bin/jest.js --watchAll", 22 | "type-check": "tsc --noEmit" 23 | }, 24 | "jest": { 25 | "preset": "jest-expo" 26 | }, 27 | "dependencies": { 28 | "@expo/react-native-action-sheet": "^3.7.0", 29 | "@expo/samples": "^3.0.3", 30 | "@expo/vector-icons": "^10.0.0", 31 | "expo": "^39.0.0", 32 | "expo-asset": "~8.2.0", 33 | "expo-font": "~8.3.0", 34 | "expo-web-browser": "^8.5.0", 35 | "react": "16.13.1", 36 | "react-native": "https://github.com/expo/react-native/archive/sdk-39.0.3.tar.gz", 37 | "react-native-gesture-handler": "~1.7.0", 38 | "react-native-paper": "^4.5.0", 39 | "react-native-reanimated": "~2.10.0", 40 | "react-navigation": "^4.4.3", 41 | "react-redux": "^7.2.0", 42 | "redux": "^4.0.5", 43 | "redux-persist": "^6.0.0", 44 | "redux-thunk": "^2.3.0" 45 | }, 46 | "devDependencies": { 47 | "@octokit/rest": "^16.16.0", 48 | "@react-native-community/eslint-config": "^2.0.0", 49 | "@storybook/addon-actions": "^6.0.28", 50 | "@storybook/addon-knobs": "^6.0.28", 51 | "@storybook/addon-viewport": "^6.0.28", 52 | "@storybook/react": "^6.0.28", 53 | "@types/expo": "^32.0.13", 54 | "@types/expo__vector-icons": "9.0.1", 55 | "@types/jest": "^25.2.2", 56 | "@types/react": "~16.9.35", 57 | "@types/react-native": "~0.63.2", 58 | "@types/react-redux": "^7.1.9", 59 | "@types/react-test-renderer": "^16.9.2", 60 | "@types/redux-logger": "^3.0.7", 61 | "@types/redux-persist": "^4.3.1", 62 | "@types/redux-thunk": "^2.1.0", 63 | "babel-loader": "^8.1.0", 64 | "babel-preset-expo": "^8.3.0", 65 | "cache-loader": "^4.1.0", 66 | "eslint": "^7.12.1", 67 | "eslint-plugin-prettier": "^3.3.1", 68 | "fork-ts-checker-webpack-plugin": "^5.2.1", 69 | "jest-expo": "^39.0.0", 70 | "metro-react-native-babel-preset": "0.63.0", 71 | "node-fetch": "^2.6.7", 72 | "prettier": "^2.1.2", 73 | "react-art": "16.13.1", 74 | "react-dom": "16.13.1", 75 | "react-native-vector-icons": "^6.5.0", 76 | "react-native-web": "~0.13.7", 77 | "react-test-renderer": "^16.9.0", 78 | "redux-logger": "^3.0.6", 79 | "reg-keygen-git-hash-plugin": "^0.10.8", 80 | "reg-notify-github-plugin": "^0.10.8", 81 | "reg-publish-s3-plugin": "^0.10.8", 82 | "reg-suit": "^0.10.8", 83 | "scaffdog": "^0.3.0", 84 | "storycap": "^3.0.1", 85 | "thread-loader": "^2.1.3", 86 | "ts-jest": "^25.3.1", 87 | "ts-loader": "^7.0.4", 88 | "typescript": "~3.9.2", 89 | "vercel": "^20.1.2" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /regconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "core": { 3 | "workingDir": ".reg", 4 | "actualDir": "__screenshots__", 5 | "thresholdRate": 0, 6 | "addIgnore": true, 7 | "ximgdiff": { 8 | "invocationType": "client" 9 | } 10 | }, 11 | "plugins": { 12 | "reg-keygen-git-hash-plugin": {}, 13 | "reg-notify-github-plugin": { 14 | "clientId": "MzQ3MDA2MDU11E+tKMjXLaksSC1OLsosKNEtLkksKkkt0jc0N7U0NrPU90ssKS1KzEnOSSwCAA==" 15 | }, 16 | "reg-publish-s3-plugin": { 17 | "bucketName": "reg-publish-bucket-77f298c3-cecd-4e1c-bd6e-fec5f3f843be" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/report-artifact: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const fetch = require("node-fetch"); 3 | const octokit = require("@octokit/rest")(); 4 | 5 | const { 6 | CIRCLE_PULL_REQUEST, 7 | CIRCLE_BUILD_NUM, 8 | GITHUB_API_TOKEN, 9 | CIRCLE_CI_API_TOKEN 10 | } = process.env; 11 | 12 | const [targetPath, messagePrefix] = process.argv.slice(2); 13 | 14 | if (!CIRCLE_PULL_REQUEST) { 15 | console.error("Cannot find pull request ID"); 16 | return; 17 | } 18 | if (!CIRCLE_BUILD_NUM) { 19 | console.error("Cannot find build number"); 20 | return; 21 | } 22 | if (!GITHUB_API_TOKEN) { 23 | console.error("The environment variable GITHUB_API_TOKEN must be required"); 24 | return; 25 | } 26 | if (!CIRCLE_CI_API_TOKEN) { 27 | console.error( 28 | "The environment variable CIRCLE_CI_API_TOKEN must be required" 29 | ); 30 | } 31 | 32 | const segments = CIRCLE_PULL_REQUEST.split("/"); 33 | const pullRequestId = segments[segments.length - 1]; 34 | 35 | fetch( 36 | `https://circleci.com/api/v1.1/project/github/Naturalclar/expo-typescript-starter/${CIRCLE_BUILD_NUM}/artifacts?circle-token=${CIRCLE_CI_API_TOKEN}` 37 | ) 38 | .then(res => res.json()) 39 | .then( 40 | artifacts => 41 | artifacts.filter(artifact => artifact.path.includes(targetPath))[0] 42 | ) 43 | .then(artifact => { 44 | if (!artifact) { 45 | throw new Error(`Cannot find any artifacts with: ${targetPath}`); 46 | } 47 | 48 | octokit.authenticate({ 49 | type: "token", 50 | token: GITHUB_API_TOKEN 51 | }); 52 | return octokit.issues.createComment({ 53 | owner: "Naturalclar", 54 | repo: "expo-typescript-starter", 55 | number: pullRequestId, 56 | body: `${messagePrefix}:\n${artifact.url}` 57 | }); 58 | }) 59 | .then(console.log) 60 | .catch(console.error); 61 | -------------------------------------------------------------------------------- /src/action/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/src/action/index.ts -------------------------------------------------------------------------------- /src/assets/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { "global-require": 0 } 3 | }; 4 | -------------------------------------------------------------------------------- /src/assets/fonts/SpaceMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/src/assets/fonts/SpaceMono-Regular.ttf -------------------------------------------------------------------------------- /src/assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/src/assets/images/icon.png -------------------------------------------------------------------------------- /src/assets/images/index.ts: -------------------------------------------------------------------------------- 1 | export const Icon = require('./icon.png'); 2 | export const RobotDev = require('./robot-dev.png'); 3 | export const RobotProd = require('./robot-prod.png'); 4 | export const Splash = require('./splash.png'); 5 | -------------------------------------------------------------------------------- /src/assets/images/robot-dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/src/assets/images/robot-dev.png -------------------------------------------------------------------------------- /src/assets/images/robot-prod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/src/assets/images/robot-prod.png -------------------------------------------------------------------------------- /src/assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naturalclar/expo-typescript-starter/4c72b2ebfbc757b9967aaf537f3a0a50885e09cd/src/assets/images/splash.png -------------------------------------------------------------------------------- /src/atoms/ListItem.story.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { text } from '@storybook/addon-knobs'; 4 | import { action } from '@storybook/addon-actions'; 5 | import ListItem from './ListItem'; 6 | import { StorybookContainer } from '../templates/StoryContainer'; 7 | 8 | storiesOf('atoms', module) 9 | .addDecorator(StorybookContainer) 10 | .add('ListItem', () => ( 11 | 16 | )); 17 | -------------------------------------------------------------------------------- /src/atoms/ListItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; 3 | 4 | const styles = StyleSheet.create({ 5 | container: { 6 | flexDirection: 'row', 7 | }, 8 | name: { fontWeight: 'bold' }, 9 | content: {}, 10 | avatar: { 11 | width: 40, 12 | height: 40, 13 | borderRadius: 20, 14 | backgroundColor: 'blue', 15 | marginRight: 8, 16 | }, 17 | }); 18 | 19 | type Props = { 20 | onPress: () => void; 21 | name: string; 22 | content: string; 23 | }; 24 | 25 | const ListItem: React.FC = ({ 26 | onPress, 27 | name, 28 | content, 29 | }: Props): JSX.Element => ( 30 | 31 | 32 | 33 | 34 | {name} 35 | {content} 36 | 37 | 38 | 39 | ); 40 | 41 | export default ListItem; 42 | -------------------------------------------------------------------------------- /src/atoms/button/HelloWorld.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { View, Text } from 'react-native'; 4 | 5 | storiesOf('atoms', module).add('Hello World', () => ( 6 | 7 | Hello Typescript! 8 | 9 | )); 10 | -------------------------------------------------------------------------------- /src/atoms/button/HelloWorld.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Text } from 'react-native'; 3 | 4 | interface Props { 5 | children: React.ReactChild; 6 | } 7 | 8 | const Button = ({ children }: Props) => ( 9 | 10 | {children} 11 | 12 | ); 13 | 14 | export default Button; 15 | -------------------------------------------------------------------------------- /src/atoms/button/IconButton.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { action } from '@storybook/addon-actions'; 4 | import { text, number } from '@storybook/addon-knobs'; 5 | import IconButton from './IconButton'; 6 | import { StorybookContainer } from '../../templates/StoryContainer'; 7 | 8 | storiesOf('atoms', module) 9 | .addDecorator(StorybookContainer) 10 | .add('IconButton', () => ( 11 | 17 | )); 18 | -------------------------------------------------------------------------------- /src/atoms/button/IconButton.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { StyleSheet, TouchableOpacity } from 'react-native'; 3 | // @ts-ignore Storybook works by this import, but types are not provided 4 | import Icon from '@expo/vector-icons/MaterialIcons'; 5 | 6 | const styles = StyleSheet.create({ 7 | container: { 8 | justifyContent: 'center', 9 | alignItems: 'center', 10 | }, 11 | }); 12 | 13 | interface Props { 14 | icon: string; 15 | onPress: () => void; 16 | color?: string; 17 | size?: number; 18 | } 19 | 20 | const IconButton: React.FC = ({ 21 | icon, 22 | onPress, 23 | color = 'gray', 24 | size = 20, 25 | }: Props): JSX.Element => ( 26 | 27 | 28 | 29 | ); 30 | 31 | export default IconButton; 32 | -------------------------------------------------------------------------------- /src/atoms/button/RoundButton.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { View } from 'react-native'; 4 | import { text } from '@storybook/addon-knobs'; 5 | import { action } from '@storybook/addon-actions'; 6 | import RoundButton from './RoundButton'; 7 | import { StorybookContainer } from '../../templates/StoryContainer'; 8 | 9 | storiesOf('atoms', module) 10 | .addDecorator(StorybookContainer) 11 | .add('RoundButton', () => ( 12 | 13 | 18 | 19 | )); 20 | -------------------------------------------------------------------------------- /src/atoms/button/RoundButton.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Text, StyleSheet, TouchableOpacity } from 'react-native'; 3 | 4 | const styles = StyleSheet.create({ 5 | container: { 6 | borderRadius: 100, 7 | paddingVertical: 8, 8 | paddingHorizontal: 12, 9 | justifyContent: 'center', 10 | alignItems: 'center', 11 | }, 12 | text: { 13 | color: 'white', 14 | }, 15 | }); 16 | 17 | interface Props { 18 | onPress: () => void; 19 | color?: string; 20 | label: string; 21 | } 22 | 23 | const RoundButton: React.FC = ({ 24 | onPress, 25 | label, 26 | color = 'dodgerblue', 27 | }: Props): JSX.Element => ( 28 | 32 | {label} 33 | 34 | ); 35 | 36 | export default RoundButton; 37 | -------------------------------------------------------------------------------- /src/atoms/button/index.ts: -------------------------------------------------------------------------------- 1 | export { default as RoundButton } from './RoundButton'; 2 | export { default as IconButton } from './IconButton'; 3 | -------------------------------------------------------------------------------- /src/atoms/index.ts: -------------------------------------------------------------------------------- 1 | export * from './button'; 2 | -------------------------------------------------------------------------------- /src/components/StyledText.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Text, TextStyle } from 'react-native'; 3 | 4 | interface Props { 5 | style?: TextStyle; 6 | children: React.ReactChild; 7 | } 8 | 9 | export const MonoText = ({ style, ...rest }: Props) => { 10 | return ; 11 | }; 12 | -------------------------------------------------------------------------------- /src/components/TabBarIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import * as Icon from '@expo/vector-icons'; 3 | import { StyleSheet } from 'react-native'; 4 | import Colors from '../constants/Colors'; 5 | 6 | interface Props { 7 | name: string; 8 | focused: boolean; 9 | } 10 | 11 | const styles = StyleSheet.create({ 12 | icon:{ marginBottom: -3 }, 13 | }); 14 | 15 | const TabBarIcon = ({ name, focused }: Props) => ( 16 | 22 | ); 23 | 24 | export default TabBarIcon; 25 | -------------------------------------------------------------------------------- /src/components/__tests__/StyledText.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import renderer from 'react-test-renderer'; 3 | import 'react-native'; 4 | import { MonoText } from '../StyledText'; 5 | 6 | it('renders correctly', () => { 7 | const tree = renderer.create(Snapshot test!).toJSON(); 8 | 9 | expect(tree).toMatchSnapshot(); 10 | }); 11 | -------------------------------------------------------------------------------- /src/components/__tests__/__snapshots__/StyledText.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`renders correctly 1`] = ` 4 | 11 | Snapshot test! 12 | 13 | `; 14 | -------------------------------------------------------------------------------- /src/constants/Colors.ts: -------------------------------------------------------------------------------- 1 | const tintColor = '#2f95dc'; 2 | 3 | export default { 4 | tintColor, 5 | tabIconDefault: '#ccc', 6 | tabIconSelected: tintColor, 7 | tabBar: '#fefefe', 8 | errorBackground: 'red', 9 | errorText: '#fff', 10 | warningBackground: '#EAEB5E', 11 | warningText: '#666804', 12 | noticeBackground: tintColor, 13 | noticeText: '#fff', 14 | }; 15 | -------------------------------------------------------------------------------- /src/constants/Layout.ts: -------------------------------------------------------------------------------- 1 | import { Dimensions } from 'react-native'; 2 | 3 | const { width, height } = Dimensions.get('window'); 4 | 5 | export default { 6 | window: { 7 | width, 8 | height, 9 | }, 10 | isSmallDevice: width < 375, 11 | }; 12 | -------------------------------------------------------------------------------- /src/molecules/DialogCloseButton.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { action } from '@storybook/addon-actions'; 4 | import DialogCloseButton from './DialogCloseButton'; 5 | 6 | storiesOf('molecules', module).add('DialogCloseButton', () => ( 7 | 8 | )); 9 | -------------------------------------------------------------------------------- /src/molecules/DialogCloseButton.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import IconButton from '../atoms/button/IconButton'; 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | position: 'absolute', 8 | top: 16, 9 | right: 16, 10 | zIndex: 2, 11 | }, 12 | }); 13 | 14 | interface Props { 15 | onPress: () => void; 16 | } 17 | 18 | const DialogCloseButton: React.FC = ({ 19 | onPress, 20 | }: Props): JSX.Element => ( 21 | 22 | 23 | 24 | ); 25 | 26 | export default DialogCloseButton; 27 | -------------------------------------------------------------------------------- /src/molecules/DismissableDialog.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { View, StyleSheet } from 'react-native'; 4 | import { action } from '@storybook/addon-actions'; 5 | import { text } from '@storybook/addon-knobs'; 6 | import DismissableDialog from './DismissableDialog'; 7 | 8 | const styles = StyleSheet.create({ 9 | container: { 10 | flex: 1, 11 | }, 12 | component: { flex: 1, justifyContent: 'center', alignItems: 'center' }, 13 | }); 14 | 15 | storiesOf('molecules', module) 16 | .addDecorator(story => ( 17 | 18 | {story()} 19 | 20 | )) 21 | .add('DismissableDialog', () => ( 22 | 29 | )); 30 | -------------------------------------------------------------------------------- /src/molecules/DismissableDialog.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, StyleSheet, Text } from 'react-native'; 3 | import DialogCloseButton from './DialogCloseButton'; 4 | import { RoundButton } from '../atoms'; 5 | import IconText from './IconText'; 6 | 7 | const styles = StyleSheet.create({ 8 | modal: { 9 | ...StyleSheet.absoluteFillObject, 10 | backgroundColor: 'rgba(0,0,0,.4)', 11 | justifyContent: 'center', 12 | alignItems: 'center', 13 | padding: 24, 14 | }, 15 | container: { 16 | padding: 24, 17 | borderRadius: 10, 18 | backgroundColor: 'white', 19 | width: '100%', 20 | }, 21 | main: { 22 | flex: 1, 23 | alignItems: 'center', 24 | }, 25 | titleContainer: { 26 | marginBottom: 16, 27 | }, 28 | titleText: { 29 | fontSize: 18, 30 | }, 31 | bodyContainer: { 32 | marginBottom: 16, 33 | }, 34 | bodyText: { 35 | fontSize: 14, 36 | color: 'gray', 37 | }, 38 | checkList: { 39 | marginBottom: 16, 40 | }, 41 | }); 42 | 43 | interface Props { 44 | title: string; 45 | body: string; 46 | onPressOk: () => void; 47 | onRequestClose: () => void; 48 | buttonText?: string; 49 | } 50 | 51 | const DismissableDialog: React.FC = ({ 52 | title, 53 | body, 54 | onPressOk, 55 | onRequestClose, 56 | buttonText = 'ok', 57 | }: Props): JSX.Element => ( 58 | 59 | 60 | 61 | 62 | 63 | {title} 64 | 65 | 66 | {body} 67 | 68 | 69 | 70 | Check 1 71 | 72 | 73 | Check 2 74 | 75 | 76 | Check 3 77 | 78 | 79 | 80 | 81 | 82 | 83 | ); 84 | 85 | export default DismissableDialog; 86 | -------------------------------------------------------------------------------- /src/molecules/IconText.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { text } from '@storybook/addon-knobs'; 4 | import IconText from './IconText'; 5 | import { StorybookContainer } from '../templates/StoryContainer'; 6 | 7 | storiesOf('molecules', module) 8 | .addDecorator(StorybookContainer) 9 | .add('IconText', () => ( 10 | 11 | {text('children', 'Take it easy')} 12 | 13 | )); 14 | -------------------------------------------------------------------------------- /src/molecules/IconText.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Text, StyleSheet } from 'react-native'; 3 | // @ts-ignore 4 | import Icon from '@expo/vector-icons/MaterialIcons'; 5 | 6 | const styles = StyleSheet.create({ 7 | container: { 8 | flexDirection: 'row', 9 | alignItems: 'center', 10 | }, 11 | iconContainer: { 12 | marginRight: 4, 13 | justifyContent: 'center', 14 | alignItems: 'center', 15 | }, 16 | }); 17 | 18 | interface Props { 19 | icon: string; 20 | children: string; 21 | iconColor?: string; 22 | textColor?: string; 23 | } 24 | 25 | const IconText: React.FC = ({ 26 | icon, 27 | children, 28 | iconColor = 'dodgerBlue', 29 | textColor = 'gray', 30 | }: Props): JSX.Element => ( 31 | 32 | 33 | 34 | 35 | {children} 36 | 37 | ); 38 | 39 | export default IconText; 40 | -------------------------------------------------------------------------------- /src/navigation/AppNavigator.tsx: -------------------------------------------------------------------------------- 1 | import { createAppContainer, createSwitchNavigator } from 'react-navigation'; 2 | 3 | import MainTabNavigator from './MainTabNavigator'; 4 | 5 | export default createAppContainer( 6 | createSwitchNavigator({ 7 | // You could add another route here for authentication. 8 | // Read more at https://reactnavigation.org/docs/en/auth-flow.html 9 | Main: MainTabNavigator, 10 | }) 11 | ); 12 | -------------------------------------------------------------------------------- /src/navigation/MainTabNavigator.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Platform } from 'react-native'; 3 | import { 4 | createStackNavigator, 5 | createBottomTabNavigator, 6 | } from 'react-navigation'; 7 | 8 | import TabBarIcon from '../components/TabBarIcon'; 9 | import HomeScreen from '../screens/HomeScreen'; 10 | import SettingsScreen from '../screens/SettingsScreen'; 11 | import MyPageScreen from '../screens/MyPageScreen'; 12 | 13 | interface TabProps { 14 | focused: boolean; 15 | } 16 | 17 | const HomeStack = createStackNavigator({ 18 | Home: HomeScreen, 19 | }); 20 | 21 | HomeStack.navigationOptions = { 22 | tabBarLabel: 'Home', 23 | tabBarIcon: ({ focused }: TabProps) => ( 24 | 28 | ), 29 | }; 30 | 31 | const SettingsStack = createStackNavigator({ 32 | Settings: SettingsScreen, 33 | }); 34 | 35 | SettingsStack.navigationOptions = { 36 | tabBarLabel: 'Notifications', 37 | tabBarIcon: ({ focused }: TabProps) => ( 38 | 42 | ), 43 | }; 44 | 45 | const MyPageStack = createStackNavigator({ 46 | MyPage: MyPageScreen, 47 | }); 48 | 49 | MyPageStack.navigationOptions = { 50 | tabBarLabel: 'MyPage', 51 | tabBarIcon: ({ focused }: TabProps) => ( 52 | 56 | ), 57 | }; 58 | 59 | export default createBottomTabNavigator({ 60 | HomeStack, 61 | SettingsStack, 62 | MyPageStack, 63 | }); 64 | -------------------------------------------------------------------------------- /src/organisms/Appbar.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { storiesOf } from '@storybook/react'; 3 | import { action } from '@storybook/addon-actions'; 4 | import { text } from '@storybook/addon-knobs'; 5 | import Appbar from './Appbar'; 6 | 7 | storiesOf('React Native Paper', module).add('Appbar', () => ( 8 | 14 | )); 15 | -------------------------------------------------------------------------------- /src/organisms/Appbar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet } from 'react-native'; 3 | import { Appbar } from 'react-native-paper'; 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | position: 'absolute', 8 | top: 0, 9 | right: 0, 10 | left: 0, 11 | }, 12 | }); 13 | 14 | interface Props { 15 | title: string; 16 | subtitle?: string; 17 | onPressBack: () => void; 18 | onPressAction: () => void; 19 | } 20 | 21 | const AppbarExample: React.FC = ({ 22 | title, 23 | subtitle = '', 24 | onPressBack, 25 | onPressAction, 26 | }: Props): JSX.Element => ( 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | 34 | export default AppbarExample; 35 | -------------------------------------------------------------------------------- /src/reducer/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | import { combineReducers } from 'redux'; 3 | import { persistReducer } from 'redux-persist'; 4 | import storage from 'redux-persist/lib/storage'; 5 | 6 | export default combineReducers({ 7 | foo: (state = {}, action: any) => { 8 | return state; 9 | }, 10 | bar: persistReducer({ key: 'bar', storage }, (state = {}, action: any) => { 11 | return state; 12 | }), 13 | }); 14 | -------------------------------------------------------------------------------- /src/screens/HomeScreen.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Image, 4 | Platform, 5 | ScrollView, 6 | StyleSheet, 7 | Text, 8 | TouchableOpacity, 9 | View, 10 | } from 'react-native'; 11 | import { WebBrowser } from 'expo'; 12 | 13 | import { MonoText } from '../components/StyledText'; 14 | import { RobotDev, RobotProd } from '../assets/images'; 15 | 16 | const styles = StyleSheet.create({ 17 | container: { 18 | flex: 1, 19 | backgroundColor: '#fff', 20 | }, 21 | developmentModeText: { 22 | marginBottom: 20, 23 | color: 'rgba(0,0,0,0.4)', 24 | fontSize: 14, 25 | lineHeight: 19, 26 | textAlign: 'center', 27 | }, 28 | contentContainer: { 29 | paddingTop: 30, 30 | }, 31 | welcomeContainer: { 32 | alignItems: 'center', 33 | marginTop: 10, 34 | marginBottom: 20, 35 | }, 36 | welcomeImage: { 37 | width: 100, 38 | height: 80, 39 | resizeMode: 'contain', 40 | marginTop: 3, 41 | marginLeft: -10, 42 | }, 43 | getStartedContainer: { 44 | alignItems: 'center', 45 | marginHorizontal: 50, 46 | }, 47 | homeScreenFilename: { 48 | marginVertical: 7, 49 | }, 50 | codeHighlightText: { 51 | color: 'rgba(96,100,109, 0.8)', 52 | }, 53 | codeHighlightContainer: { 54 | backgroundColor: 'rgba(0,0,0,0.05)', 55 | borderRadius: 3, 56 | paddingHorizontal: 4, 57 | }, 58 | getStartedText: { 59 | fontSize: 17, 60 | color: 'rgba(96,100,109, 1)', 61 | lineHeight: 24, 62 | textAlign: 'center', 63 | }, 64 | tabBarInfoContainerAndroid: { 65 | position: 'absolute', 66 | bottom: 0, 67 | left: 0, 68 | right: 0, 69 | alignItems: 'center', 70 | backgroundColor: '#fbfbfb', 71 | paddingVertical: 20, 72 | elevation: 20, 73 | }, 74 | tabBarInfoContainerIos: { 75 | position: 'absolute', 76 | bottom: 0, 77 | left: 0, 78 | right: 0, 79 | alignItems: 'center', 80 | backgroundColor: '#fbfbfb', 81 | paddingVertical: 20, 82 | shadowColor: 'black', 83 | shadowOffset: { width: 0, height: -3 }, 84 | shadowOpacity: 0.1, 85 | shadowRadius: 3, 86 | }, 87 | tabBarInfoText: { 88 | fontSize: 17, 89 | color: 'rgba(96,100,109, 1)', 90 | textAlign: 'center', 91 | }, 92 | navigationFilename: { 93 | marginTop: 5, 94 | }, 95 | helpContainer: { 96 | marginTop: 15, 97 | alignItems: 'center', 98 | }, 99 | helpLink: { 100 | paddingVertical: 15, 101 | }, 102 | helpLinkText: { 103 | fontSize: 14, 104 | color: '#2e78b7', 105 | }, 106 | }); 107 | 108 | const handleLearnMorePress = (): void => { 109 | WebBrowser.openBrowserAsync( 110 | 'https://docs.expo.io/versions/latest/guides/development-mode' 111 | ); 112 | }; 113 | 114 | const handleHelpPress = (): void => { 115 | WebBrowser.openBrowserAsync( 116 | 'https://docs.expo.io/versions/latest/guides/up-and-running.html#can-t-see-your-changes' 117 | ); 118 | }; 119 | 120 | const maybeRenderDevelopmentModeWarning = (): JSX.Element => { 121 | if (__DEV__) { 122 | const learnMoreButton = ( 123 | 124 | Learn more 125 | 126 | ); 127 | 128 | return ( 129 | 130 | Development mode is enabled, your app will be slower but you can use 131 | useful development tools. 132 | {learnMoreButton} 133 | 134 | ); 135 | } 136 | return ( 137 | 138 | You are not in development mode, your app will run at full speed. 139 | 140 | ); 141 | }; 142 | 143 | const HomeScreen = (): JSX.Element => ( 144 | 145 | 149 | 150 | 154 | 155 | 156 | 157 | {maybeRenderDevelopmentModeWarning()} 158 | 159 | Get started by opening 160 | 161 | 164 | 165 | screens/HomeScreen.js 166 | 167 | 168 | 169 | 170 | Change this text and your app will automatically reload. 171 | 172 | 173 | 174 | 175 | 176 | 177 | Help, it didn’t automatically reload! 178 | 179 | 180 | 181 | 182 | 183 | 190 | 191 | This is a tab bar. You can edit it in: 192 | 193 | 194 | 195 | 196 | navigation/MainTabNavigator.js 197 | 198 | 199 | 200 | 201 | ); 202 | 203 | HomeScreen.navigationOptions = { 204 | header: null, 205 | }; 206 | 207 | export default HomeScreen; 208 | -------------------------------------------------------------------------------- /src/screens/MyPageScreen.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Text, TouchableOpacity } from 'react-native'; 3 | import { connectActionSheet } from '@expo/react-native-action-sheet'; 4 | 5 | interface Props { 6 | showActionSheetWithOptions: ( 7 | options: any, 8 | buttonIndex: (index: number) => void 9 | ) => void; 10 | } 11 | 12 | const MyPageScreen = ({ showActionSheetWithOptions }: Props): JSX.Element => { 13 | const onOpenActionSheet = (): void => { 14 | const options = ['Foo', 'Bar', 'Cancel']; 15 | const okButtonIndex = 0; 16 | const destructionButtonIndex = 1; 17 | const cancelButtonIndex = 2; 18 | 19 | showActionSheetWithOptions( 20 | { 21 | options, 22 | cancelButtonIndex, 23 | }, 24 | buttonIndex => { 25 | switch (buttonIndex) { 26 | case cancelButtonIndex: 27 | break; 28 | case okButtonIndex: 29 | break; 30 | case destructionButtonIndex: 31 | break; 32 | default: 33 | break; 34 | } 35 | } 36 | ); 37 | }; 38 | 39 | return ( 40 | 41 | 42 | Hello World! 43 | 44 | 45 | ); 46 | }; 47 | 48 | MyPageScreen.navigationOptions = { 49 | title: 'MyPage', 50 | }; 51 | 52 | export default connectActionSheet(MyPageScreen); 53 | -------------------------------------------------------------------------------- /src/screens/SettingsScreen.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // @ts-ignore 3 | import { ExpoConfigView } from '@expo/samples'; 4 | 5 | const SettingsScreen = (): JSX.Element => ; 6 | 7 | SettingsScreen.navigationOptions = { 8 | title: 'app.json', 9 | }; 10 | 11 | export default SettingsScreen; 12 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import { persistStore } from 'redux-persist'; 3 | import thunk from 'redux-thunk'; 4 | import reduxLogger from 'redux-logger'; 5 | import reducer from '../reducer'; 6 | 7 | // development なら redux-loggerを入れる 8 | const logger = __DEV__ ? [reduxLogger] : []; 9 | 10 | const middlewares = applyMiddleware(thunk, ...logger); 11 | 12 | const initialState = {}; 13 | 14 | const store = createStore(reducer, initialState, middlewares); 15 | const persistor = persistStore(store); 16 | 17 | export { store, persistor }; 18 | -------------------------------------------------------------------------------- /src/templates/Modal.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { View, Text, StyleSheet } from 'react-native'; 3 | import { storiesOf } from '@storybook/react'; 4 | import { boolean } from '@storybook/addon-knobs'; 5 | 6 | import Modal from './Modal'; 7 | 8 | const styles = StyleSheet.create({ 9 | modalWindow: { 10 | backgroundColor: 'white', 11 | borderRadius: 10, 12 | height: 200, 13 | width: 200, 14 | justifyContent: 'center', 15 | alignItems: 'center', 16 | alignSelf: 'center', 17 | }, 18 | }); 19 | 20 | storiesOf('React Native Paper', module).add('Modal', () => ( 21 | 22 | 23 | Hello World! 24 | 25 | 26 | )); 27 | -------------------------------------------------------------------------------- /src/templates/Modal.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Modal } from 'react-native-paper'; 3 | 4 | interface Props { 5 | visible: boolean; 6 | children: React.ReactNode; 7 | } 8 | 9 | const ModalTemplate: React.FC = ({ 10 | visible, 11 | children, 12 | }: Props): JSX.Element => {children}; 13 | 14 | export default ModalTemplate; 15 | -------------------------------------------------------------------------------- /src/templates/StoryContainer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { StyleSheet, View, Text } from 'react-native'; 3 | 4 | const styles = StyleSheet.create({ 5 | container: { 6 | flex: 1, 7 | padding: 24, 8 | backgroundColor: 'aliceblue', 9 | }, 10 | component: { 11 | flex: 1, 12 | backgroundColor: 'white', 13 | }, 14 | }); 15 | 16 | export const StorybookContainer = (story: any) => ( 17 | 18 | {story()} 19 | Padding is here for clarity when displaying on storybook. 20 | This part will not be shown on the actual app. 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */, 5 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, 6 | "lib": [ 7 | "es2015" 8 | ] /* Specify library files to be included in the compilation. */, 9 | // "allowJs": true, /* Allow javascript files to be compiled. */ 10 | // "checkJs": true, /* Report errors in .js files. */ 11 | "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */, 12 | "skipLibCheck": true /* Avoid error that happens with @types/node and @types/react-native */, 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | // "outDir": "./", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "removeComments": true, /* Do not emit comments to output. */ 21 | // "noEmit": true, /* Do not emit outputs. */ 22 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 23 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 24 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 25 | 26 | /* Strict Type-Checking Options */ 27 | "strict": true /* Enable all strict type-checking options. */, 28 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 29 | // "strictNullChecks": true, /* Enable strict null checks. */ 30 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 31 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 32 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 33 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 34 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 35 | 36 | /* Additional Checks */ 37 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 38 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 39 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 40 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 41 | 42 | /* Module Resolution Options */ 43 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 44 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 45 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 46 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 47 | // "typeRoots": [], /* List of folders to include type definitions from. */ 48 | // "types": [], /* Type declaration files to be included in compilation. */ 49 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 50 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 51 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 52 | 53 | /* Source Map Options */ 54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 58 | 59 | /* Experimental Options */ 60 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 61 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "package.json", 6 | "use": "@now/static-build" 7 | } 8 | ] 9 | } 10 | --------------------------------------------------------------------------------