├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .prettierrc.js ├── .storybook ├── assets │ ├── AntDesign.ttf │ ├── Entypo.ttf │ ├── EvilIcons.ttf │ ├── Feather.ttf │ ├── FontAwesome.ttf │ ├── Ionicons.ttf │ ├── MaterialCommunityIcons.ttf │ └── MaterialIcons.ttf ├── main.js ├── manager.js ├── preview-head.html ├── preview.js ├── theme.js └── webpack.config.js ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── 0.5baeeca9.iframe.bundle.js ├── 0.fee418253491f34f1687.manager.bundle.js ├── 4.66dcec55.iframe.bundle.js ├── 4.66dcec55.iframe.bundle.js.LICENSE.txt ├── 4.66dcec55.iframe.bundle.js.map ├── 4.920ef856637ed265ddf6.manager.bundle.js ├── 4.920ef856637ed265ddf6.manager.bundle.js.LICENSE.txt ├── 5.2a7a0df7.iframe.bundle.js ├── 5.8b78b85b80910cb5a79f.manager.bundle.js ├── 5.8b78b85b80910cb5a79f.manager.bundle.js.LICENSE.txt ├── 6.30d57e8b.iframe.bundle.js ├── 6.30d57e8b.iframe.bundle.js.LICENSE.txt ├── 6.30d57e8b.iframe.bundle.js.map ├── 6.9a92a691c685a5dc4029.manager.bundle.js ├── 7.394152bb.iframe.bundle.js ├── 7.ccbf050e29ff2321f65b.manager.bundle.js ├── AntDesign.ttf ├── Entypo.ttf ├── EvilIcons.ttf ├── Feather.ttf ├── FontAwesome.ttf ├── Ionicons.ttf ├── MaterialCommunityIcons.ttf ├── MaterialIcons.ttf ├── favicon.ico ├── iframe.html ├── index.html ├── main.31d7c7422073e28fcb1d.manager.bundle.js ├── main.393ad775.iframe.bundle.js ├── runtime~main.22dddf64.iframe.bundle.js ├── runtime~main.5073734e2463b8bcc9e0.manager.bundle.js ├── vendors~main.8c6275b3e42f55ff6bbe.manager.bundle.js ├── vendors~main.8c6275b3e42f55ff6bbe.manager.bundle.js.LICENSE.txt ├── vendors~main.af429b2f.iframe.bundle.js ├── vendors~main.af429b2f.iframe.bundle.js.LICENSE.txt └── vendors~main.af429b2f.iframe.bundle.js.map ├── guides ├── Colors.stories.mdx ├── DesignRules.stories.mdx ├── GetStarted.stories.mdx └── Theme.stories.mdx ├── package.json ├── src ├── ActionButton │ ├── ActionButton.js │ ├── ActionButton.stories.mdx │ └── index.js ├── Avatar │ ├── Avatar.js │ ├── Avatar.stories.mdx │ └── index.js ├── Badge │ ├── Badge.js │ ├── Badge.stories.mdx │ └── index.js ├── Button │ ├── Button.js │ ├── Button.stories.mdx │ ├── IconButton.js │ ├── MenuAddButton.example.js │ ├── MenuAddButton.js │ ├── MenuAddButton.stories.mdx │ └── index.js ├── Card │ ├── Card.js │ ├── Card.stories.mdx │ └── index.js ├── CheckBox │ ├── CheckBox.example.js │ ├── CheckBox.js │ ├── CheckBox.stories.mdx │ └── index.js ├── CircularProgressBar │ ├── CircularProgressBar.js │ ├── CircularProgressBar.stories.mdx │ └── index.js ├── Deck │ ├── Deck.js │ ├── Deck.stories.mdx │ ├── DeckHorizontal.js │ ├── DeckVertical.js │ ├── DeckVerticalBasic.js │ └── index.js ├── DismissKeyboard │ ├── DismissKeyboard.js │ └── index.js ├── FullScreenLoader │ ├── FullScreenLoader.js │ ├── FullScreenLoader.stories.mdx │ └── index.js ├── Header │ ├── Header.js │ ├── Header.stories.mdx │ └── index.js ├── Image │ ├── Image.js │ ├── Image.stories.mdx │ └── index.js ├── Input │ ├── Input.example.js │ ├── Input.js │ ├── Input.stories.mdx │ └── index.js ├── Layout │ ├── Box.js │ ├── Box.stories.mdx │ ├── Flex.js │ ├── Flex.stories.mdx │ ├── Spacer.js │ ├── Stack.js │ ├── Stack.stories.mdx │ ├── StackList.js │ ├── TileList.js │ └── index.js ├── ListItem │ ├── ListItem.js │ ├── ListItem.stories.mdx │ └── index.js ├── Overlay │ ├── Overlay.js │ ├── Overlay.stories.mdx │ └── index.js ├── RadioButton │ ├── RadioButton.example.js │ ├── RadioButton.js │ ├── RadioButton.stories.mdx │ └── index.js ├── SearchBar │ ├── SearchBar.js │ ├── SearchBar.stories.mdx │ └── index.js ├── Text │ ├── Text.js │ ├── Text.stories.mdx │ └── index.js ├── index.d.ts ├── index.js ├── types │ ├── ActionButton.d.ts │ ├── Avatar.d.ts │ ├── Badge.d.ts │ ├── Box.d.ts │ ├── Button.d.ts │ ├── Card.d.ts │ ├── CheckBox.d.ts │ ├── CircularProgressBar.d.ts │ ├── Deck.d.ts │ ├── DismissKeyboard.d.ts │ ├── Flex.d.ts │ ├── FullScreenLoader.d.ts │ ├── Header.d.ts │ ├── IconButton.d.ts │ ├── Image.d.ts │ ├── Input.d.ts │ ├── ListItem.d.ts │ ├── MenuAddButton.d.ts │ ├── Overlay.d.ts │ ├── RadioButton.d.ts │ ├── RadioItem.d.ts │ ├── SearchBar.d.ts │ ├── Spacer.d.ts │ ├── Stack.d.ts │ ├── StackList.d.ts │ ├── Text.d.ts │ ├── align-type.d.ts │ ├── colors-type.d.ts │ ├── direction-type.d.ts │ ├── icon-type.d.ts │ ├── layout-children-type.d.ts │ ├── length-type.d.ts │ ├── size-type.d.ts │ ├── space-type.d.ts │ ├── text-align-type.d.ts │ ├── theme.d.ts │ ├── typography-type.d.ts │ └── width-type.d.ts └── util │ ├── ThemeProvider.js │ ├── accessibility.js │ ├── colors.js │ ├── prop-types.js │ ├── theme.js │ └── touchable.js └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | rules: { 5 | 'prettier/prettier': 0, 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # node.js 6 | # 7 | node_modules/ 8 | .vscode 9 | .cache-loader/ 10 | npm-debug.log 11 | yarn-error.log -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | guides 2 | .storybook 3 | .cache-loader 4 | docs 5 | *.stories.mdx 6 | *.example.js 7 | .vscode -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; 7 | -------------------------------------------------------------------------------- /.storybook/assets/AntDesign.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/.storybook/assets/AntDesign.ttf -------------------------------------------------------------------------------- /.storybook/assets/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/.storybook/assets/Entypo.ttf -------------------------------------------------------------------------------- /.storybook/assets/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/.storybook/assets/EvilIcons.ttf -------------------------------------------------------------------------------- /.storybook/assets/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/.storybook/assets/Feather.ttf -------------------------------------------------------------------------------- /.storybook/assets/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/.storybook/assets/FontAwesome.ttf -------------------------------------------------------------------------------- /.storybook/assets/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/.storybook/assets/Ionicons.ttf -------------------------------------------------------------------------------- /.storybook/assets/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/.storybook/assets/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /.storybook/assets/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/.storybook/assets/MaterialIcons.ttf -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: [ 3 | '../guides/GetStarted.stories.mdx', 4 | '../guides/DesignRules.stories.mdx', 5 | '../guides/Theme.stories.mdx', 6 | '../guides/Colors.stories.mdx', 7 | '../src/**/*.stories.@(js|mdx)' 8 | ], 9 | addons: [ 10 | '@storybook/addon-knobs', 11 | '@storybook/addon-actions/register', 12 | { 13 | name: '@storybook/addon-docs', 14 | options: { 15 | configureJSX: true, 16 | babelOptions: {}, 17 | sourceLoaderOptions: null, 18 | }, 19 | }, 20 | ] 21 | }; -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from '@storybook/addons'; 2 | import storyTheme from './theme'; 3 | 4 | addons.setConfig({ 5 | theme: storyTheme, 6 | }); -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {ThemeProvider, theme} from '../src'; 3 | import {withKnobs} from '@storybook/addon-knobs'; 4 | 5 | export const decorators = [ 6 | withKnobs, 7 | Story => ( 8 | 9 | 10 | 11 | ), 12 | ]; 13 | -------------------------------------------------------------------------------- /.storybook/theme.js: -------------------------------------------------------------------------------- 1 | import {create} from '@storybook/theming/create'; 2 | 3 | export default create({ 4 | base: 'light', 5 | 6 | brandUrl: 'https://www.npmjs.com/package/react-native-design-system', 7 | brandImage: 8 | 'https://raw.githubusercontent.com/iamshadmirza/BlogsByShad/master/blogs/saved_data/rnds_logo_mini.png', 9 | }); 10 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const jsWorkerCommonOptions = { 4 | workers: 2, 5 | workerParallelJobs: 50, 6 | poolParallelJobs: 50 7 | }; 8 | 9 | const babelWorkerOptions = { 10 | ...jsWorkerCommonOptions, 11 | name: "babel-pool" 12 | }; 13 | 14 | module.exports = ({ config, mode }) => { 15 | config.module.rules.push({ 16 | test: /\.(jsx|js)?$/, 17 | include: [ 18 | path.resolve(__dirname, "../node_modules/react-native"), 19 | path.resolve(__dirname, "../node_modules/react-native-vector-icons"), 20 | ], 21 | use: [ 22 | { loader: "cache-loader" }, 23 | { loader: "thread-loader", options: babelWorkerOptions }, 24 | { 25 | loader: "babel-loader?cacheDirectory?true", 26 | options: { 27 | presets: [ 28 | "module:metro-react-native-babel-preset", 29 | "@babel/preset-flow" 30 | ] 31 | } 32 | } 33 | ] 34 | }); 35 | 36 | config.module.rules.push({ 37 | test: /\.ttf$/, 38 | loader: "url-loader", // or directly file-loader 39 | include: path.resolve(__dirname, "../", "node_modules/react-native-vector-icons"), 40 | }); 41 | // convert react-native to react-native-web for storybook 42 | config.resolve.alias["react-native$"] = require.resolve("react-native-web"); 43 | // config.resolve.alias["react-native-vector-icons/"] = require.resolve("react-native-vector-icons/dist/"); 44 | 45 | config.resolve.extensions.push(".js", ".jsx", ".mdx"); 46 | return config; 47 | }; -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to React Native Design System 2 | Hey there! 🙋‍♂️ Thanks for contributing to React Native Design System 3 | 4 | ## Ways to contribute 5 | * Reporting a bug 6 | * Adding Storybook docs 7 | * Adding components 8 | * Suggesting UI enhancement 9 | 10 | ## How to contribute 11 | React Native Design System follows Component Driver Development (CDD). StoryBook helps us develop components in isolation from your app, which also encourages better reusability and testability for your components. Here is quick development setup guide: 12 | 13 | ## Install 14 | Fork/Clone the repo and install dependencies 15 | ```sh 16 | yarn install 17 | ``` 18 | 19 | ## Usage 20 | Run storybook server and start building 21 | ```sh 22 | yarn run storybook 23 | ``` 24 | 25 | ## Build 26 | Finally build the bundle with documentation changes 27 | ```sh 28 | yarn run build:storybook 29 | ``` 30 | 31 | ### Points to consider 32 | * If you're adding a component then it goes into a new folder inside `src/` of `react-native-design-system`. 33 | * You just create a `.js` component file and a `stories.mdx` story file and write a basic component and a story. 34 | * Now you can see the component on storybook and start building. 35 | * If you're updating something then you can just browse to the component folder and its storybook then make changes. 36 | 37 | ## Send a PR 38 | Create a pull request when you're done making changes. One PR should contain only one feature or bug fix. A story and a component can come along in a single PR. 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Mohd Shad Mirza 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/4.66dcec55.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Prism: Lightweight, robust, elegant syntax highlighting 3 | * 4 | * @license MIT 5 | * @author Lea Verou 6 | * @namespace 7 | * @public 8 | */ 9 | -------------------------------------------------------------------------------- /docs/4.66dcec55.iframe.bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"4.66dcec55.iframe.bundle.js","sources":[],"mappings":";A","sourceRoot":""} -------------------------------------------------------------------------------- /docs/4.920ef856637ed265ddf6.manager.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Prism: Lightweight, robust, elegant syntax highlighting 3 | * 4 | * @license MIT 5 | * @author Lea Verou 6 | * @namespace 7 | * @public 8 | */ 9 | -------------------------------------------------------------------------------- /docs/5.8b78b85b80910cb5a79f.manager.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * OverlayScrollbars 3 | * https://github.com/KingSora/OverlayScrollbars 4 | * 5 | * Version: 1.13.0 6 | * 7 | * Copyright KingSora | Rene Haas. 8 | * https://github.com/KingSora 9 | * 10 | * Released under the MIT license. 11 | * Date: 02.08.2020 12 | */ 13 | -------------------------------------------------------------------------------- /docs/6.30d57e8b.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * OverlayScrollbars 3 | * https://github.com/KingSora/OverlayScrollbars 4 | * 5 | * Version: 1.13.0 6 | * 7 | * Copyright KingSora | Rene Haas. 8 | * https://github.com/KingSora 9 | * 10 | * Released under the MIT license. 11 | * Date: 02.08.2020 12 | */ 13 | -------------------------------------------------------------------------------- /docs/6.30d57e8b.iframe.bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"6.30d57e8b.iframe.bundle.js","sources":[],"mappings":";A","sourceRoot":""} -------------------------------------------------------------------------------- /docs/7.ccbf050e29ff2321f65b.manager.bundle.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[7],{1029:function(module,exports){module.exports=function(e,n){return n=n||{},new Promise((function(t,r){var s=new XMLHttpRequest,o=[],u=[],i={},a=function(){return{ok:2==(s.status/100|0),statusText:s.statusText,status:s.status,url:s.responseURL,text:function(){return Promise.resolve(s.responseText)},json:function(){return Promise.resolve(s.responseText).then(JSON.parse)},blob:function(){return Promise.resolve(new Blob([s.response]))},clone:a,headers:{keys:function(){return o},entries:function(){return u},get:function(e){return i[e.toLowerCase()]},has:function(e){return e.toLowerCase()in i}}}};for(var l in s.open(n.method||"get",e,!0),s.onload=function(){s.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm,(function(e,n,t){o.push(n=n.toLowerCase()),u.push([n,t]),i[n]=i[n]?i[n]+","+t:t})),t(a())},s.onerror=r,s.withCredentials="include"==n.credentials,n.headers)s.setRequestHeader(l,n.headers[l]);s.send(n.body||null)}))}}}]); -------------------------------------------------------------------------------- /docs/AntDesign.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/docs/AntDesign.ttf -------------------------------------------------------------------------------- /docs/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/docs/Entypo.ttf -------------------------------------------------------------------------------- /docs/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/docs/EvilIcons.ttf -------------------------------------------------------------------------------- /docs/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/docs/Feather.ttf -------------------------------------------------------------------------------- /docs/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/docs/FontAwesome.ttf -------------------------------------------------------------------------------- /docs/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/docs/Ionicons.ttf -------------------------------------------------------------------------------- /docs/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/docs/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /docs/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/docs/MaterialIcons.ttf -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamshadmirza/react-native-design-system/96a2c975323808d66a1f801e414b5d1cfe188267/docs/favicon.ico -------------------------------------------------------------------------------- /docs/iframe.html: -------------------------------------------------------------------------------- 1 | Storybook

No Preview

Sorry, but you either have no stories or none are selected somehow.

  • Please check the Storybook config.
  • Try reloading the page.

If the problem persists, check the browser console, or the terminal you've run Storybook from.

-------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | Storybook
-------------------------------------------------------------------------------- /docs/main.31d7c7422073e28fcb1d.manager.bundle.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[1],{527:function(module,exports,__webpack_require__){__webpack_require__(528),__webpack_require__(949),__webpack_require__(946),__webpack_require__(947),__webpack_require__(939),__webpack_require__(950),module.exports=__webpack_require__(945)},595:function(module,exports){},738:function(module,exports){},945:function(module,exports,__webpack_require__){"use strict";__webpack_require__(40).addons.setConfig({refs:{}})},949:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.r(__webpack_exports__);var esm=__webpack_require__(80),create=__webpack_require__(503),theme=Object(create.create)({base:"light",brandUrl:"https://www.npmjs.com/package/react-native-design-system",brandImage:"https://raw.githubusercontent.com/iamshadmirza/BlogsByShad/master/blogs/saved_data/rnds_logo_mini.png"});esm.c.setConfig({theme:theme})}},[[527,2,3]]]); -------------------------------------------------------------------------------- /docs/runtime~main.22dddf64.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | !function(modules){function webpackJsonpCallback(data){for(var moduleId,chunkId,chunkIds=data[0],moreModules=data[1],executeModules=data[2],i=0,resolves=[];i 40 | * 41 | * Copyright (c) 2014-2017, Jon Schlinkert. 42 | * Released under the MIT License. 43 | */ 44 | 45 | /** @license React v0.19.1 46 | * scheduler.production.min.js 47 | * 48 | * Copyright (c) Facebook, Inc. and its affiliates. 49 | * 50 | * This source code is licensed under the MIT license found in the 51 | * LICENSE file in the root directory of this source tree. 52 | */ 53 | 54 | /** @license React v16.13.1 55 | * react-dom.production.min.js 56 | * 57 | * Copyright (c) Facebook, Inc. and its affiliates. 58 | * 59 | * This source code is licensed under the MIT license found in the 60 | * LICENSE file in the root directory of this source tree. 61 | */ 62 | 63 | /** @license React v16.13.1 64 | * react-is.production.min.js 65 | * 66 | * Copyright (c) Facebook, Inc. and its affiliates. 67 | * 68 | * This source code is licensed under the MIT license found in the 69 | * LICENSE file in the root directory of this source tree. 70 | */ 71 | 72 | /** @license React v16.13.1 73 | * react.production.min.js 74 | * 75 | * Copyright (c) Facebook, Inc. and its affiliates. 76 | * 77 | * This source code is licensed under the MIT license found in the 78 | * LICENSE file in the root directory of this source tree. 79 | */ 80 | 81 | /** @license React v17.0.2 82 | * react-is.production.min.js 83 | * 84 | * Copyright (c) Facebook, Inc. and its affiliates. 85 | * 86 | * This source code is licensed under the MIT license found in the 87 | * LICENSE file in the root directory of this source tree. 88 | */ 89 | -------------------------------------------------------------------------------- /docs/vendors~main.af429b2f.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | object-assign 3 | (c) Sindre Sorhus 4 | @license MIT 5 | */ 6 | 7 | /*! 8 | * The buffer module from node.js, for the browser. 9 | * 10 | * @author Feross Aboukhadijeh 11 | * @license MIT 12 | */ 13 | 14 | /*! 15 | * escape-html 16 | * Copyright(c) 2012-2013 TJ Holowaychuk 17 | * Copyright(c) 2015 Andreas Lubbe 18 | * Copyright(c) 2015 Tiancheng "Timothy" Gu 19 | * MIT Licensed 20 | */ 21 | 22 | /*! 23 | * https://github.com/es-shims/es5-shim 24 | * @license es5-shim Copyright 2009-2020 by contributors, MIT License 25 | * see https://github.com/es-shims/es5-shim/blob/master/LICENSE 26 | */ 27 | 28 | /*! 29 | * https://github.com/paulmillr/es6-shim 30 | * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com) 31 | * and contributors, MIT License 32 | * es6-shim: v0.35.4 33 | * see https://github.com/paulmillr/es6-shim/blob/0.35.3/LICENSE 34 | * Details and documentation: 35 | * https://github.com/paulmillr/es6-shim/ 36 | */ 37 | 38 | /*! 39 | * is-plain-object 40 | * 41 | * Copyright (c) 2014-2017, Jon Schlinkert. 42 | * Released under the MIT License. 43 | */ 44 | 45 | /*! 46 | * isobject 47 | * 48 | * Copyright (c) 2014-2017, Jon Schlinkert. 49 | * Released under the MIT License. 50 | */ 51 | 52 | /** @license React v0.19.1 53 | * scheduler.production.min.js 54 | * 55 | * Copyright (c) Facebook, Inc. and its affiliates. 56 | * 57 | * This source code is licensed under the MIT license found in the 58 | * LICENSE file in the root directory of this source tree. 59 | */ 60 | 61 | /** @license React v16.13.1 62 | * react-dom-unstable-native-dependencies.production.min.js 63 | * 64 | * Copyright (c) Facebook, Inc. and its affiliates. 65 | * 66 | * This source code is licensed under the MIT license found in the 67 | * LICENSE file in the root directory of this source tree. 68 | */ 69 | 70 | /** @license React v16.13.1 71 | * react-dom.production.min.js 72 | * 73 | * Copyright (c) Facebook, Inc. and its affiliates. 74 | * 75 | * This source code is licensed under the MIT license found in the 76 | * LICENSE file in the root directory of this source tree. 77 | */ 78 | 79 | /** @license React v16.13.1 80 | * react-is.production.min.js 81 | * 82 | * Copyright (c) Facebook, Inc. and its affiliates. 83 | * 84 | * This source code is licensed under the MIT license found in the 85 | * LICENSE file in the root directory of this source tree. 86 | */ 87 | 88 | /** @license React v16.13.1 89 | * react.production.min.js 90 | * 91 | * Copyright (c) Facebook, Inc. and its affiliates. 92 | * 93 | * This source code is licensed under the MIT license found in the 94 | * LICENSE file in the root directory of this source tree. 95 | */ 96 | 97 | //! stable.js 0.1.8, https://github.com/Two-Screen/stable 98 | 99 | //! © 2018 Angry Bytes and contributors. MIT licensed. 100 | -------------------------------------------------------------------------------- /docs/vendors~main.af429b2f.iframe.bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"vendors~main.af429b2f.iframe.bundle.js","sources":[],"mappings":";A","sourceRoot":""} -------------------------------------------------------------------------------- /guides/Colors.stories.mdx: -------------------------------------------------------------------------------- 1 | import { 2 | Meta, 3 | Preview, 4 | Story, 5 | ColorPalette, 6 | ColorItem, 7 | } from '@storybook/addon-docs/blocks'; 8 | import {FlatList} from 'react-native'; 9 | import colors from '../src/util/colors'; 10 | 11 | 12 | 13 | # Colors 14 | 15 | These are all the colors that you can use. 16 | 17 | ```js 18 | //usage 19 | import {colors} from 'react-native-design-system'; 20 | 21 | theme.colors.primary = colors['lime-A700']; 22 | ``` 23 | 24 | 25 | typeof colors[item] === 'string')} 27 | keyExtractor={(hex, index) => index.toString()} 28 | renderItem={({item: shade}) => { 29 | return ( 30 | 38 | ); 39 | }} 40 | /> 41 | 42 | -------------------------------------------------------------------------------- /guides/DesignRules.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta} from '@storybook/addon-docs/blocks'; 2 | 3 | 4 | 5 | # Design Rules 6 | 7 | These are some design rules that this library follows. It is based on the four key aspects that I considered while creating this. 8 | 9 | > Feel free to send a PR for corrections, these are personal opinion and I'm here to learn. 😅 10 | 11 | # Low surface area 12 | 13 | Most of the props are common across all components or they are the same as their parent component imported from React Native. This makes sure that you do not have to learn a whole set of extra props or just use what you already know. 14 | For example: 15 | 16 | - If it's a Button, it receives all the props of Touchable component of React Native. 17 | - If it's a Modal, it receives all the props of Modal. 18 | - Each component receives a `size` prop whose value can be one of these: `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl`, `5xl`. You just have to pass `size` prop with one of these value and you're done. 19 | - Another example could be `color` prop. You can pass one of the colors defined in `colors` of theme to any component. 20 | - If it's a layout based component like `Box`, `Stack` or our best friend `Card` then it receives a `space` prop. This also takes one of the values between `xs` and `9xl` ( with an addition of `space="none"`) and provide consistent spacing between components. 21 | - Each component receives a `style` and a `textStyle` prop (if there is a text involved). This is for some rare cases when you have to override the default styling. It's preferable to tweak the `theme` instead to maintain consistency and avoid adding that `style` again and again. 22 | 23 | These props are common to all the components. Other component-specific props are pretty straight forward too. 24 | 25 | # Speed 26 | 27 | For most of the cases, default styles like `size="md"` or `space="md"` will be enough. In other cases, it's just two to three props max to achieve any desired result. This makes it faster to prototype. The layout components make it easier to achieve the desired screen layout with `space` props. See the playground in `Stack` documentation. 28 | 29 | One of the key aspects of pixel-perfect design is the spacing between components. This design system proposes two things: 30 | 31 | 1. Every UI component has a margin of 0. 32 | 2. The spacing of any component will be determined by its parent Layout component. 33 | 34 | The separation of concerns makes the job easier. Layout component should take care of `space` only and UI component should worry about UI only i.e., `color` or `size`. 35 | 36 | # Consistency 37 | 38 | The correct balance of freedom and consistency is hard to achieve. 39 | 40 | 1. For freedom, you get straight forward props like `color` and `size`. 41 | 2. For consistency, you need to define these configurations inside theme file i.e **Single source of truth**. 42 | 43 | It helps in maintaining uniformity across all the usage. It also allows you to have several choices and use them as needed. Check out the theme section of this guide for the default configuration. 44 | 45 | # Connection 46 | 47 | Big problems are always more manageable when broken into smaller pieces. The design language of the system is broken down into color, typography, size, and space. These API is followed by each component. 48 | 49 | ## Color 50 | 51 | You have all the colors available in pallete with shades from `50` to `900`. 52 | In addition to few of the brand colors which has their dark mode counter part. `primary`, `seconday`, `success`, `error`, `warning`, `disabled`, `disabledText`, `heading`, `body`, `subtle`, `transparent`, `semitransparent`, `outline`, `white`, `black`, `shadowColor`, `bgInput`, `bgImage`, `bg100`, `bg200`, `bg300` 53 | 54 | ## Typography 55 | 56 | To keep things simple and consistent. There are two choices for fonts to use and they will resolve to appropriate font family: 57 | 58 | - heading 59 | - body 60 | 61 | You will pass it as `fontBase` property. Example `fontBase="heading"` 62 | 63 | These two the parent font family which has some variants. These variants are: 64 | 65 | `light`, `medium`, `regular`, `semibold`, `bold`, `extrabold`, `italic`, `bolditalic`. 66 | 67 | You can pass any of the above value as `fontVariant` prop. Example: `fontVariant="semibold"` 68 | 69 | It will resolve to the fonts you have set in theme. 70 | 71 | ```js 72 | { 73 | heading: { 74 | light: "", 75 | medium: "", 76 | regular: "", 77 | semibold: "", 78 | bold: "", 79 | extrabold: "", 80 | italic: "", 81 | bolditalic: "", 82 | }, 83 | body: { 84 | light: "", 85 | medium: "", 86 | regular: "", 87 | semibold: "", 88 | bold: "", 89 | extrabold: "", 90 | italic: "", 91 | bolditalic: "", 92 | }, 93 | } 94 | ``` 95 | 96 | ## Size 97 | 98 | - The available sizes you can use is `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl`, `5xl`. The default is `"md"` and it will be applied if are not passing anything. 99 | - Font size is also similar and it ranges from "xs" to "9xl". 100 | 101 | ## Space 102 | 103 | Space also shares similar API as size but with one addition. You can also pass `"none"` with the range of `"xs"` to `"9xl"`. Space is a dedicated prop for layout components like `Stack`, `Box` and `Card`. 104 | 105 | > You can contribute to the theme. Please share what are the common color tokens you use, what are the common font sizes that you use in any app, etc. Let's make the theme config more generic together. 106 | -------------------------------------------------------------------------------- /guides/GetStarted.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta} from '@storybook/addon-docs/blocks'; 2 | 3 | 4 | 5 | # Get Started 6 | 7 | `React Native Design System` is a set of design rules and component library that lets you prototype faster with easy to use cross-platform components. Let's get started! 8 | 9 | # Install 10 | 11 | Simply go to the command line and run this command. 12 | 13 | ```sh 14 | yarn add react-native-design-system 15 | ``` 16 | 17 | You can use `yarn` or `npm` as per your choice. 18 | 19 | ```sh 20 | npm install react-native-design-system 21 | ``` 22 | 23 | This library needs `react-native-vector-icons` so go on and install that too to get all the cool icons. Check out [Install guide](https://github.com/oblador/react-native-vector-icons#installation). 24 | 25 | # Usage 26 | 27 | React Native Design System uses a centralized theme to provide consistency across all the components. 28 | 29 | ### Step 1. Import ThemeProvider and theme then wrap your root component. 30 | 31 | This step is important. We are passing `theme` as context value that each component will access. `ThemeProvider` also needs a `colorMode` prop to resolve the component UI to either light mode or dark mode. 32 | 33 | ```js 34 | //your root component 35 | import {ThemeProvider, theme} from 'react-native-design-system'; 36 | 37 | function App() { 38 | return ( 39 | 40 | 41 | 42 | ); 43 | } 44 | ``` 45 | 46 | ### Step 2. Use component. 47 | 48 | ```js 49 | //inside any file 50 | import {Button} from 'react-native-design-system'; 51 | 52 | function HomeScreen() { 53 | return ; 54 | } 55 | ``` 56 | 57 | That's pretty much it. `theme` file contains configuration for all the components. Don't worry, you can easily customize it. Let me show how: 58 | 59 | # Customize 60 | 61 | You just need to import `theme`, reassign the value you want to change and pass it to `ThemeProvider`. Example: 62 | Default primary color is blue but you like orange so you can simply do: 63 | 64 | ```js 65 | import {ThemeProvider, theme} from 'react-native-design-system'; 66 | 67 | theme.colors.primary = 'orange'; 68 | 69 | function App() { 70 | return ( 71 | 72 | 73 | 74 | ); 75 | } 76 | ``` 77 | 78 | And we are done! 79 | 80 | > You can see all the configurations available on the theme page. 81 | 82 | # If you have a lot of customizations 83 | 84 | This is just a personal approach, you can do as you prefer. What I usually do is create a `theme.config.js` file and add all my customizations there. 85 | 86 | ```js 87 | //theme.config.js at root 88 | import {theme} from 'react-native-design-system'; 89 | 90 | theme.colors = { 91 | primary: '#000', 92 | heading: '#999', 93 | subtle: '#333', 94 | disabled: '#78909c', 95 | }; 96 | 97 | export default theme; 98 | ``` 99 | 100 | Now, I will just import `theme` from here and pass it to my `ThemeProvider`. 101 | 102 | ```js 103 | import {ThemeProvider} from 'react-native-design-system'; 104 | import theme from './theme.config.js'; 105 | 106 | function App() { 107 | return ( 108 | 109 | 110 | 111 | ); 112 | } 113 | ``` 114 | 115 | > Please make sure to pass all the keys while reassigning any object inside the theme. 116 | 117 | ### Using Dark Mode 118 | 119 | You can access current mode via `useDarkMode` hook will give you `isDarkMode` and `toggleDarkMode`. 120 | 121 | ```js 122 | //inside any file 123 | import {Button, useDarkMode} from 'react-native-design-system'; 124 | 125 | function HomeScreen() { 126 | const { isDarkMode, toggleDarkMode } = useDarkMode(); 127 | return ( 128 | 131 | ); 132 | } 133 | 134 | # Playground 135 | 136 | Storybook provide interactive playground to test the component in all possible scenarios. There is a `playground` story at the end of each component. Click on that and switch to `Canvas` to access `Knobs` and `Actions` addons. 137 | ``` 138 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-design-system", 3 | "version": "2.0.5", 4 | "description": "A reusabale component library and design rules for react-native.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "storybook": "start-storybook -p 9001 -c .storybook -s .storybook/assets", 9 | "build:storybook": "build-storybook -c .storybook -s .storybook/assets -o docs" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/iamshadmirza/react-native-design-system.git" 14 | }, 15 | "author": "Shad Mirza", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/iamshadmirza/react-native-design-system/issues" 19 | }, 20 | "homepage": "https://github.com/iamshadmirza/react-native-design-system#readme", 21 | "keywords": [ 22 | "react-native", 23 | "reactjs", 24 | "reactnative", 25 | "design-system", 26 | "ui", 27 | "ui-library", 28 | "cross-platform", 29 | "reusable" 30 | ], 31 | "dependencies": { 32 | "clamp": "^1.0.1", 33 | "prop-types": "^15.7.2" 34 | }, 35 | "peerDependencies": { 36 | "react-native": ">=0.56.0", 37 | "react-native-vector-icons": ">6.0.0" 38 | }, 39 | "devDependencies": { 40 | "@babel/core": "^7.8.3", 41 | "@babel/preset-env": "^7.8.3", 42 | "@babel/preset-react": "^7.8.3", 43 | "@babel/runtime": "^7.8.3", 44 | "@react-native-community/eslint-config": "^0.0.5", 45 | "@react-native-community/toolbar-android": "^0.1.0-rc.2", 46 | "@storybook/addon-actions": "^6.2.9", 47 | "@storybook/addon-docs": "^6.2.9", 48 | "@storybook/addon-knobs": "^6.2.9", 49 | "@storybook/addons": "^6.2.9", 50 | "@storybook/react": "^6.2.9", 51 | "@storybook/theming": "^6.2.9", 52 | "@types/prop-types": "^15.7.3", 53 | "@types/react": "^16.4.16", 54 | "@types/react-native": "^0.57.4", 55 | "babel-jest": "^24.9.0", 56 | "babel-loader": "^8.0.6", 57 | "cache-loader": "^4.1.0", 58 | "eslint": "^6.7.2", 59 | "jest": "^24.9.0", 60 | "metro-react-native-babel-preset": "^0.57.0", 61 | "react": "16.13.1", 62 | "react-dom": "^16.8.3", 63 | "react-native-vector-icons": "^6.6.0", 64 | "react-native-web": "^0.11.7", 65 | "react-scripts": "^3.2.0", 66 | "react-test-renderer": "16.9.0", 67 | "thread-loader": "^2.1.2", 68 | "typescript": "^3.7.5", 69 | "url-loader": "^3.0.0" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/ActionButton/ActionButton.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { 4 | Platform, 5 | StyleSheet, 6 | TouchableNativeFeedback, 7 | TouchableOpacity, 8 | View, 9 | } from 'react-native'; 10 | import Feather from 'react-native-vector-icons/Feather'; 11 | import {shadows, sizes} from '../util/prop-types'; 12 | import {useThemeContext} from '../util/ThemeProvider'; 13 | 14 | const getContainerStyle = ({theme, size, color, shadow}) => { 15 | return { 16 | ...theme.shadow[shadow], 17 | justifyContent: 'center', 18 | alignItems: 'center', 19 | backgroundColor: theme.colors[color], 20 | width: theme.actionButtonSize[size], 21 | height: theme.actionButtonSize[size], 22 | borderRadius: theme.actionButtonSize[size] / 2, 23 | }; 24 | }; 25 | 26 | const ActionButton = React.forwardRef(({style, ...props}, ref) => { 27 | const theme = useThemeContext(); 28 | const TouchableElement = 29 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 30 | 31 | return ( 32 | 33 | 38 | {props.icon || ( 39 | 44 | )} 45 | 46 | 47 | ); 48 | }); 49 | 50 | ActionButton.propTypes = { 51 | size: sizes, 52 | onPress: PropTypes.func.isRequired, 53 | iconColor: PropTypes.string, 54 | color: PropTypes.string, 55 | icon: PropTypes.element, 56 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 57 | shadow: shadows, 58 | }; 59 | 60 | ActionButton.defaultProps = { 61 | size: 'md', 62 | color: 'primary', 63 | shadow: 'md', 64 | iconColor: 'white', 65 | }; 66 | 67 | export default ActionButton; 68 | -------------------------------------------------------------------------------- /src/ActionButton/ActionButton.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select} from '@storybook/addon-knobs'; 3 | import {action} from '@storybook/addon-actions'; 4 | import Stack from '../Layout/Stack'; 5 | import Feather from 'react-native-vector-icons/Feather'; 6 | import ActionButton from './ActionButton'; 7 | import {sizeArray} from '../util/prop-types'; 8 | 9 | 10 | 11 | # ActionButton 12 | 13 | ActionButton is the buttons you use on your landing screen to guide users towards your goal action. It's the part of the landing screen that the user needs to click to take the action you want them to take. 14 | 15 | # Usage 16 | 17 | ```js 18 | import {ActionButton} from 'react-native-design-system'; 19 | 20 | this.handlePress()} />; 21 | ``` 22 | 23 | # Props 24 | 25 | 26 | 27 | # Sizes 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | # Color 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | # Icon 58 | 59 | 60 | 61 | } 63 | size="md" 64 | onPress={action('pressed')} 65 | /> 66 | 67 | 68 | 69 | # Playground 70 | 71 | Play with ActionButton in Canvas mode. 72 | 73 | 74 | 79 | 80 | -------------------------------------------------------------------------------- /src/ActionButton/index.js: -------------------------------------------------------------------------------- 1 | import ActionButton from './ActionButton'; 2 | export { ActionButton }; 3 | -------------------------------------------------------------------------------- /src/Avatar/Avatar.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { 4 | Image, 5 | Platform, 6 | StyleSheet, 7 | Text, 8 | TouchableNativeFeedback, 9 | TouchableOpacity, 10 | View, 11 | } from 'react-native'; 12 | import Feather from 'react-native-vector-icons/Feather'; 13 | import { 14 | extractAccessibilityPropsFromProps, 15 | removeAccessibilityPropsFromProps, 16 | } from '../util/accessibility'; 17 | import {radii, shadows, sizes} from '../util/prop-types'; 18 | import {useCustomComponent, useThemeContext} from '../util/ThemeProvider'; 19 | import {removeBackgroundProp} from '../util/touchable'; 20 | 21 | const getContainerStyle = ({ 22 | theme, 23 | source, 24 | square, 25 | rounded, 26 | size, 27 | background, 28 | shadow, 29 | radius, 30 | }) => { 31 | const avatarStyle = [styles.container]; 32 | avatarStyle.push({ 33 | backgroundColor: theme.colors[background], 34 | width: theme.avatarSize[size], 35 | height: theme.avatarSize[size], 36 | borderRadius: theme.radius.full, 37 | }); 38 | if (shadow) { 39 | avatarStyle.push(theme.shadow[shadow]); 40 | } 41 | if (source) { 42 | avatarStyle.push({ 43 | padding: 0, 44 | }); 45 | } 46 | if (square) { 47 | avatarStyle.push({ 48 | borderRadius: 0, 49 | }); 50 | } 51 | if (rounded) { 52 | avatarStyle.push({ 53 | borderRadius: theme.radius.md, 54 | }); 55 | } 56 | if (radius) { 57 | avatarStyle.push({ 58 | borderRadius: theme.radius[radius], 59 | }); 60 | } 61 | return avatarStyle; 62 | }; 63 | 64 | const getEditIconStyle = ({theme, size}) => { 65 | const iconStyle = [ 66 | styles.editView, 67 | { 68 | width: theme.avatarSize[size] / 3, 69 | height: theme.avatarSize[size] / 3, 70 | borderRadius: theme.avatarSize[size], 71 | backgroundColor: theme.colors.bg200, 72 | }, 73 | ]; 74 | return iconStyle; 75 | }; 76 | 77 | const getTitleStyle = ({theme, size}) => { 78 | return { 79 | fontWeight: '600', 80 | fontSize: theme.avatarSize[size] / 4, 81 | color: theme.colors.para, 82 | }; 83 | }; 84 | 85 | const Avatar = React.forwardRef(({style, ...props}, ref) => { 86 | const theme = useThemeContext(); 87 | const customComponent = useCustomComponent(); 88 | const ImageComponent = customComponent?.Image ?? Image; 89 | const TouchableElement = 90 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 91 | const updateProps = removeBackgroundProp(props); 92 | return ( 93 | 100 | 103 | 108 | {props.source ? ( 109 | 115 | ) : ( 116 | 122 | {props.title} 123 | 124 | )} 125 | 126 | 127 | {props.editable && ( 128 | 133 | 138 | 139 | )} 140 | 141 | ); 142 | }); 143 | 144 | Avatar.propTypes = { 145 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 146 | textStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 147 | title: PropTypes.string, 148 | background: PropTypes.string, 149 | source: PropTypes.object, 150 | editable: PropTypes.bool, 151 | onPress: PropTypes.func, 152 | size: sizes, 153 | square: PropTypes.bool, 154 | rounded: PropTypes.bool, 155 | editIconStyle: PropTypes.object, 156 | editIconColor: PropTypes.string, 157 | shadow: shadows, 158 | radius: radii, 159 | imageProps: PropTypes.object, 160 | }; 161 | 162 | Avatar.defaultProps = { 163 | title: 'MD', 164 | editable: false, 165 | size: 'lg', 166 | background: 'bgImage', 167 | shadow: 'none', 168 | }; 169 | 170 | const styles = StyleSheet.create({ 171 | container: { 172 | overflow: 'hidden', 173 | justifyContent: 'center', 174 | alignItems: 'center', 175 | }, 176 | propView: { 177 | backgroundColor: 'transparent', 178 | }, 179 | image: { 180 | width: '100%', 181 | height: '100%', 182 | }, 183 | editView: { 184 | position: 'absolute', 185 | right: 0, 186 | bottom: 0, 187 | justifyContent: 'center', 188 | alignItems: 'center', 189 | elevation: 1, 190 | }, 191 | }); 192 | 193 | export default Avatar; 194 | -------------------------------------------------------------------------------- /src/Avatar/Avatar.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select, text, boolean, color} from '@storybook/addon-knobs'; 3 | import {action} from '@storybook/addon-actions'; 4 | import Stack from '../Layout/Stack'; 5 | import Feather from 'react-native-vector-icons/Feather'; 6 | import Avatar from './Avatar'; 7 | import {sizeArray, radiusArray, shadowArray} from '../util/prop-types'; 8 | 9 | 10 | 11 | # Avatar 12 | 13 | Avatars are used to represent a user and can contain photos or text. 14 | 15 | # Usage 16 | 17 | ```js 18 | import {Avatar} from 'react-native-design-system'; 19 | 20 | this.handlePress()} 24 | />; 25 | ``` 26 | 27 | # Props 28 | 29 | 30 | 31 | # Sizes 32 | 33 | As usual, 9 sizes are available. 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | # Types 52 | 53 | There are mainly three types og Avatar: `default`, `square` and `rounded`. All props accept `boolean` value. 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | # Title 66 | 67 | `title` accepts a string. Passing upto 3 character (maximum) is recommended. 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | # Source 76 | 77 | `source` is same as Image component. You can pass a `required` image or a `uri` object. 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | # Shadow 86 | 87 | `shadow` prop can be used to customize shadow level. Allowed values are `none`, `xs`, `sm`, `md`, `lg`, `xl`. 88 | 89 | 90 | 91 | 95 | 96 | 97 | 98 | # Radius 99 | 100 | `radius` prop customises the roundness of Avatar. Allowed values are 'none', `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `full`. 101 | 102 | 103 | 104 | 108 | 109 | 110 | 111 | # Editable 112 | 113 | `editable` is a boolean value which adds an edit button to the bottom. You just have to pass one `onPress` function and the `Avatar` is clickable. 114 | 115 | 116 | 117 | 118 | 119 | 124 | 125 | 126 | 127 | 128 | # Playground 129 | 130 | Play with Avatar in Canvas mode. 131 | 132 | 133 | 142 | 143 | -------------------------------------------------------------------------------- /src/Avatar/index.js: -------------------------------------------------------------------------------- 1 | import Avatar from './Avatar'; 2 | export { Avatar }; 3 | -------------------------------------------------------------------------------- /src/Badge/Badge.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | View, 4 | TouchableOpacity, 5 | TouchableNativeFeedback, 6 | Platform, 7 | Text, 8 | StyleSheet, 9 | } from 'react-native'; 10 | import PropTypes from 'prop-types'; 11 | import {useThemeContext} from '../util/ThemeProvider'; 12 | import {radii, sizes} from '../util/prop-types'; 13 | 14 | const getContainerStyle = ({theme, size, mini, color, square, radius}) => { 15 | const badgeStyle = [styles.container]; 16 | if (color) { 17 | badgeStyle.push({ 18 | backgroundColor: theme.colors[color], 19 | borderRadius: theme.radius.full, 20 | }); 21 | } 22 | if (square) { 23 | badgeStyle.push({ 24 | borderRadius: theme.radius.none, 25 | }); 26 | } 27 | if (radius) { 28 | badgeStyle.push({ 29 | borderRadius: theme.radius[radius], 30 | }); 31 | } 32 | if (mini) { 33 | badgeStyle.push({ 34 | width: theme.miniBadgeSize[size], 35 | height: theme.miniBadgeSize[size], 36 | borderRadius: theme.radius.full, 37 | }); 38 | } 39 | return badgeStyle; 40 | }; 41 | 42 | const getTextStyle = ({theme, size}) => { 43 | return { 44 | color: '#fff', 45 | fontSize: theme.badgeSize[size], 46 | marginVertical: 5, 47 | marginHorizontal: 10, 48 | }; 49 | }; 50 | 51 | const Badge = ({children, onPress, style, textStyle, ...props}) => { 52 | const theme = useThemeContext(); 53 | const TouchableElement = 54 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 55 | return ( 56 | 57 | 61 | {props.mini ? null : ( 62 | 67 | {children} 68 | 69 | )} 70 | 71 | 72 | ); 73 | }; 74 | 75 | Badge.propTypes = { 76 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 77 | textStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 78 | children: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 79 | size: sizes, 80 | mini: PropTypes.bool, 81 | onPress: PropTypes.func, 82 | square: PropTypes.bool, 83 | radius: radii, 84 | }; 85 | 86 | Badge.defaultProps = { 87 | children: 0, 88 | color: 'primary', 89 | size: 'sm', 90 | }; 91 | 92 | const styles = StyleSheet.create({ 93 | container: { 94 | alignSelf: 'flex-start', 95 | justifyContent: 'center', 96 | alignItems: 'center', 97 | }, 98 | }); 99 | 100 | export default Badge; 101 | -------------------------------------------------------------------------------- /src/Badge/Badge.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import { 3 | withKnobs, 4 | select, 5 | number, 6 | boolean, 7 | color, 8 | } from '@storybook/addon-knobs'; 9 | import {action} from '@storybook/addon-actions'; 10 | import Stack from '../Layout/Stack'; 11 | import Feather from 'react-native-vector-icons/Feather'; 12 | import Badge from './Badge'; 13 | import {sizeArray} from '../util/prop-types'; 14 | 15 | 16 | 17 | # Badge 18 | 19 | Badges are small components typically used to communicate a number value or indicate the status of an item to the user. 20 | 21 | # Usage 22 | 23 | ```js 24 | import { Badge } from 'react-native-design-system'; 25 | 26 | this.handlePress())} 28 | > 29 | 10000 30 | 31 | ``` 32 | 33 | # Props 34 | 35 | 36 | 37 | # Sizes 38 | 39 | As usual, there are 9 sizes available. 40 | 41 | 42 | 43 | 44 | 45 | 10000 46 | 47 | 48 | 10000 49 | 50 | 51 | 10000 52 | 53 | 54 | 10000 55 | 56 | 57 | 10000 58 | 59 | 60 | 1000 61 | 62 | 63 | 100 64 | 65 | 66 | 50 67 | 68 | 69 | 0 70 | 71 | 72 | -10 73 | 74 | 75 | 76 | 77 | 78 | # Types 79 | 80 | There are 3 types of Badges mainly: `default` which is round, `sqaure` and `mini`. The prop accept boolean value. 81 | 82 | 83 | 84 | 85 | 10 86 | 87 | 10 88 | 89 | 90 | 91 | Featured 92 | 93 | 94 | Deprecated 95 | 96 | 97 | 98 | 99 | 100 | # Playground 101 | 102 | Play with Badge in Canvas mode. 103 | 104 | 105 | 113 | 114 | -------------------------------------------------------------------------------- /src/Badge/index.js: -------------------------------------------------------------------------------- 1 | import Badge from './Badge'; 2 | export {Badge}; 3 | -------------------------------------------------------------------------------- /src/Button/IconButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Platform, 4 | TouchableNativeFeedback, 5 | StyleSheet, 6 | View, 7 | TouchableOpacity, 8 | } from 'react-native'; 9 | import {useThemeContext} from '../util/ThemeProvider'; 10 | 11 | import Text from '../Text/index'; 12 | 13 | const getContainerStyle = props => { 14 | const { 15 | outline, 16 | transparent, 17 | theme, 18 | borderColor, 19 | radius, 20 | shadow, 21 | rounded, 22 | background, 23 | size, 24 | } = props; 25 | const buttonStyles = [styles.root]; 26 | buttonStyles.push({ 27 | backgroundColor: theme.colors[background], 28 | borderRadius: theme.radius[radius], 29 | borderWidth: StyleSheet.hairlineWidth, 30 | borderColor: theme.colors[background], 31 | width: theme.size[size] * 2, 32 | height: theme.size[size] * 2, 33 | ...theme.shadow[shadow], 34 | }); 35 | if (rounded) { 36 | buttonStyles.push({ 37 | borderRadius: theme.buttonSize.xs, 38 | }); 39 | } 40 | if (outline) { 41 | buttonStyles.push({ 42 | borderWidth: StyleSheet.hairlineWidth, 43 | borderColor: theme.colors[borderColor], 44 | }); 45 | } 46 | if (transparent) { 47 | buttonStyles.push({ 48 | borderWidth: StyleSheet.hairlineWidth, 49 | borderColor: 'transparent', 50 | backgroundColor: 'transparent', 51 | }); 52 | } 53 | return buttonStyles; 54 | }; 55 | 56 | const IconButton = props => { 57 | const { 58 | text, 59 | onPress, 60 | style, 61 | iconStyle, 62 | icon, 63 | color, 64 | size, 65 | onLongPress, 66 | disabled, 67 | background, 68 | radius, 69 | shadow, 70 | ...rest 71 | } = props; 72 | const theme = useThemeContext(); 73 | const TouchableElement = 74 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 75 | 76 | return ( 77 | 82 | 83 | {icon} 84 | {text ? ( 85 | 86 | {text} 87 | 88 | ) : null} 89 | 90 | 91 | ); 92 | }; 93 | 94 | IconButton.defaultProps = { 95 | size: 'lg', 96 | background: 'bg100', 97 | radius: 'full', 98 | shadow: 'none', 99 | borderColor: 'primary', 100 | }; 101 | 102 | const styles = StyleSheet.create({ 103 | root: { 104 | flexDirection: 'row', 105 | alignItems: 'center', 106 | justifyContent: 'center', 107 | }, 108 | text: {marginLeft: 6}, 109 | }); 110 | 111 | export default IconButton; 112 | -------------------------------------------------------------------------------- /src/Button/MenuAddButton.example.js: -------------------------------------------------------------------------------- 1 | import React, {useState} from 'react'; 2 | import MenuAddButton from './MenuAddButton'; 3 | import {select, boolean, color} from '@storybook/addon-knobs'; 4 | import {sizeArray} from '../util/prop-types'; 5 | 6 | export default function ExampleMenuButton() { 7 | const [count, setCount] = useState(0); 8 | return ( 9 | setCount(count + 1)} 13 | onDecrement={() => setCount(count - 1)} 14 | iconColor={color('iconColor', '#333')} 15 | count={count} 16 | /> 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/Button/MenuAddButton.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { 4 | Platform, 5 | StyleSheet, 6 | Text, 7 | TouchableNativeFeedback, 8 | TouchableOpacity, 9 | View, 10 | } from 'react-native'; 11 | import MaterialIcons from 'react-native-vector-icons/MaterialIcons'; 12 | import {radii, shadows, sizes} from '../util/prop-types'; 13 | import {useThemeContext, useThemeMode} from '../util/ThemeProvider'; 14 | import {removeBackgroundProp} from '../util/touchable'; 15 | 16 | const getContainerStyle = ({ 17 | theme, 18 | size, 19 | count, 20 | disabled, 21 | shadow, 22 | radius, 23 | background, 24 | }) => { 25 | const buttonStyle = [styles.container]; 26 | buttonStyle.push({ 27 | backgroundColor: theme.colors[background], 28 | paddingVertical: theme.buttonSize.paddingVertical[size], 29 | paddingHorizontal: theme.buttonSize.paddingHorizontal[size], 30 | flexDirection: 'row', 31 | justifyContent: 'center', 32 | borderRadius: theme.radius[radius], 33 | }); 34 | if (shadow) { 35 | buttonStyle.push(theme.shadow[shadow]); 36 | } 37 | if (count < 1) { 38 | buttonStyle.push({ 39 | backgroundColor: theme.colors[background], 40 | justifyContent: 'center', 41 | alignItems: 'center', 42 | }); 43 | } 44 | if (disabled) { 45 | buttonStyle.push({ 46 | backgroundColor: theme.colors.disabled, 47 | justifyContent: 'center', 48 | alignItems: 'center', 49 | }); 50 | } 51 | return buttonStyle; 52 | }; 53 | 54 | const getTextStyle = ({theme, size, disabled}) => { 55 | const textStyle = [ 56 | { 57 | fontSize: theme.fontSize[size], 58 | paddingHorizontal: 10, 59 | color: theme.colors.para, 60 | }, 61 | ]; 62 | if (disabled) { 63 | textStyle.push({ 64 | color: theme.colors.disabledText, 65 | }); 66 | } 67 | return textStyle; 68 | }; 69 | 70 | const MenuAddButton = ({style, textStyle, ...props}) => { 71 | const theme = useThemeContext(); 72 | const {isDarkMode} = useThemeMode(); 73 | const TouchableElement = 74 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 75 | 76 | const updateProps = removeBackgroundProp(props); 77 | 78 | if (props.count < 1) { 79 | return ( 80 | 84 | 85 | 87 | ADD 88 | 89 | 90 | 91 | ); 92 | } 93 | return ( 94 | 95 | 96 | 97 | {props.minusIcon || ( 98 | 103 | )} 104 | 105 | 106 | 107 | 108 | {props.count} 109 | 110 | 111 | 112 | 113 | {props.plusIcon || ( 114 | 119 | )} 120 | 121 | 122 | 123 | ); 124 | }; 125 | 126 | MenuAddButton.propTypes = { 127 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 128 | textStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 129 | count: PropTypes.number.isRequired, 130 | onIncrement: PropTypes.func.isRequired, 131 | onDecrement: PropTypes.func.isRequired, 132 | plusIcon: PropTypes.element, 133 | minusIcon: PropTypes.element, 134 | iconColor: PropTypes.string, 135 | disabled: PropTypes.bool, 136 | size: sizes, 137 | shadow: shadows, 138 | radius: radii, 139 | }; 140 | 141 | MenuAddButton.defaultProps = { 142 | count: 0, 143 | size: 'md', 144 | shadow: 'none', 145 | radius: 'sm', 146 | background: 'bg200', 147 | }; 148 | 149 | const styles = StyleSheet.create({ 150 | container: { 151 | flexDirection: 'row', 152 | backgroundColor: '#f8f8f8', 153 | }, 154 | icon: { 155 | flex: 2, 156 | justifyContent: 'center', 157 | alignItems: 'center', 158 | paddingHorizontal: 15, 159 | }, 160 | countView: { 161 | flex: 3, 162 | justifyContent: 'center', 163 | alignItems: 'center', 164 | }, 165 | }); 166 | 167 | export default MenuAddButton; 168 | -------------------------------------------------------------------------------- /src/Button/MenuAddButton.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs} from '@storybook/addon-knobs'; 3 | import {useState} from 'react'; 4 | import {action} from '@storybook/addon-actions'; 5 | import Stack from '../Layout/Stack'; 6 | import AntDesign from 'react-native-vector-icons/AntDesign'; 7 | import MenuAddButton from './MenuAddButton'; 8 | import ExampleMenuButton from './MenuAddButton.example.js'; 9 | 10 | 11 | 12 | # MenuAddButton 13 | 14 | A `MenuAddButton` is a clickable button to carry out actions like adding and removing items from cart. 15 | 16 | # Usage 17 | 18 | ```js 19 | import {MenuAddButton} from 'react-native-design-system'; 20 | 21 | handleIncrement()} 23 | onDecrement={() => handleDecrement()} 24 | count={this.state.count} 25 | />; 26 | ``` 27 | 28 | # Props 29 | 30 | 31 | 32 | # Count 33 | 34 | Pass an `Integer` value in `count` prop as number of items. 35 | 36 | 37 | 38 | 39 | 44 | 49 | 54 | 59 | 60 | 61 | 62 | 63 | # Disabled 64 | 65 | `disabled` accepts a boolean value and restricts touch response. 66 | 67 | 68 | 69 | 75 | 76 | 77 | 78 | # Size 79 | 80 | There are 7 different size available. You may not need all of them but it doesn't hurt to have them just in case. 😅 81 | 82 | 83 | 84 | 85 | 91 | 97 | 103 | 109 | 115 | 121 | 127 | 128 | 129 | 130 | 131 | # Custom icons 132 | 133 | Pass custom icon as `plusIcon` and `minusIcon` of your choice. 134 | 135 | 136 | 137 | } 141 | minusIcon={} 142 | count={10} 143 | /> 144 | 145 | 146 | 147 | # Playground 148 | 149 | Play with MenuAddButton in Canvas mode. 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/Button/index.js: -------------------------------------------------------------------------------- 1 | import Button from './Button'; 2 | import MenuAddButton from './MenuAddButton'; 3 | import IconButton from './IconButton'; 4 | 5 | export {Button, MenuAddButton, IconButton}; 6 | -------------------------------------------------------------------------------- /src/Card/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StyleSheet} from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import {radii, shadows, spaces} from '../util/prop-types'; 6 | 7 | const getContainerStyle = ({ 8 | row, 9 | horizontal, 10 | align, 11 | vertical, 12 | theme, 13 | space, 14 | shadow, 15 | outline, 16 | wrap, 17 | background, 18 | radius, 19 | }) => { 20 | const cardStyle = [ 21 | styles.container, 22 | { 23 | padding: theme.space[space], 24 | backgroundColor: theme.colors[background], 25 | borderRadius: theme.radius[radius], 26 | }, 27 | ]; 28 | if (shadow) { 29 | cardStyle.push(theme.shadow[shadow]); 30 | } 31 | if (row) { 32 | cardStyle.push({ 33 | flexDirection: 'row', 34 | justifyContent: 'flex-start', 35 | alignItems: 'center', 36 | }); 37 | } 38 | if (wrap) { 39 | cardStyle.push({flexWrap: 'wrap'}); 40 | } 41 | if (outline) { 42 | cardStyle.push({ 43 | borderWidth: StyleSheet.hairlineWidth, 44 | borderColor: '#333', 45 | }); 46 | } 47 | if (align === 'center') { 48 | cardStyle.push({ 49 | alignItems: 'center', 50 | }); 51 | } 52 | if (align === 'left') { 53 | cardStyle.push({ 54 | alignItems: 'flex-start', 55 | }); 56 | } 57 | if (align === 'right') { 58 | cardStyle.push({ 59 | alignItems: 'flex-end', 60 | }); 61 | } 62 | if (horizontal) { 63 | cardStyle.push({ 64 | paddingVertical: 0, 65 | }); 66 | } 67 | if (vertical) { 68 | cardStyle.push({ 69 | paddingHorizontal: 0, 70 | }); 71 | } 72 | return cardStyle; 73 | }; 74 | 75 | const Card = props => { 76 | const theme = useThemeContext(); 77 | return ( 78 | 84 | {props.children} 85 | 86 | ); 87 | }; 88 | 89 | Card.propTypes = { 90 | row: PropTypes.bool, 91 | wrap: PropTypes.bool, 92 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 93 | space: spaces, 94 | children: PropTypes.oneOfType([PropTypes.array, PropTypes.element]) 95 | .isRequired, 96 | horizontal: PropTypes.bool, 97 | vertical: PropTypes.bool, 98 | align: PropTypes.oneOf(['center', 'left', 'right']), 99 | shadow: shadows, 100 | outline: PropTypes.bool, 101 | background: PropTypes.string, 102 | radius: radii, 103 | }; 104 | 105 | Card.defaultProps = { 106 | space: 'lg', 107 | outline: false, 108 | background: 'bg200', 109 | shadow: 'none', 110 | radius: 'sm', 111 | }; 112 | 113 | const styles = StyleSheet.create({ 114 | container: { 115 | width: '100%', 116 | alignItems: 'stretch', 117 | justifyContent: 'center', 118 | }, 119 | }); 120 | 121 | export default Card; 122 | -------------------------------------------------------------------------------- /src/Card/index.js: -------------------------------------------------------------------------------- 1 | import Card from './Card'; 2 | 3 | export { Card }; 4 | -------------------------------------------------------------------------------- /src/CheckBox/CheckBox.example.js: -------------------------------------------------------------------------------- 1 | import React, {useState} from 'react'; 2 | import {select, boolean} from '@storybook/addon-knobs'; 3 | import {CheckBox} from './index'; 4 | import {sizeArray} from '../util/prop-types'; 5 | 6 | export default function ExampleRadioButton() { 7 | const [value, setCheckBoxValue] = useState(false); 8 | return ( 9 | setCheckBoxValue(!value)}> 16 | Hello CheckBox 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /src/CheckBox/CheckBox.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | View, 4 | TouchableOpacity, 5 | TouchableNativeFeedback, 6 | Platform, 7 | StyleSheet, 8 | } from 'react-native'; 9 | import PropTypes from 'prop-types'; 10 | import MaterialIcons from 'react-native-vector-icons/MaterialIcons'; 11 | import {useThemeContext} from '../util/ThemeProvider'; 12 | import {fontBases, fontVariants, sizes} from '../util/prop-types'; 13 | import {Text} from '../Text'; 14 | 15 | const getTextStyle = ({theme, size, textColor, iconRight}) => { 16 | const textStyle = [ 17 | { 18 | marginLeft: theme.space.lg, 19 | }, 20 | ]; 21 | if (iconRight) { 22 | textStyle.push({ 23 | marginLeft: 0, 24 | marginRight: 5, 25 | }); 26 | } 27 | return textStyle; 28 | }; 29 | 30 | const renderIcon = ({style, theme, size, color, ...props}) => { 31 | if (props.checked) { 32 | return ( 33 | props.checkedIcon || ( 34 | 39 | ) 40 | ); 41 | } else { 42 | return ( 43 | props.uncheckedIcon || ( 44 | 49 | ) 50 | ); 51 | } 52 | }; 53 | 54 | const CheckBox = React.forwardRef(({style, textStyle, ...props}, ref) => { 55 | const theme = useThemeContext(); 56 | const propsWithTheme = {...props, theme}; 57 | const TouchableElement = 58 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 59 | return ( 60 | 65 | 66 | {!props.iconRight && renderIcon(propsWithTheme)} 67 | {typeof props.children !== 'function' ? ( 68 | 76 | {props.children} 77 | 78 | ) : ( 79 | props.children 80 | )} 81 | {props.iconRight && renderIcon(propsWithTheme)} 82 | 83 | 84 | ); 85 | }); 86 | 87 | CheckBox.propTypes = { 88 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 89 | textStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 90 | children: PropTypes.oneOfType([PropTypes.string, PropTypes.element]) 91 | .isRequired, 92 | checked: PropTypes.bool, 93 | iconRight: PropTypes.bool, 94 | color: PropTypes.string, 95 | textColor: PropTypes.string, 96 | size: sizes, 97 | onPress: PropTypes.func.isRequired, 98 | checkedIcon: PropTypes.element, 99 | uncheckedIcon: PropTypes.element, 100 | fontBase: fontBases, 101 | fontVariant: fontVariants, 102 | }; 103 | 104 | CheckBox.defaultProps = { 105 | size: 'md', 106 | color: 'primary', 107 | textColor: 'para', 108 | fontBase: 'body', 109 | fontVariant: 'regular', 110 | }; 111 | 112 | const styles = StyleSheet.create({ 113 | container: { 114 | flexDirection: 'row', 115 | alignItems: 'center', 116 | }, 117 | }); 118 | 119 | export default CheckBox; 120 | -------------------------------------------------------------------------------- /src/CheckBox/CheckBox.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs} from '@storybook/addon-knobs'; 3 | import {action} from '@storybook/addon-actions'; 4 | import Stack from '../Layout/Stack'; 5 | import Ionicons from 'react-native-vector-icons/Ionicons'; 6 | import CheckBox from './CheckBox'; 7 | import ExampleCheckBox from './CheckBox.example.js'; 8 | 9 | 10 | 11 | # CheckBox 12 | 13 | Use `CheckBox` when looking for yes or no answers. 14 | 15 | # Usage 16 | 17 | ```js 18 | import {CheckBox} from 'react-native-design-system'; 19 | 20 | this.setState({checked: !this.state.checked})}> 23 | Hello CheckBox 24 | ; 25 | ``` 26 | 27 | # Props 28 | 29 | 30 | 31 | # Size 32 | 33 | There are 9 sizes available bases on fontSize. 34 | 35 | 36 | 37 | 38 | Hello CheckBox 39 | Hello CheckBox 40 | Hello CheckBox 41 | Hello CheckBox 42 | Hello CheckBox 43 | Hello CheckBox 44 | Hello CheckBox 45 | Hello CheckBox 46 | Hello CheckBox 47 | 48 | 49 | 50 | 51 | # Right align icon 52 | 53 | Pass `iconRight={true}` to shift checkbox icon to right. 54 | 55 | 56 | 57 | Hello CheckBox 58 | 59 | 60 | 61 | # Checked 62 | 63 | Pass `checked={true}` to select checkbox. 64 | 65 | 66 | 67 | Hello CheckBox 68 | 69 | 70 | 71 | # Color 72 | 73 | Pass `color` to select from three available brand colors. 74 | 75 | 76 | 77 | 78 | Hello CheckBox 79 | Hello CheckBox 80 | 81 | 82 | 83 | 84 | # Text color 85 | 86 | Pass `textColor` to select from available brand text colors. 87 | 88 | 89 | 90 | 91 | Hello CheckBox 92 | Hello CheckBox 93 | Hello CheckBox 94 | 95 | 96 | 97 | 98 | # Custom icons 99 | 100 | Pass custom icons via `checkedIcon` and `uncheckedIcon` prop. Size and color will be manually set by developer. 101 | 102 | 103 | 104 | 105 | 109 | } 110 | uncheckedIcon={ 111 | 112 | }> 113 | Hello CheckBox 114 | 115 | 119 | } 120 | uncheckedIcon={ 121 | 122 | }> 123 | Hello CheckBox 124 | 125 | 126 | 127 | 128 | 129 | # Playground 130 | 131 | Play with CheckBox in Canvas mode. 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /src/CheckBox/index.js: -------------------------------------------------------------------------------- 1 | import CheckBox from './CheckBox'; 2 | export { CheckBox }; 3 | -------------------------------------------------------------------------------- /src/CircularProgressBar/CircularProgressBar.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React, { useEffect } from 'react'; 3 | import { Animated, Easing, StyleSheet, View } from 'react-native'; 4 | import { extractAccessibilityPropsFromProps } from '../util/accessibility'; 5 | 6 | const CircularProgressBar = (props) => { 7 | const { 8 | activeColor, 9 | passiveColor, 10 | baseColor, 11 | radius, 12 | percent, 13 | width, 14 | duration, 15 | children, 16 | ...rest 17 | } = props; 18 | 19 | const initialValueHalfCircle = percent >= 50 ? 0 : 180; 20 | const initialValueInnerCircle = 0; 21 | const firstCircleAnimatedValue = new Animated.Value(initialValueHalfCircle); 22 | const secondCircleAnimatedValue = new Animated.Value(initialValueHalfCircle); 23 | const thirdCircleAnimatedValue = new Animated.Value(initialValueInnerCircle); 24 | const timePerDegree = duration / 360; 25 | const firstCircleColor = activeColor; 26 | const secondCircleColor = percent >= 50 ? activeColor : passiveColor; 27 | 28 | const secondAnimation = () => { 29 | firstCircleAnimatedValue.setValue(initialValueHalfCircle); 30 | secondCircleAnimatedValue.setValue(initialValueHalfCircle); 31 | thirdCircleAnimatedValue.setValue(initialValueHalfCircle); 32 | Animated.parallel([ 33 | Animated.timing(firstCircleAnimatedValue, { 34 | toValue: 180, 35 | duration: 180 * timePerDegree, 36 | useNativeDriver: true, 37 | easing: Easing.linear, 38 | }), 39 | Animated.timing(secondCircleAnimatedValue, { 40 | toValue: 180 + (percent - 50) * 3.6, 41 | duration: (180 + (percent - 50) * 3.6) * timePerDegree, 42 | useNativeDriver: true, 43 | easing: Easing.linear, 44 | }), 45 | Animated.timing(thirdCircleAnimatedValue, { 46 | toValue: (percent - 50) * 3.6, 47 | delay: 180 * timePerDegree, 48 | duration: timePerDegree * ((percent - 50) * 3.6), 49 | useNativeDriver: false, 50 | easing: Easing.linear, 51 | }), 52 | ]).start(); 53 | }; 54 | 55 | const firstAnimation = () => { 56 | Animated.timing(secondCircleAnimatedValue, { 57 | toValue: 180 + percent * 3.6, 58 | duration: percent * 3.6 * timePerDegree, 59 | useNativeDriver: true, 60 | easing: Easing.linear, 61 | }).start(); 62 | }; 63 | 64 | useEffect(() => { 65 | if (percent < 50) { 66 | firstAnimation(); 67 | } else { 68 | secondAnimation(); 69 | } 70 | }); 71 | 72 | const renderHalf = (color, transforms = [], otherStyles = {}) => ( 73 | 88 | ); 89 | 90 | const rotate1 = firstCircleAnimatedValue.interpolate({ 91 | inputRange: [0, 1], 92 | outputRange: ['0deg', '1deg'], 93 | }); 94 | 95 | const rotate2 = secondCircleAnimatedValue.interpolate({ 96 | inputRange: [0, 1], 97 | outputRange: ['0deg', '1deg'], 98 | }); 99 | 100 | const rotate3 = thirdCircleAnimatedValue.interpolate({ 101 | inputRange: [0, 1], 102 | outputRange: ['0deg', '1deg'], 103 | }); 104 | 105 | const elevation3 = thirdCircleAnimatedValue.interpolate({ 106 | inputRange: [0, 1], 107 | outputRange: [0, -1], 108 | }); 109 | 110 | const innerCircleStyle = { 111 | backgroundColor: baseColor, 112 | width: 2 * radius - width, 113 | height: 2 * radius - width, 114 | borderRadius: radius, 115 | elevation: 1000, 116 | display: 'flex', 117 | justifyContent: 'center', 118 | alignItems: 'center', 119 | }; 120 | 121 | return ( 122 | 123 | 134 | {renderHalf(firstCircleColor, [{ rotate: rotate1 }])} 135 | {renderHalf(secondCircleColor, [{ rotate: rotate2 }])} 136 | {renderHalf(passiveColor, [{ rotate: rotate3 }], { 137 | elevation: elevation3, zIndex: elevation3, 138 | })} 139 | { 140 | {children} 141 | } 142 | 143 | 144 | ); 145 | }; 146 | 147 | CircularProgressBar.propTypes = { 148 | activeColor: PropTypes.string.isRequired, 149 | passiveColor: PropTypes.string.isRequired, 150 | baseColor: PropTypes.string.isRequired, 151 | width: PropTypes.number.isRequired, 152 | radius: PropTypes.number.isRequired, 153 | percent: PropTypes.number.isRequired, 154 | duration: PropTypes.number.isRequired, 155 | children: PropTypes.element, 156 | }; 157 | 158 | const styles = StyleSheet.create({ 159 | container: { 160 | flex: 1, 161 | backgroundColor: '#fff', 162 | alignItems: 'center', 163 | justifyContent: 'center', 164 | }, 165 | outerCircle: { 166 | position: 'relative', 167 | justifyContent: 'center', 168 | alignItems: 'center', 169 | overflow: 'hidden', 170 | 171 | }, 172 | half: { 173 | position: 'absolute', 174 | left: 0, 175 | top: 0, 176 | borderTopRightRadius: 0, 177 | borderBottomRightRadius: 0, 178 | }, 179 | }); 180 | 181 | export default CircularProgressBar; 182 | -------------------------------------------------------------------------------- /src/CircularProgressBar/CircularProgressBar.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import { 3 | withKnobs, 4 | select, 5 | boolean, 6 | color, 7 | number, 8 | } from '@storybook/addon-knobs'; 9 | import {Text} from 'react-native'; 10 | import {action} from '@storybook/addon-actions'; 11 | import Stack from '../Layout/Stack'; 12 | import CircularProgressBar from './CircularProgressBar'; 13 | 14 | 15 | 16 | # CircularProgressBar 17 | 18 | Animated circular progress bar for cross plateform. 19 | 20 | # Usage 21 | 22 | ```js 23 | import {CircularProgressBar} from 'react-native-design-system'; 24 | 25 | 33 | Wow! 34 | ; 35 | ``` 36 | 37 | # Props 38 | 39 | 40 | 41 | # Playground 42 | 43 | This component is fully customizable. Go on, play with CircularProgressBar inside Canvas. 44 | 45 | 46 | 54 | Wow! 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/CircularProgressBar/index.js: -------------------------------------------------------------------------------- 1 | import CircularProgressBar from './CircularProgressBar'; 2 | export { CircularProgressBar }; 3 | -------------------------------------------------------------------------------- /src/Deck/Deck.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DeckHorizontal from './DeckHorizontal'; 3 | import DeckVertical from './DeckVertical'; 4 | import DeckVerticalBasic from './DeckVerticalBasic'; 5 | 6 | export default function Deck({ direction, allowBackSwipe, ...props }) { 7 | return direction === 'horizontal' 8 | ? 9 | : allowBackSwipe 10 | ? 11 | : ; 12 | } 13 | -------------------------------------------------------------------------------- /src/Deck/Deck.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks'; 2 | import { withKnobs, select, boolean, color, number } from "@storybook/addon-knobs"; 3 | import { View, Text, Image } from "react-native"; 4 | import { action } from '@storybook/addon-actions'; 5 | import Stack from '../Layout/Stack'; 6 | import Deck from './Deck'; 7 | 8 | 9 | 10 | # Deck 11 | Swippable Deck component. 12 | 13 | # Usage 14 | ```js 15 | import { Deck } from 'react-native-design-system'; 16 | 17 | item.id.toString()} 37 | renderItem={item => { 38 | return ( 39 | 40 | 41 | 42 | ); 43 | }} 44 | /> 45 | ``` 46 | 47 | # Props 48 | 49 | 50 | # data 51 | 52 | Pass array of items you want to render. Works just like `` 53 | 54 | # renderItem 55 | 56 | Pass a callback function to render each item. Function receives `item` as argument and returns react element. Works just like `` 57 | 58 | # keyExtractor 59 | 60 | Pass a function that returns unique id as strings. Function receives `item` as argument. Works just like `` 61 | 62 | # direction 63 | 64 | Pass `direction` as `vertical` or `horizontal` to change direction of swipe. Default is `horzintal`. 65 | 66 | # loop 67 | 68 | Pass `loop={true}` to repeat the data array when all items are swiped. Default is `false`. 69 | 70 | # fade 71 | 72 | Pass `fade={true}` to reduce opacity as the user swipes. Default is `true`. 73 | 74 | # onPositiveSwipe 75 | 76 | Pass a function to be called when item has been swiped right in case of `direction="horizontal"` and up in case of `direction="vertical"`. 77 | 78 | # onNegativeSwipe 79 | 80 | Pass a function to be called when item has been swiped left in case of `direction="horizontal"` and down in case of `direction="vertical"`. 81 | 82 | # loadMoreCards 83 | 84 | Pass an async function (promise) to load more cards from all cards are swiped. This function will receive `page` as argument which is integer value for pagination and should return new batch of items in an array. We take care of concatinating received data inside Deck component, you just have to return an array with new data. 85 | 86 | # loadInitialData 87 | 88 | Pass `loadInitialData={true}` when passing `data={[]}` as empty array. Deck component will use `loadMoreCards` to fetch the initial batch of data. We show a loading screen while fetching data, you can pass this loading screen yourself. See next prop. 89 | 90 | # loadingScreen 91 | 92 | React component to show while fetching data, this component will be used at initial screen when `loadInitialData={true}`. 93 | 94 | # Playground 95 | This component is fully customizable. Go on, play with Deck inside Canvas. 96 | 97 | 98 | item.toString()} 106 | renderItem={item => { 107 | return ( 108 | 109 | 110 | Adorable Kittens 😍 111 | 112 | ); 113 | }} 114 | direction={select('direction', ['horizontal', 'vertical'], 'horizontal')} 115 | fade={boolean('fade', false)} 116 | loop={boolean('loop', true)} 117 | onPositiveSwipe={action('swipped up or right')} 118 | onNegativeSwipe={action('swipped down or left')} 119 | /> 120 | 121 | -------------------------------------------------------------------------------- /src/Deck/index.js: -------------------------------------------------------------------------------- 1 | import Deck from './Deck'; 2 | 3 | export { Deck }; 4 | -------------------------------------------------------------------------------- /src/DismissKeyboard/DismissKeyboard.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Keyboard, TouchableWithoutFeedback} from 'react-native'; 3 | import {extractAccessibilityPropsFromProps} from '../util/accessibility'; 4 | 5 | const DismissKeyboard = ({children, style, ...rest}) => { 6 | return ( 7 | Keyboard.dismiss()} 9 | style={style} 10 | {...extractAccessibilityPropsFromProps(rest)}> 11 | {children} 12 | 13 | ); 14 | }; 15 | 16 | export default DismissKeyboard; 17 | -------------------------------------------------------------------------------- /src/DismissKeyboard/index.js: -------------------------------------------------------------------------------- 1 | import DismissKeyboard from './DismissKeyboard'; 2 | export {DismissKeyboard}; 3 | -------------------------------------------------------------------------------- /src/FullScreenLoader/FullScreenLoader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StyleSheet, ActivityIndicator, Text} from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import {extractAccessibilityPropsFromProps} from '../util/accessibility'; 6 | 7 | const FullScreenLoader = props => { 8 | const theme = useThemeContext(); 9 | const backgroundStyles = { 10 | backgroundColor: theme.colors[props.background], 11 | }; 12 | if (props.loading) { 13 | return ( 14 | 21 | 26 | {props.children} 27 | 28 | ); 29 | } else { 30 | return null; 31 | } 32 | }; 33 | 34 | FullScreenLoader.propTypes = { 35 | loading: PropTypes.bool, 36 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 37 | children: PropTypes.element, 38 | indicatorColor: PropTypes.string, 39 | background: PropTypes.string, 40 | size: PropTypes.oneOf(['small', 'large']), 41 | }; 42 | 43 | FullScreenLoader.defaultProps = { 44 | size: 'large', 45 | background: 'bg300', 46 | indicatorColor: '#1e88e5', 47 | loading: true, 48 | }; 49 | 50 | const styles = StyleSheet.create({ 51 | container: { 52 | position: 'absolute', 53 | zIndex: 1000, 54 | width: '100%', 55 | height: '100%', 56 | justifyContent: 'center', 57 | alignItems: 'center', 58 | }, 59 | indicator: { 60 | padding: 10, 61 | }, 62 | }); 63 | 64 | export default FullScreenLoader; 65 | -------------------------------------------------------------------------------- /src/FullScreenLoader/FullScreenLoader.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select, boolean, color} from '@storybook/addon-knobs'; 3 | import {View} from 'react-native'; 4 | import FullScreenLoader from './FullScreenLoader'; 5 | import {Text} from '../Text'; 6 | 7 | 8 | 9 | # FullScreenLoader 10 | 11 | FullScreenLoader is a loading screen component which sits on top of all the view. It shows an Activity Indicator and restrict touches while spinner is rotating. 12 | 13 | # Usage 14 | 15 | ```js 16 | import { FullScreenLoader } from 'react-native-design-system'; 17 | 18 | 21 | ``` 22 | 23 | # Props 24 | 25 | 26 | 27 | # Loading 28 | 29 | Passing `loading={true}` makes the loading screen visible. View will be unmounted when `loading` changes to `false`. 30 | 31 | # Indicator Color 32 | 33 | Pass any theme color in `indicatorColor` prop for desired result. Passed color should be present in `colors` of `theme`. 34 | 35 | # Background 36 | 37 | Pass any theme color in `background` prop for set desired Background. Passed color should be present in `colors` of `theme`. 38 | 39 | # Size 40 | 41 | Size gives the size of Indicator: `small` and `large`. 42 | 43 | # Children 44 | 45 | If you want to pass any element to render with spinner. 46 | 47 | # Playground 48 | 49 | Play with FullScreenLoader in Canvas mode. 50 | 51 | 52 | 53 | 54 | 59 | Loading... 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/FullScreenLoader/index.js: -------------------------------------------------------------------------------- 1 | import FullScreenLoader from './FullScreenLoader'; 2 | export { FullScreenLoader }; 3 | -------------------------------------------------------------------------------- /src/Header/Header.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { 4 | Platform, 5 | SafeAreaView, 6 | StatusBar, 7 | StyleSheet, 8 | Text, 9 | TouchableNativeFeedback, 10 | TouchableOpacity, 11 | View, 12 | } from 'react-native'; 13 | import {extractAccessibilityPropsFromProps} from '../util/accessibility'; 14 | import {shadows, sizes} from '../util/prop-types'; 15 | import {useThemeContext} from '../util/ThemeProvider'; 16 | 17 | const getContainerStyle = ({theme, color}) => { 18 | const headerStyle = [styles.container]; 19 | headerStyle.push({ 20 | backgroundColor: theme.colors[color], 21 | }); 22 | return headerStyle; 23 | }; 24 | 25 | const getTextStyle = ({theme, color, textAlign, fontSize}) => { 26 | const textStyle = [styles.text]; 27 | textStyle.push({ 28 | backgroundColor: theme.colors[color], 29 | fontSize: theme.fontSize[fontSize], 30 | }); 31 | if (textAlign) { 32 | textStyle.push({ 33 | textAlign: textAlign, 34 | }); 35 | } 36 | return textStyle; 37 | }; 38 | 39 | const Header = React.forwardRef(({style, textStyle, shadow, ...props}, ref) => { 40 | const theme = useThemeContext(); 41 | const TouchableElement = 42 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 43 | return ( 44 | 53 | 57 | 63 | {props.leftIcon && ( 64 | 65 | 67 | {props.leftIcon} 68 | 69 | 70 | )} 71 | {!!props.children && ( 72 | 77 | {props.children} 78 | 79 | )} 80 | {props.rightIcon && ( 81 | 82 | 84 | {props.rightIcon} 85 | 86 | 87 | )} 88 | 89 | 90 | ); 91 | }); 92 | 93 | Header.propTypes = { 94 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 95 | textStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 96 | textAlign: PropTypes.oneOf(['auto', 'left', 'center', 'right', 'justify']), 97 | fontSize: sizes, 98 | children: PropTypes.string, 99 | color: PropTypes.string, 100 | leftIcon: PropTypes.element, 101 | onLeftIconPress: PropTypes.func, 102 | rightIcon: PropTypes.element, 103 | onRightIconPress: PropTypes.func, 104 | iconStyle: PropTypes.object, 105 | barColor: PropTypes.string, 106 | barStyle: PropTypes.oneOf(['default', 'dark-content', 'light-content']), 107 | shadow: shadows, 108 | }; 109 | 110 | Header.defaultProps = { 111 | color: 'primary', 112 | barColor: 'primary', 113 | barStyle: 'light-content', 114 | fontSize: 'md', 115 | shadow: 'md', 116 | }; 117 | 118 | const styles = StyleSheet.create({ 119 | safeAreaView: { 120 | zIndex: 10, 121 | }, 122 | container: { 123 | width: '100%', 124 | height: Platform.select({ 125 | android: 56, 126 | ios: 56, 127 | web: 64, 128 | }), 129 | flexDirection: 'row', 130 | alignItems: 'center', 131 | zIndex: 10, 132 | }, 133 | text: { 134 | flex: 1, 135 | fontWeight: Platform.select({ 136 | android: '600', 137 | ios: '500', 138 | web: '600', 139 | }), 140 | textAlign: Platform.select({ 141 | android: 'left', 142 | ios: 'center', 143 | web: 'left', 144 | }), 145 | color: '#fff', 146 | paddingHorizontal: 15, 147 | }, 148 | iconStyle: { 149 | padding: 10, 150 | }, 151 | }); 152 | 153 | export default Header; 154 | -------------------------------------------------------------------------------- /src/Header/Header.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select} from '@storybook/addon-knobs'; 3 | import {View} from 'react-native'; 4 | import {action} from '@storybook/addon-actions'; 5 | import EvilIcons from 'react-native-vector-icons/EvilIcons'; 6 | import Feather from 'react-native-vector-icons/Feather'; 7 | import Header from './Header'; 8 | import Stack from '../Layout/Stack'; 9 | import {sizeArray} from '../util/prop-types'; 10 | 11 | 12 | 13 | # Header 14 | 15 | Header is just a fixed Header bar that sits on top of screen. 16 | 17 | # Usage 18 | 19 | ```js 20 | import {Header} from 'react-native-design-system'; 21 | 22 |
Home
; 23 | ``` 24 | 25 | > If you're using `Expo` then you have to provide top margin for StatusBar: 26 | 27 | ```js 28 | import { Constants } from 'expo' 29 | 30 | ... 31 | headerStyle: { marginTop: Constants.statusBarHeight }, 32 | ``` 33 | 34 | # Props 35 | 36 | 37 | 38 | # Text Align 39 | 40 | You can align Header title position by passing `auto`,`left`, `center`, `right` or `justify` as `textAlign` property. 41 | 42 | 43 | 44 | 45 |
Home
46 |
Home
47 |
Home
48 |
49 |
50 |
51 | 52 | # Font Size 53 | 54 | There are 7 font sizes available from `xs` to `9xl`. 55 | 56 | 57 | 58 | 59 |
Home
60 |
Home
61 |
Home
62 |
63 |
64 |
65 | 66 | # Color 67 | 68 | Color takes any string defined in `color` of `theme` file. 69 | 70 | 71 | 72 | 73 |
Home
74 |
Home
75 |
Home
76 |
77 |
78 |
79 | 80 | # Icons 81 | 82 | You can pass `leftIcon` and `rightIcon` with `onLeftIconPress` and `onRightIconPress` handler. Size, type and color of icon is upto developer. 83 | 84 | 85 | 86 |
} 88 | rightIcon={} 89 | onLeftIconPress={action('left icon pressed')} 90 | onRightIconPress={action('right icon pressed')}> 91 | Home 92 |
93 |
94 |
95 | 96 | # Bar Color 97 | 98 | You can pass StatusBar **backgroundColor** as `barColor` and **barStyle** for StatusBar `barColor` 99 | 100 | # Icon Styles 101 | 102 | You can pass `iconStyle` to pass custom styling for left and right. This is handy when you have to provide some extra padding to the icons. 103 | 104 | # Playground 105 | 106 | Play with Header in Canvas mode. 107 | 108 | 109 |
117 | Home 118 |
119 |
120 | -------------------------------------------------------------------------------- /src/Header/index.js: -------------------------------------------------------------------------------- 1 | import Header from './Header'; 2 | export { Header }; 3 | -------------------------------------------------------------------------------- /src/Image/Image.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Image as RNImage, 4 | Platform, 5 | TouchableNativeFeedback, 6 | TouchableOpacity, 7 | View, 8 | } from 'react-native'; 9 | import PropTypes from 'prop-types'; 10 | import {useThemeContext} from '../util/ThemeProvider'; 11 | import {radii, shadows, spaces} from '../util/prop-types'; 12 | 13 | const getContainerStyle = ({ 14 | theme, 15 | space, 16 | shadow, 17 | outline, 18 | background, 19 | radius, 20 | borderColor, 21 | aspectRatio, 22 | width, 23 | height, 24 | borderWidth, 25 | }) => { 26 | const imageStyle = [ 27 | { 28 | padding: theme.space[space], 29 | backgroundColor: theme.colors[background], 30 | borderRadius: theme.radius[radius], 31 | width, 32 | height, 33 | overflow: 'hidden', 34 | ...theme.shadow[shadow], 35 | }, 36 | ]; 37 | if (outline) { 38 | imageStyle.push({ 39 | borderWidth, 40 | borderColor: theme.colors[borderColor], 41 | }); 42 | } 43 | if (aspectRatio) { 44 | imageStyle.push({ 45 | aspectRatio, 46 | }); 47 | } 48 | return imageStyle; 49 | }; 50 | 51 | const Image = React.forwardRef(({style, ...props}, ref) => { 52 | const theme = useThemeContext(); 53 | const TouchableElement = 54 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 55 | return ( 56 | 57 | 61 | 62 | 63 | 64 | ); 65 | }); 66 | 67 | Image.propTypes = { 68 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 69 | space: spaces, 70 | shadow: shadows, 71 | outline: PropTypes.bool, 72 | background: PropTypes.string, 73 | radius: radii, 74 | borderColor: PropTypes.string, 75 | aspectRatio: PropTypes.number, 76 | borderWidth: PropTypes.number, 77 | width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 78 | height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 79 | onPress: PropTypes.func, 80 | }; 81 | 82 | Image.defaultProps = { 83 | space: 'none', 84 | outline: false, 85 | background: 'bgImage', 86 | shadow: 'none', 87 | radius: 'none', 88 | borderColor: 'outline', 89 | width: 250, 90 | height: 250, 91 | borderWidth: 1, 92 | }; 93 | 94 | export default Image; 95 | -------------------------------------------------------------------------------- /src/Image/Image.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select, boolean, color} from '@storybook/addon-knobs'; 3 | import {View, Text, Button} from 'react-native'; 4 | import Image from './Image'; 5 | 6 | 7 | 8 | # Image 9 | 10 | It's just a wrapper around RN Image component to give you more customizations like shadow and radius. 11 | 12 | # Usage 13 | 14 | ```js 15 | import {Image} from 'react-native-design-system'; 16 | 17 | ; 22 | ``` 23 | 24 | # Props 25 | 26 | 27 | 28 | # Styles 29 | 30 | The container receives an `style` props that overrides default styles. 31 | 32 | # Aspect Ratio 33 | 34 | 35 | 36 | 40 | 41 | 42 | 43 | # Radius 44 | 45 | Image curves can be customized with `radius` prop, default is `none`. 46 | 47 | 48 | 49 | 53 | 54 | 55 | 56 | # Shadow 57 | 58 | Image shadows can be customized with `shadow` prop, default is `none`. 59 | 60 | 61 | 62 | 66 | 67 | 68 | 69 | # Outline 70 | 71 | Image outline can be customized with `outline` prop, default is `false`. 72 | 73 | 74 | 75 | 82 | 83 | 84 | 85 | # Width and Height 86 | 87 | Image size can be updated with width and height 88 | 89 | 90 | 91 | 96 | 97 | 98 | 99 | # On Press 100 | 101 | Image is ofcourse pressable, just pass `onPress` 102 | 103 | 104 | 105 | console.log('pressed')} 107 | source={{uri: 'https://www.github.com/iamshadmirza.png'}} 108 | /> 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/Image/index.js: -------------------------------------------------------------------------------- 1 | import Image from './Image'; 2 | export {Image}; 3 | -------------------------------------------------------------------------------- /src/Input/Input.example.js: -------------------------------------------------------------------------------- 1 | import React, {useState} from 'react'; 2 | import Input from './Input'; 3 | import {select, boolean, text} from '@storybook/addon-knobs'; 4 | import {sizeArray} from '../util/prop-types'; 5 | 6 | export default function ExampleInput() { 7 | const [textValue, setTextValue] = useState(''); 8 | return ( 9 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /src/Input/index.js: -------------------------------------------------------------------------------- 1 | import Input from './Input'; 2 | export { Input }; 3 | -------------------------------------------------------------------------------- /src/Layout/Box.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StyleSheet} from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import {spaces} from '../util/prop-types'; 6 | 7 | const getContainerStyle = ({theme, space, background}) => { 8 | return { 9 | padding: theme.space[space], 10 | background: theme.colors[background], 11 | alignItems: 'center', 12 | justifyContent: 'center', 13 | }; 14 | }; 15 | 16 | const Box = props => { 17 | const theme = useThemeContext(); 18 | return ( 19 | 25 | {props.children} 26 | 27 | ); 28 | }; 29 | 30 | Box.propTypes = { 31 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 32 | background: PropTypes.string, 33 | space: spaces, 34 | children: PropTypes.oneOfType([PropTypes.array, PropTypes.element]) 35 | .isRequired, 36 | }; 37 | 38 | Box.defaultProps = { 39 | space: 'md', 40 | background: 'transparent', 41 | }; 42 | 43 | export default Box; 44 | -------------------------------------------------------------------------------- /src/Layout/Box.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select} from '@storybook/addon-knobs'; 3 | import {action} from '@storybook/addon-actions'; 4 | import Button from '../Button/Button'; 5 | import Box from './Box'; 6 | import {spaceArray} from '../util/prop-types'; 7 | 8 | 9 | 10 | # Box 11 | 12 | Box is a simple layout container which accepts a child and provide padding around it. The child is centered by default. 13 | 14 | # Usage 15 | 16 | ```js 17 | import {Box} from 'react-native-design-system'; 18 | 19 | 20 | 21 | ; 22 | ``` 23 | 24 | # Props 25 | 26 | 27 | 28 | # Space 29 | 30 | `space` receives values from `none`, `xs` upto `9xl`. 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | # Background 41 | 42 | You can also pass a `background` color. Color string should be present inside `colors` of theme. 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | # Playground 53 | 54 | Play with Box in Canvas mode. 55 | 56 | 57 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/Layout/Flex.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StyleSheet} from 'react-native'; 3 | import PropTypes, {number} from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import {spaces} from '../util/prop-types'; 6 | 7 | const getContainerStyle = ({ 8 | theme, 9 | space, 10 | background, 11 | flex, 12 | flexDirection, 13 | alignItems, 14 | justifyContent, 15 | flexWrap, 16 | alignContent, 17 | alignSelf, 18 | }) => { 19 | const styles = { 20 | flex: flex, 21 | flexDirection, 22 | alignItems, 23 | justifyContent, 24 | padding: theme.space[space], 25 | background: theme.colors[background], 26 | }; 27 | if (flexWrap) { 28 | styles.flexWrap = flexWrap; 29 | } 30 | if (alignContent) { 31 | styles.alignContent = alignContent; 32 | } 33 | if (alignSelf) { 34 | styles.alignSelf = alignSelf; 35 | } 36 | return styles; 37 | }; 38 | 39 | const Flex = props => { 40 | const theme = useThemeContext(); 41 | return ( 42 | 48 | {props.children} 49 | 50 | ); 51 | }; 52 | 53 | Flex.propTypes = { 54 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 55 | background: PropTypes.string, 56 | space: spaces, 57 | flexDirection: PropTypes.oneOf([ 58 | 'row', 59 | 'column', 60 | 'row-reverse', 61 | 'column-reverse', 62 | ]), 63 | alignItems: PropTypes.oneOf([ 64 | 'flex-start', 65 | 'flex-end', 66 | 'center', 67 | 'stretch', 68 | 'baseline', 69 | ]), 70 | alignSelf: PropTypes.oneOf([ 71 | 'flex-start', 72 | 'flex-end', 73 | 'center', 74 | 'stretch', 75 | 'baseline', 76 | ]), 77 | justifyContent: PropTypes.oneOf([ 78 | 'flex-start', 79 | 'flex-end', 80 | 'center', 81 | 'space-between', 82 | 'space-around', 83 | 'space-evenly', 84 | ]), 85 | alignContent: PropTypes.oneOf([ 86 | 'flex-start', 87 | 'flex-end', 88 | 'center', 89 | 'space-between', 90 | 'space-around', 91 | 'space-evenly', 92 | ]), 93 | flex: number, 94 | flexWrap: PropTypes.oneOf(['no-wrap', 'wrap', 'wrap-reverse']), 95 | children: PropTypes.oneOfType([PropTypes.array, PropTypes.element]) 96 | .isRequired, 97 | }; 98 | 99 | Flex.defaultProps = { 100 | flex: 1, 101 | flexDirection: 'row', 102 | space: 'none', 103 | background: 'transparent', 104 | }; 105 | 106 | export default Flex; 107 | -------------------------------------------------------------------------------- /src/Layout/Flex.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select} from '@storybook/addon-knobs'; 3 | import {action} from '@storybook/addon-actions'; 4 | import Button from '../Button/Button'; 5 | import Avatar from '../Avatar/Avatar'; 6 | import Text from '../Text/Text'; 7 | import Stack from '../Layout/Stack'; 8 | import Flex from './Flex'; 9 | import {spaceArray} from '../util/prop-types'; 10 | 11 | 12 | 13 | # Flex 14 | 15 | Flex is a simple layout container works as a Flex box. 16 | 17 | # Usage 18 | 19 | ```js 20 | import {Flex} from 'react-native-design-system'; 21 | 22 | 23 | 24 | ; 25 | ``` 26 | 27 | # Props 28 | 29 | 30 | 31 | # Space 32 | 33 | `space` receives values from `none`, `xs` upto `9xl`. 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | # Background 44 | 45 | You can also pass a `background` color. Color string should be present inside `colors` of theme. 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | # Demo 56 | 57 | You can use Flex component to build your card ui 58 | 59 | 60 | 61 | 62 | 63 | 64 | Heading 65 | 66 | Subtitle 67 | 68 | 69 | 70 | 71 | 72 | 73 | # Playground 74 | 75 | Play with Flex in Canvas mode. 76 | 77 | 78 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/Layout/Spacer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View} from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import {spaces} from '../util/prop-types'; 6 | 7 | const getContainerStyle = ({ 8 | theme, 9 | m, 10 | mv, 11 | mh, 12 | mt, 13 | mb, 14 | ml, 15 | mr, 16 | p, 17 | pv, 18 | ph, 19 | pt, 20 | pb, 21 | pl, 22 | pr, 23 | }) => { 24 | const style = {}; 25 | if (m) { 26 | style.margin = theme.space[m]; 27 | } 28 | if (mv) { 29 | style.marginVertical = theme.space[mv]; 30 | } 31 | if (mh) { 32 | style.marginHorizontal = theme.space[mh]; 33 | } 34 | if (mt) { 35 | style.marginTop = theme.space[mt]; 36 | } 37 | if (mb) { 38 | style.marginBottom = theme.space[mb]; 39 | } 40 | if (ml) { 41 | style.marginLeft = theme.space[ml]; 42 | } 43 | if (mr) { 44 | style.marginRight = theme.space[mr]; 45 | } 46 | if (p) { 47 | style.padding = theme.space[p]; 48 | } 49 | if (pv) { 50 | style.paddingVertical = theme.space[pv]; 51 | } 52 | if (ph) { 53 | style.paddingHorizontal = theme.space[ph]; 54 | } 55 | if (pt) { 56 | style.paddingTop = theme.space[pt]; 57 | } 58 | if (pb) { 59 | style.paddingBottom = theme.space[pb]; 60 | } 61 | if (pl) { 62 | style.paddingLeft = theme.space[pl]; 63 | } 64 | if (pr) { 65 | style.paddingRight = theme.space[pr]; 66 | } 67 | return style; 68 | }; 69 | 70 | const Spacer = ({style, children, ...props}) => { 71 | const theme = useThemeContext(); 72 | return ( 73 | 74 | {children} 75 | 76 | ); 77 | }; 78 | 79 | Spacer.propTypes = { 80 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 81 | m: spaces, 82 | mv: spaces, 83 | mh: spaces, 84 | mt: spaces, 85 | mb: spaces, 86 | ml: spaces, 87 | mr: spaces, 88 | p: spaces, 89 | pv: spaces, 90 | ph: spaces, 91 | pt: spaces, 92 | pb: spaces, 93 | pl: spaces, 94 | pr: spaces, 95 | children: PropTypes.oneOfType([PropTypes.array, PropTypes.element]) 96 | .isRequired, 97 | }; 98 | 99 | export default Spacer; 100 | -------------------------------------------------------------------------------- /src/Layout/Stack.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StyleSheet, ScrollView} from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import {removeAccessibilityPropsFromProps} from '../util/accessibility'; 6 | import {spaces} from '../util/prop-types'; 7 | 8 | const getChildrenStyle = ( 9 | { 10 | direction, 11 | theme, 12 | space, 13 | verticalSpace, 14 | horizontalSpace, 15 | cropEndSpace, 16 | children, 17 | }, 18 | index, 19 | ) => { 20 | if (direction === 'vertical') { 21 | const childStyle = [ 22 | { 23 | marginBottom: theme.space[space], 24 | }, 25 | ]; 26 | if (index === 0) { 27 | childStyle.push({ 28 | marginTop: theme.space[space], 29 | }); 30 | } 31 | if (horizontalSpace) { 32 | childStyle.push({ 33 | marginHorizontal: theme.space[horizontalSpace], 34 | }); 35 | } 36 | if (cropEndSpace) { 37 | if (index === 0) { 38 | childStyle.push({ 39 | marginTop: 0, 40 | }); 41 | } 42 | if (index === React.Children.count(children) - 1) { 43 | childStyle.push({ 44 | marginBottom: 0, 45 | }); 46 | } 47 | } 48 | return childStyle; 49 | } else { 50 | const childStyle = [ 51 | { 52 | marginRight: theme.space[space], 53 | }, 54 | ]; 55 | if (index === 0) { 56 | childStyle.push({ 57 | marginLeft: theme.space[space], 58 | }); 59 | } 60 | if (verticalSpace) { 61 | childStyle.push({ 62 | marginVertical: theme.space[verticalSpace], 63 | }); 64 | } 65 | if (cropEndSpace) { 66 | if (index === 0) { 67 | childStyle.push({ 68 | marginLeft: 0, 69 | }); 70 | } 71 | if (index === React.Children.count(children) - 1) { 72 | childStyle.push({ 73 | marginRight: 0, 74 | }); 75 | } 76 | } 77 | return childStyle; 78 | } 79 | }; 80 | 81 | const Stack = React.forwardRef((props, ref) => { 82 | const theme = useThemeContext(); 83 | const Container = props.scrollable ? ScrollView : View; 84 | const {direction, style, children, ...otherProps} = props; 85 | return ( 86 | 94 | {React.Children.toArray(children).map((item, index) => ( 95 | 106 | {item} 107 | 108 | ))} 109 | 110 | ); 111 | }); 112 | 113 | Stack.propTypes = { 114 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 115 | space: spaces, 116 | horizontalSpace: spaces, 117 | verticalSpace: spaces, 118 | children: PropTypes.oneOfType([PropTypes.array, PropTypes.element]) 119 | .isRequired, 120 | direction: PropTypes.oneOf(['vertical', 'horizontal']).isRequired, 121 | cropEndSpace: PropTypes.bool, 122 | background: PropTypes.string, 123 | scrollable: PropTypes.bool, 124 | }; 125 | 126 | Stack.defaultProps = { 127 | space: 'md', 128 | horizontalSpace: 'none', 129 | verticalSpace: 'none', 130 | cropEndSpace: false, 131 | direction: 'vertical', 132 | scrollable: false, 133 | background: 'transparent', 134 | }; 135 | 136 | const styles = StyleSheet.create({ 137 | container: { 138 | flexDirection: 'row', 139 | alignItems: 'center', 140 | flexGrow: 1, 141 | flexWrap: 'wrap', 142 | }, 143 | }); 144 | 145 | export default Stack; 146 | -------------------------------------------------------------------------------- /src/Layout/Stack.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select, boolean} from '@storybook/addon-knobs'; 3 | import {action} from '@storybook/addon-actions'; 4 | import Input from '../Input/Input'; 5 | import Button from '../Button/Button'; 6 | import Stack from './Stack'; 7 | import {spaceArray} from '../util/prop-types'; 8 | 9 | 10 | 11 | # Stack 12 | 13 | Stack is a layout container which alligns it's children vertrically (stack) and provide constant margin around them. 14 | 15 | # Usage 16 | 17 | ```js 18 | import {Stack, Input} from 'react-native-design-system'; 19 | 20 | 21 | handleUsernameChange(text)} 26 | /> 27 | handleEmailChange(text)} 32 | /> 33 | handlePasswordChange(text)} 38 | /> 39 | ; 40 | ``` 41 | 42 | # Props 43 | 44 | 45 | 46 | # Space 47 | 48 | `space` receives values from `none`, `xs` upto `9xl`. 49 | 50 | 51 | 52 | 53 | action('pressed')} 58 | /> 59 | action('pressed')} 64 | /> 65 | action('pressed')} 70 | /> 71 | 72 | 73 | 74 | 75 | # Direction 76 | 77 | Give `direction="horizontal"` to make it behave like Inline. Direction can either be "vertical" or "horizontal". Default is "vertical". 78 | 79 | # Horizontal Space 80 | 81 | `horizontalSpace` prop adds horizontal spacing. Default is `none` but you can any of the 8 spacing values provided. 82 | 83 | 84 | 85 | 86 | action('pressed')} 91 | /> 92 | action('pressed')} 97 | /> 98 | action('pressed')} 103 | /> 104 | 105 | 106 | 107 | 108 | # Playground 109 | 110 | Play with Stack in Canvas mode. 111 | 112 | 113 | 118 | action('pressed')} 124 | /> 125 | action('pressed')} 131 | /> 132 | action('pressed')} 138 | /> 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/Layout/StackList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, FlatList, StyleSheet} from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import {spaces} from '../util/prop-types'; 6 | 7 | const getChildrenStyle = ( 8 | {theme, space, horizontalSpace, cropEndSpace, data}, 9 | index, 10 | ) => { 11 | const childStyle = [ 12 | { 13 | marginBottom: theme.space[space], 14 | }, 15 | ]; 16 | if (index === 0) { 17 | childStyle.push({ 18 | marginTop: theme.space[space], 19 | }); 20 | } 21 | if (horizontalSpace) { 22 | childStyle.push({ 23 | marginHorizontal: theme.space[horizontalSpace], 24 | }); 25 | } 26 | if (cropEndSpace) { 27 | if (index === 0) { 28 | childStyle.push({ 29 | marginTop: 0, 30 | }); 31 | } 32 | if (index === data.length - 1) { 33 | childStyle.push({ 34 | marginBottom: 0, 35 | }); 36 | } 37 | } 38 | return childStyle; 39 | }; 40 | 41 | const StackList = React.forwardRef((props, ref) => { 42 | const theme = useThemeContext(); 43 | return ( 44 | ( 52 | 53 | {props.renderItem(child)} 54 | 55 | )} 56 | /> 57 | ); 58 | }); 59 | 60 | StackList.propTypes = { 61 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 62 | space: spaces, 63 | horizontalSpace: spaces, 64 | background: PropTypes.string, 65 | cropEndSpace: PropTypes.bool, 66 | ...FlatList.propTypes, 67 | }; 68 | 69 | StackList.defaultProps = { 70 | space: 'md', 71 | horizontalSpace: 'none', 72 | cropEndSpace: true, 73 | background: 'bg300', 74 | }; 75 | 76 | export default StackList; 77 | -------------------------------------------------------------------------------- /src/Layout/TileList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, FlatList} from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import {spaces} from '../util/prop-types'; 6 | 7 | const getChildrenStyle = ( 8 | {theme, space, horizontalSpace, cropEndSpace, data}, 9 | index, 10 | ) => { 11 | const childStyle = [ 12 | { 13 | marginLeft: theme.space[space], 14 | marginTop: theme.space[space], 15 | }, 16 | ]; 17 | // if (index === 0) { 18 | // childStyle.push({ 19 | // marginTop: theme.space[space], 20 | // }); 21 | // } 22 | // if (horizontalSpace) { 23 | // childStyle.push({ 24 | // marginHorizontal: theme.space[horizontalSpace], 25 | 26 | // }); 27 | // } 28 | // if (cropEndSpace) { 29 | // if (index === 0) { 30 | // childStyle.push({ 31 | // marginTop: 0, 32 | // }); 33 | // } 34 | // if (index === data.length - 1) { 35 | // childStyle.push({ 36 | // marginBottom: 0, 37 | // }); 38 | // } 39 | // } 40 | return childStyle; 41 | }; 42 | 43 | const TileList = props => { 44 | const theme = useThemeContext(); 45 | return ( 46 | ( 51 | 52 | {props.renderItem(child)} 53 | 54 | )} 55 | /> 56 | ); 57 | }; 58 | 59 | TileList.propTypes = { 60 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 61 | space: spaces, 62 | horizontalSpace: spaces, 63 | cropEndSpace: PropTypes.bool, 64 | ...FlatList.propTypes, 65 | }; 66 | 67 | TileList.defaultProps = { 68 | space: 'md', 69 | horizontalSpace: 'none', 70 | cropEndSpace: false, 71 | }; 72 | 73 | export default TileList; 74 | -------------------------------------------------------------------------------- /src/Layout/index.js: -------------------------------------------------------------------------------- 1 | import Stack from './Stack'; 2 | import Box from './Box'; 3 | import StackList from './StackList'; 4 | import TileList from './TileList'; 5 | import Flex from './Flex'; 6 | import Spacer from './Spacer'; 7 | 8 | export {Stack, Box, StackList, TileList, Flex, Spacer}; 9 | -------------------------------------------------------------------------------- /src/ListItem/ListItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | View, 4 | TouchableOpacity, 5 | TouchableNativeFeedback, 6 | Platform, 7 | StyleSheet, 8 | } from 'react-native'; 9 | import Feather from 'react-native-vector-icons/Feather'; 10 | import {Avatar} from '../Avatar'; 11 | import {Text} from '../Text'; 12 | import PropTypes from 'prop-types'; 13 | import {useThemeContext} from '../util/ThemeProvider'; 14 | import { 15 | fontBases, 16 | fontVariants, 17 | radii, 18 | shadows, 19 | sizes, 20 | spaces, 21 | } from '../util/prop-types'; 22 | 23 | const getContainerStyle = ({theme, space, background, shadow, radius}) => { 24 | const itemStyle = [styles.container]; 25 | itemStyle.push({ 26 | borderColor: theme.colors.outline, 27 | borderRadius: theme.radius[radius], 28 | backgroundColor: theme.colors[background], 29 | paddingVertical: theme.buttonSize.paddingVertical[space], 30 | paddingHorizontal: theme.space[space], 31 | ...theme.shadow[shadow], 32 | }); 33 | return itemStyle; 34 | }; 35 | 36 | const renderLeftChild = ({avatarSource, leftIcon, iconStyle}) => { 37 | if (avatarSource) { 38 | return ; 39 | } 40 | if (leftIcon) { 41 | return ( 42 | 43 | {leftIcon} 44 | 45 | ); 46 | } 47 | return null; 48 | }; 49 | 50 | const renderRightChild = ({ 51 | chevron, 52 | rightIcon, 53 | iconStyle, 54 | theme, 55 | size, 56 | chevronColor, 57 | }) => { 58 | return ( 59 | <> 60 | {rightIcon && ( 61 | 62 | {rightIcon} 63 | 64 | )} 65 | {chevron && ( 66 | 67 | 72 | 73 | )} 74 | 75 | ); 76 | }; 77 | 78 | const ListItem = React.forwardRef( 79 | ( 80 | {style, textStyle, subtitleStyle, background, subtitleSize, ...props}, 81 | ref, 82 | ) => { 83 | const theme = useThemeContext(); 84 | const propsWithTheme = {...props, background, theme}; 85 | const TouchableElement = 86 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 87 | return ( 88 | 89 | 94 | {renderLeftChild(propsWithTheme)} 95 | 96 | {typeof props.children !== 'function' ? ( 97 | 104 | {props.children} 105 | 106 | ) : ( 107 | props.children 108 | )} 109 | {props.subtitle && 110 | (typeof props.subtitle !== 'function' ? ( 111 | 118 | {props.subtitle} 119 | 120 | ) : ( 121 | props.subtitle 122 | ))} 123 | 124 | {renderRightChild(propsWithTheme)} 125 | 126 | 127 | ); 128 | }, 129 | ); 130 | 131 | ListItem.propTypes = { 132 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 133 | textStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 134 | subtitleStyle: PropTypes.object, 135 | iconStyle: PropTypes.object, 136 | textAlign: PropTypes.oneOf(['auto', 'left', 'center', 'right', 'justify']), 137 | children: PropTypes.oneOfType([ 138 | PropTypes.string, 139 | PropTypes.number, 140 | PropTypes.array, 141 | PropTypes.element, 142 | ]).isRequired, 143 | subtitle: PropTypes.string, 144 | background: PropTypes.string, 145 | textColor: PropTypes.string, 146 | subtitleColor: PropTypes.string, 147 | chevronColor: PropTypes.string, 148 | size: sizes, 149 | subtitleSize: sizes, 150 | space: spaces, 151 | onPress: PropTypes.func.isRequired, 152 | avatarSource: PropTypes.object, 153 | leftIcon: PropTypes.element, 154 | rightIcon: PropTypes.element, 155 | chevron: PropTypes.bool, 156 | disabled: PropTypes.bool, 157 | activeOpacity: PropTypes.number, 158 | shadow: shadows, 159 | radius: radii, 160 | /** Customize button font */ 161 | fontBase: fontBases, 162 | fontVariant: fontVariants, 163 | /** Customize button font */ 164 | subtitleFontBase: fontBases, 165 | subtitleFontVariant: fontVariants, 166 | }; 167 | 168 | ListItem.defaultProps = { 169 | children: 'Pass children to render', 170 | background: 'bg200', 171 | textColor: 'para', 172 | subtitleColor: 'subtle', 173 | chevronColor: 'body', 174 | textAlign: 'left', 175 | space: 'md', 176 | size: 'md', 177 | subtitleSize: 'md', 178 | shadow: 'none', 179 | radius: 'sm', 180 | fontBase: 'body', 181 | fontVariant: 'medium', 182 | subtitleFontBase: 'body', 183 | subtitleFontVariant: 'light', 184 | }; 185 | 186 | const styles = StyleSheet.create({ 187 | container: { 188 | flexDirection: 'row', 189 | alignItems: 'center', 190 | }, 191 | textView: { 192 | flex: 1, 193 | justifyContent: 'center', 194 | paddingHorizontal: 10, 195 | }, 196 | iconStyle: { 197 | justifyContent: 'center', 198 | alignItems: 'center', 199 | }, 200 | }); 201 | 202 | export default ListItem; 203 | -------------------------------------------------------------------------------- /src/ListItem/ListItem.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select, boolean, text} from '@storybook/addon-knobs'; 3 | import {action} from '@storybook/addon-actions'; 4 | import Stack from '../Layout/Stack'; 5 | import Feather from 'react-native-vector-icons/Feather'; 6 | import AntDesign from 'react-native-vector-icons/AntDesign'; 7 | import ListItem from './ListItem'; 8 | import {sizeArray} from '../util/prop-types'; 9 | 10 | 11 | 12 | # ListItem 13 | 14 | A ListItem is a wrapper around `TextInput` with commonly used styles and easy to make customization. 15 | 16 | # Usage 17 | 18 | ```js 19 | import {ListItem} from 'react-native-design-system'; 20 | 21 | This is a ListItem; 22 | ``` 23 | 24 | # Props 25 | 26 | 27 | 28 | # Type 29 | 30 | There are three types of button mainly: `default`, `round`, and `outline`. You can pass boolean value `round={true}` for round button, `outline={true}` for outline button and nothing for default solid button. 31 | 32 | 33 | 34 | 35 | This is a ListItem 36 | This is a ListItem 37 | 38 | This is a ListItem 39 | 40 | 41 | 42 | 43 | 44 | # Chevron 45 | 46 | Pass `chevron={true}` to show chevron at left. You can pass `chevronColor` to change its color. 47 | 48 | 49 | 50 | This is a ListItem 51 | 52 | 53 | 54 | # Subtitle 55 | 56 | Pass a string to `subtitle` prop to go below list text. 57 | 58 | 59 | 60 | 61 | Hey there! 62 | 63 | 64 | 65 | 66 | # Avatar 67 | 68 | Pass `avatarSource` to get an avatar on left. It receives prop same as an Image component. 69 | 70 | 71 | 72 | 76 | Hey there! 77 | 78 | 79 | 80 | 81 | # Icon 82 | 83 | You can `leftIcon` and `rightIcon` that goes to left and right on the `ListItem`. You can customize icon with `iconStyle`. 84 | 85 | 86 | 87 | } 91 | rightIcon={}> 92 | Follow me on twitter 93 | 94 | 95 | 96 | 97 | # Disabled 98 | 99 | `disabled={true}` property restrict any kind of action on ListItem. 100 | 101 | 102 | 103 | 104 | Hey there! 105 | 106 | 107 | 108 | 109 | # Text Color 110 | 111 | You can pass any of the color present inside `textColor` in theme. Same property applies to `subtitleColor`. 112 | 113 | 114 | 115 | 116 | Hey there!! 117 | 118 | 119 | 120 | 121 | # Text Align 122 | 123 | You can align ListItem text position by passing `auto`,`left`, `center`, `right` or `justify` as `textAlign` property. 124 | 125 | 126 | 127 | 128 | 129 | Home 130 | 131 | 132 | Home 133 | 134 | 135 | Home 136 | 137 | 138 | 139 | 140 | 141 | # Size 142 | 143 | ListItem has 9 available sizes. 144 | 145 | 146 | 147 | 148 | 149 | Hey there! 150 | 151 | 152 | Hey there! 153 | 154 | 155 | Hey there! 156 | 157 | 158 | Hey there! 159 | 160 | 161 | Hey there! 162 | 163 | 164 | Hey there! 165 | 166 | 167 | Hey there! 168 | 169 | 170 | Hey there! 171 | 172 | 173 | Hey there! 174 | 175 | 176 | 177 | 178 | 179 | # Playground 180 | 181 | Play with ListItem in Canvas mode. 182 | 183 | 184 | 203 | {text('children', 'Play around with ListItem')} 204 | 205 | 206 | -------------------------------------------------------------------------------- /src/ListItem/index.js: -------------------------------------------------------------------------------- 1 | import ListItem from './ListItem'; 2 | // import SlidingListItem from './SlidingListItem'; 3 | export { ListItem }; 4 | -------------------------------------------------------------------------------- /src/Overlay/Overlay.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StyleSheet, Modal, Pressable} from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import { 6 | extractAccessibilityPropsFromProps, 7 | removeAccessibilityPropsFromProps, 8 | } from '../util/accessibility'; 9 | import {radii} from '../util/prop-types'; 10 | 11 | const getContainerStyle = ({theme, background, style}) => { 12 | const containerStyle = [ 13 | styles.container, 14 | { 15 | backgroundColor: theme.colors[background], 16 | }, 17 | ]; 18 | if (style) { 19 | containerStyle.push(style); 20 | } 21 | return StyleSheet.flatten(containerStyle); 22 | }; 23 | 24 | const getChildStyle = ({ 25 | theme, 26 | overlayBackground, 27 | overlayStyle, 28 | radius, 29 | width, 30 | }) => { 31 | const contentStyle = [ 32 | { 33 | elevation: 1, 34 | backgroundColor: theme.colors[overlayBackground], 35 | borderRadius: theme.radius[radius], 36 | width: width, 37 | }, 38 | ]; 39 | if (overlayStyle) { 40 | contentStyle.push(overlayStyle); 41 | } 42 | return StyleSheet.flatten(contentStyle); 43 | }; 44 | 45 | const Overlay = props => { 46 | const theme = useThemeContext(); 47 | const ContainerView = props.onPressOutside ? Pressable : View; 48 | return ( 49 | 50 | 54 | {props.children} 55 | 56 | 57 | ); 58 | }; 59 | 60 | Overlay.propTypes = { 61 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 62 | overlayStyle: PropTypes.object, 63 | children: PropTypes.element.isRequired, 64 | background: PropTypes.string, 65 | overlayBackground: PropTypes.string, 66 | radius: radii, 67 | width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), 68 | height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), 69 | }; 70 | 71 | Overlay.defaultProps = { 72 | background: 'semitransparent', 73 | overlayBackground: 'clearWhite', 74 | radius: 'lg', 75 | width: '80%', 76 | }; 77 | 78 | const styles = StyleSheet.create({ 79 | container: { 80 | flex: 1, 81 | justifyContent: 'center', 82 | alignItems: 'center', 83 | }, 84 | }); 85 | 86 | export default Overlay; 87 | -------------------------------------------------------------------------------- /src/Overlay/Overlay.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select, boolean, color} from '@storybook/addon-knobs'; 3 | import {View, Text, Button} from 'react-native'; 4 | import Overlay from './Overlay'; 5 | 6 | 7 | 8 | # Overlay 9 | 10 | Overlay covers the view and adds a transparent layer on top of it. Any view can be passed as a children. Used generally as a prompt or notify user about something. 11 | 12 | # Usage 13 | 14 | ```js 15 | import {Overlay} from 'react-native-design-system'; 16 | 17 | this.setState({visible: false})}> 20 | 21 | Hey there! 22 | 23 | ; 24 | ``` 25 | 26 | # Props 27 | 28 | 29 | 30 | # Modal Props 31 | 32 | Accepts all the modal props like `visible={true}` and `onRequestClose`, etc. 33 | 34 | # Styles 35 | 36 | The container receives an `style` props and overlay can be customized with `overlayStyle` which is the inside content on transparent layer. 37 | 38 | # Dimensions 39 | 40 | Overlay has a default width and height of `80%` and `70%`. It can be customized by passing `width` and `height` props. 41 | 42 | # Border Radius 43 | 44 | Overlay curves can be customized with `borderRadius` prop, default is `3`. 45 | 46 | # Backgrounds 47 | 48 | Container has a default background of `semitransparent` and overlay is `white` from `colors` of theme. You can pass any color inside `background` and `overlayBackground` props. 49 | -------------------------------------------------------------------------------- /src/Overlay/index.js: -------------------------------------------------------------------------------- 1 | import Overlay from './Overlay'; 2 | export { Overlay }; 3 | -------------------------------------------------------------------------------- /src/RadioButton/RadioButton.example.js: -------------------------------------------------------------------------------- 1 | import React, {useState} from 'react'; 2 | import {select, boolean} from '@storybook/addon-knobs'; 3 | import {RadioButton, RadioItem} from './index'; 4 | import {sizeArray} from '../util/prop-types'; 5 | 6 | export default function ExampleRadioButton() { 7 | const [activeId, setActiveId] = useState('a'); 8 | return ( 9 | setActiveId(id)}> 16 | Option A 17 | Option B 18 | Option C 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/RadioButton/RadioButton.js: -------------------------------------------------------------------------------- 1 | import React, {useContext, createContext} from 'react'; 2 | import { 3 | View, 4 | StyleSheet, 5 | TouchableNativeFeedback, 6 | TouchableOpacity, 7 | Platform, 8 | } from 'react-native'; 9 | import PropTypes from 'prop-types'; 10 | import Ionicons from 'react-native-vector-icons/Ionicons'; 11 | import {useThemeContext} from '../util/ThemeProvider'; 12 | import {extractAccessibilityPropsFromProps} from '../util/accessibility'; 13 | import {sizes} from '../util/prop-types'; 14 | import {Text} from '../Text'; 15 | const Context = createContext(); 16 | const {Provider} = Context; 17 | 18 | const getTextStyle = ({iconRight}) => { 19 | const textStyle = [ 20 | { 21 | marginLeft: 10, 22 | }, 23 | ]; 24 | if (iconRight) { 25 | textStyle.push({ 26 | marginLeft: 0, 27 | marginRight: 10, 28 | }); 29 | } 30 | return textStyle; 31 | }; 32 | 33 | const renderIcon = ({theme, size, color, id, activeId, ...props}) => { 34 | if (activeId === id) { 35 | return ( 36 | props.checkedIcon || ( 37 | 42 | ) 43 | ); 44 | } else { 45 | return ( 46 | props.uncheckedIcon || ( 47 | 52 | ) 53 | ); 54 | } 55 | }; 56 | 57 | export const RadioItem = ({children, id, ...otherProps}) => { 58 | const {selectItem, style, ...props} = useContext(Context); 59 | const propsToPass = {...props, id}; 60 | const TouchableElement = 61 | Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity; 62 | return ( 63 | selectItem(id)}> 67 | 68 | {!props.iconRight && renderIcon(propsToPass)} 69 | 70 | {typeof children === 'function' || typeof children === 'object' ? ( 71 | children 72 | ) : ( 73 | 82 | {children} 83 | 84 | )} 85 | 86 | {props.iconRight && renderIcon(propsToPass)} 87 | 88 | 89 | ); 90 | }; 91 | 92 | const RadioButton = ({children, ...props}) => { 93 | const theme = useThemeContext(); 94 | return {children}; 95 | }; 96 | 97 | RadioButton.propTypes = { 98 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 99 | textStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 100 | children: PropTypes.oneOfType([PropTypes.array, PropTypes.element]) 101 | .isRequired, 102 | activeId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) 103 | .isRequired, 104 | iconRight: PropTypes.bool, 105 | color: PropTypes.string, 106 | textColor: PropTypes.string, 107 | size: sizes, 108 | selectItem: PropTypes.func.isRequired, 109 | checkedIcon: PropTypes.element, 110 | uncheckedIcon: PropTypes.element, 111 | }; 112 | 113 | RadioButton.defaultProps = { 114 | size: 'md', 115 | color: 'primary', 116 | textColor: 'para', 117 | }; 118 | 119 | const styles = StyleSheet.create({ 120 | itemContainer: { 121 | flexDirection: 'row', 122 | alignItems: 'center', 123 | justifyContent: 'space-between', 124 | }, 125 | }); 126 | 127 | export default RadioButton; 128 | -------------------------------------------------------------------------------- /src/RadioButton/index.js: -------------------------------------------------------------------------------- 1 | import RadioButton, { RadioItem } from './RadioButton'; 2 | export { RadioButton, RadioItem }; 3 | -------------------------------------------------------------------------------- /src/SearchBar/SearchBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | View, 4 | TouchableOpacity, 5 | StyleSheet, 6 | ActivityIndicator, 7 | } from 'react-native'; 8 | import Feather from 'react-native-vector-icons/Feather'; 9 | import Input from '../Input/Input'; 10 | import PropTypes from 'prop-types'; 11 | import {useThemeContext} from '../util/ThemeProvider'; 12 | 13 | const renderIndicator = props => { 14 | return ( 15 | 16 | 17 | 21 | 22 | {props.onCancel && props.value.length !== 0 && ( 23 | 24 | {props.rightIcon || ( 25 | 30 | )} 31 | 32 | )} 33 | 34 | ); 35 | }; 36 | 37 | const SearchBar = React.forwardRef((props, ref) => { 38 | const theme = useThemeContext(); 39 | return ( 40 | 48 | ) 49 | } 50 | {...props} 51 | ref={ref} 52 | rightIcon={renderIndicator({...props, theme})} 53 | /> 54 | ); 55 | }); 56 | 57 | SearchBar.propTypes = { 58 | indicatorColor: PropTypes.string, 59 | loading: PropTypes.bool, 60 | iconColor: PropTypes.string, 61 | onCancel: PropTypes.func, 62 | rightIcon: PropTypes.element, 63 | }; 64 | 65 | SearchBar.defaultProps = { 66 | iconColor: 'heading', 67 | value: '', 68 | placeholder: 'Search here', 69 | }; 70 | 71 | const styles = StyleSheet.create({ 72 | rightIcons: { 73 | flexDirection: 'row', 74 | }, 75 | indicator: { 76 | paddingHorizontal: 10, 77 | }, 78 | }); 79 | 80 | export default SearchBar; 81 | -------------------------------------------------------------------------------- /src/SearchBar/index.js: -------------------------------------------------------------------------------- 1 | import SearchBar from './SearchBar'; 2 | export { SearchBar }; 3 | -------------------------------------------------------------------------------- /src/Text/Text.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Text, StyleSheet} from 'react-native'; 3 | import PropTypes from 'prop-types'; 4 | import {useThemeContext} from '../util/ThemeProvider'; 5 | import {fontBases, fontSizes, fontVariants} from '../util/prop-types'; 6 | 7 | const getTextStyle = ({ 8 | theme, 9 | color, 10 | size, 11 | fontWeight, 12 | fontFamily, 13 | textAlign, 14 | lineHeight, 15 | letterSpacing, 16 | fontBase, 17 | fontVariant, 18 | }) => { 19 | const style = [ 20 | { 21 | color: theme.colors[color], 22 | fontSize: theme.fontSize[size], 23 | lineHeight: theme.lineHeight[lineHeight || size], 24 | textAlignVertical: 'center', 25 | fontWeight, 26 | textAlign, 27 | }, 28 | ]; 29 | if (fontFamily) { 30 | style.push({fontFamily: theme.font[fontFamily]}); 31 | } 32 | if (letterSpacing) { 33 | style.push({letterSpacing: theme.letterSpacing[letterSpacing]}); 34 | } 35 | if (fontBase && fontVariant) { 36 | style.push({ 37 | fontFamily: theme.font[fontBase][fontVariant], 38 | }); 39 | } 40 | return style; 41 | }; 42 | 43 | const TextElement = React.forwardRef(({style, ...props}, ref) => { 44 | const theme = useThemeContext(); 45 | return ( 46 | 51 | {props.children} 52 | 53 | ); 54 | }); 55 | 56 | TextElement.propTypes = { 57 | style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), 58 | children: PropTypes.oneOfType([ 59 | PropTypes.string, 60 | PropTypes.number, 61 | PropTypes.array, 62 | PropTypes.element, 63 | ]).isRequired, 64 | size: fontSizes, 65 | lineHeight: fontSizes, 66 | fontFamily: PropTypes.string, 67 | color: PropTypes.string, 68 | fontWeight: PropTypes.string, 69 | letterSpacing: fontSizes, 70 | textAlign: PropTypes.oneOf(['left', 'center', 'right']), 71 | fontBase: fontBases, 72 | fontVariant: fontVariants, 73 | }; 74 | 75 | TextElement.defaultProps = { 76 | color: 'para', 77 | size: 'md', 78 | fontWeight: '500', 79 | textAlign: 'left', 80 | fontBases: 'body', 81 | fontVariant: 'medium', 82 | }; 83 | 84 | export default TextElement; 85 | -------------------------------------------------------------------------------- /src/Text/Text.stories.mdx: -------------------------------------------------------------------------------- 1 | import {Meta, Story, Preview, Props} from '@storybook/addon-docs/blocks'; 2 | import {withKnobs, select} from '@storybook/addon-knobs'; 3 | import Stack from '../Layout/Stack'; 4 | import Text from './Text'; 5 | import {sizeArray} from '../util/prop-types'; 6 | 7 | 8 | 9 | # Text 10 | 11 | Simple `Text` element that gives you different sizes and colors. 12 | 13 | # Usage 14 | 15 | ```js 16 | import {Text} from 'react-native-design-system'; 17 | 18 | Hello Design System; 19 | ``` 20 | 21 | # Props 22 | 23 | 24 | 25 | # Sizes 26 | 27 | We have sizes available from `xs` to `9xl`. 28 | 29 | 30 | 31 | 32 | Hello Design System 33 | Hello Design System 34 | Hello Design System 35 | Hello Design System 36 | Hello Design System 37 | Hello Design System 38 | Hello Design System 39 | Hello Design System 40 | Hello Design System 41 | Hello Design System 42 | Hello Design System 43 | Hello Design System 44 | Hello Design System 45 | 46 | 47 | 48 | 49 | # Color 50 | 51 | Uses color defined in `textColor` in theme. 52 | 53 | 54 | 55 | 56 | Hello Design System 57 | Hello Design System 58 | Hello Design System 59 | 60 | 61 | 62 | 63 | # Scale 64 | 65 | Pass `scale={false}` if you don't want text to scale when device default font size changes. Default is `true` and text will scale accrording to default font size. 66 | 67 | # Playground 68 | 69 | Play with Text in Canvas mode. 70 | 71 | 72 | 75 | Hello World 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/Text/index.js: -------------------------------------------------------------------------------- 1 | import Text from './Text'; 2 | export { Text }; 3 | -------------------------------------------------------------------------------- /src/index.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for react-native-design-system 2 | // Project: https://github.com/iamshadmirza/react-native-design-system 3 | // Definitions by: 4 | // Bhavesh Daswani 5 | // TypeScript Version: 3.7.5 6 | // Definition updated by Shad on 30 September 7 | 8 | import * as React from 'react'; 9 | import {themeType} from './types/theme'; 10 | import {colorsType} from './types/colors-type'; 11 | export * from './types/Button'; 12 | export * from './types/MenuAddButton'; 13 | export * from './types/IconButton'; 14 | export * from './types/ActionButton'; 15 | export * from './types/Avatar'; 16 | export * from './types/Card'; 17 | export * from './types/Badge'; 18 | export * from './types/CheckBox'; 19 | export * from './types/CircularProgressBar'; 20 | export * from './types/FullScreenLoader'; 21 | export * from './types/Header'; 22 | export * from './types/Input'; 23 | export * from './types/Box'; 24 | export * from './types/Stack'; 25 | export * from './types/ListItem'; 26 | export * from './types/OverLay'; 27 | export * from './types/SearchBar'; 28 | export * from './types/Text'; 29 | export * from './types/RadioItem'; 30 | export * from './types/RadioButton'; 31 | export * from './types/Flex'; 32 | export * from './types/StackList'; 33 | export * from './types/Spacer'; 34 | export * from './types/DismissKeyboard'; 35 | export * from './types/Image'; 36 | 37 | export let theme: themeType; 38 | export let colors: colorsType; 39 | 40 | export const ThemeProvider: React.FC<{ 41 | theme: themeType; 42 | colorMode?: 'light' | 'dark'; 43 | children: React.ReactNode | Array; 44 | components: any 45 | }>; 46 | 47 | export const useThemeContext: () => typeof theme; 48 | export const useCustomComponent: () => any; 49 | export const useThemeMode: () => { 50 | isDarkMode: boolean; 51 | toggleDarkMode: (mode?: 'light' | 'dark') => void; 52 | }; 53 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export * from './Avatar'; 2 | export * from './ActionButton'; 3 | export * from './Badge'; 4 | export * from './Button'; 5 | export * from './Card'; 6 | export * from './CheckBox'; 7 | export * from './CircularProgressBar'; 8 | export * from './FullScreenLoader'; 9 | export * from './Header'; 10 | export * from './Input'; 11 | export * from './ListItem'; 12 | export * from './Overlay'; 13 | export * from './RadioButton'; 14 | export * from './SearchBar'; 15 | export * from './Text'; 16 | export * from './Layout'; 17 | export * from './Deck'; 18 | export * from './DismissKeyboard'; 19 | export * from './Image'; 20 | export {default as colors} from './util/colors'; 21 | export { 22 | default as ThemeProvider, 23 | useThemeContext, 24 | useThemeMode, 25 | } from './util/ThemeProvider'; 26 | export {default as theme} from './util/theme'; 27 | -------------------------------------------------------------------------------- /src/types/ActionButton.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ViewStyle, StyleProp, ViewProps } from 'react-native'; 3 | 4 | import { SizeType } from './size-type'; 5 | import { IconNode } from './icon-type'; 6 | import { colorTypes } from './colors-type'; 7 | 8 | 9 | interface ActionButtonProps extends ViewProps { 10 | size?: SizeType, 11 | onPress: () => void, 12 | iconColor?: string, 13 | color?: keyof colorTypes | string, 14 | icon?: IconNode, 15 | style?: StyleProp, 16 | } 17 | 18 | export const ActionButton: React.FC; 19 | -------------------------------------------------------------------------------- /src/types/Avatar.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {ViewStyle, TextStyle, StyleProp, ViewProps} from 'react-native'; 3 | 4 | import {RadiusType, ShadowType, SizeType} from './size-type'; 5 | 6 | interface AvatarProps extends ViewProps { 7 | style?: StyleProp; 8 | textStyle?: StyleProp; 9 | title?: string; 10 | source?: object; 11 | editable?: boolean; 12 | onPress?: () => void; 13 | size?: SizeType | string; 14 | square?: boolean; 15 | rounded?: boolean; 16 | editIconStyle?: StyleProp; 17 | editIconColor?: string; 18 | shadow?: ShadowType; 19 | radius?: RadiusType; 20 | imageProps?: any 21 | } 22 | 23 | export const Avatar: React.FC; 24 | -------------------------------------------------------------------------------- /src/types/Badge.d.ts: -------------------------------------------------------------------------------- 1 | import React, {ReactNode} from 'react'; 2 | import { 3 | AccessibilityProps, 4 | StyleProp, 5 | TextStyle, 6 | ViewStyle, 7 | } from 'react-native'; 8 | import {colorTypes} from './colors-type'; 9 | import {RadiusType, SizeType} from './size-type'; 10 | 11 | interface BadgeProps extends AccessibilityProps { 12 | style?: StyleProp; 13 | textStyle?: StyleProp; 14 | children?: ReactNode; 15 | color?: keyof colorTypes | string; 16 | size?: SizeType; 17 | mini?: boolean; 18 | onPress?: () => void; 19 | square?: boolean; 20 | radius?: RadiusType; 21 | } 22 | 23 | export const Badge: React.FC; 24 | -------------------------------------------------------------------------------- /src/types/Box.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {AccessibilityProps, StyleProp, ViewStyle} from 'react-native'; 3 | import {LayoutChildrenType} from './layout-children-type'; 4 | import {SpaceType} from './space-type'; 5 | 6 | import {colorTypes} from './colors-type'; 7 | interface BoxProps extends AccessibilityProps { 8 | style?: StyleProp; 9 | background?: keyof colorTypes | string; 10 | space?: SpaceType; 11 | children: LayoutChildrenType; 12 | } 13 | 14 | export const Box: React.FC; 15 | -------------------------------------------------------------------------------- /src/types/Button.d.ts: -------------------------------------------------------------------------------- 1 | import React, {ReactNode} from 'react'; 2 | import {ViewStyle, TextStyle, StyleProp, ViewProps} from 'react-native'; 3 | 4 | import {FontSizeType, RadiusType, ShadowType, SizeType} from './size-type'; 5 | import {LengthType} from './length-type'; 6 | import {IconNode} from './icon-type'; 7 | import {colorTypes} from './colors-type'; 8 | import {fontBaseType, fontVariantType} from './typography-type'; 9 | 10 | interface ButtonProps extends ViewProps { 11 | style?: StyleProp; 12 | textStyle?: StyleProp; 13 | children?: ReactNode; 14 | indicatorColor?: string; 15 | size?: SizeType; 16 | textSize?: FontSizeType; 17 | onPress: () => void; 18 | color?: keyof colorTypes | string; 19 | textColor?: keyof colorTypes | string; 20 | borderColor?: string; 21 | round?: boolean; 22 | outline?: boolean; 23 | transparent?: boolean; 24 | disabled?: boolean; 25 | loading?: boolean; 26 | tint?: boolean; 27 | icon?: IconNode; 28 | leftIcon?: IconNode; 29 | rightIcon?: IconNode; 30 | rightIconStyle?: StyleProp; 31 | leftIconStyle?: StyleProp; 32 | length?: LengthType; 33 | radius?: RadiusType; 34 | shadow?: ShadowType; 35 | fontBase?: fontBaseType; 36 | fontVariant?: fontVariantType; 37 | } 38 | 39 | export const Button: React.FC; 40 | -------------------------------------------------------------------------------- /src/types/Card.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import {StyleProp, ViewStyle} from 'react-native'; 4 | import {AlignType} from './align-type'; 5 | import {LayoutChildrenType} from './layout-children-type'; 6 | import {SpaceType} from './space-type'; 7 | import {colorTypes} from './colors-type'; 8 | import {RadiusType, ShadowType} from './size-type'; 9 | 10 | interface CardProps extends ViewStyle { 11 | row?: boolean; 12 | style?: StyleProp; 13 | space?: SpaceType; 14 | children: LayoutChildrenType; 15 | horizontal?: boolean; 16 | vertical?: boolean; 17 | align?: AlignType; 18 | shadow?: ShadowType; 19 | background?: keyof colorTypes | string; 20 | radius?: RadiusType; 21 | } 22 | 23 | export const Card: React.FC; 24 | -------------------------------------------------------------------------------- /src/types/CheckBox.d.ts: -------------------------------------------------------------------------------- 1 | import React, {ReactElement} from 'react'; 2 | import { 3 | AccessibilityProps, 4 | StyleProp, 5 | TextStyle, 6 | ViewStyle, 7 | } from 'react-native'; 8 | import {SizeType} from './size-type'; 9 | import {colorTypes} from './colors-type'; 10 | import {fontBaseType, fontVariantType} from './typography-type'; 11 | 12 | interface CheckBoxProps extends AccessibilityProps { 13 | style?: StyleProp; 14 | textStyle?: StyleProp; 15 | children: string | ReactElement | ReactElement[]; 16 | checked?: boolean; 17 | iconRight?: boolean; 18 | color?: string; 19 | textColor?: keyof colorTypes | string; 20 | size?: SizeType; 21 | onPress: () => void; 22 | checkedIcon?: React.ReactNode; 23 | uncheckedIcon?: React.ReactNode; 24 | fontBase?: fontBaseType; 25 | fontVariant?: fontVariantType; 26 | } 27 | 28 | export const CheckBox: React.FC; 29 | -------------------------------------------------------------------------------- /src/types/CircularProgressBar.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {AccessibilityProps} from 'react-native'; 3 | 4 | interface CircularProgressBarProps extends AccessibilityProps { 5 | activeColor: string; 6 | passiveColor: string; 7 | baseColor: string; 8 | width: number; 9 | radius: number; 10 | percent: number; 11 | duration: number; 12 | } 13 | 14 | export const CircularProgressBar: React.FC; 15 | -------------------------------------------------------------------------------- /src/types/Deck.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {AccessibilityProps, StyleProp, ViewStyle} from 'react-native'; 3 | import {DirectionType} from './direction-type'; 4 | 5 | interface DeckProps extends AccessibilityProps { 6 | style?: StyleProp; 7 | direction?: DirectionType; 8 | data: Array; 9 | renderItem: () => void; 10 | keyExtractor: () => void; 11 | loadMoreCards?: () => void; 12 | onNegativeSwipe?: () => void; 13 | onPositiveSwipe?: () => void; 14 | fade?: boolean; 15 | loop?: boolean; 16 | loadInitialData?: boolean; 17 | loadingScreen: React.ReactNode; 18 | } 19 | 20 | export const Deck: React.FC; 21 | -------------------------------------------------------------------------------- /src/types/DismissKeyboard.d.ts: -------------------------------------------------------------------------------- 1 | import React, {ReactElement} from 'react'; 2 | import {AccessibilityProps, StyleProp, ViewStyle} from 'react-native'; 3 | 4 | interface DismissKeyboardProps extends AccessibilityProps { 5 | style?: StyleProp; 6 | children?: ReactElement | ReactElement[]; 7 | } 8 | 9 | export const DismissKeyboard: React.FC; 10 | -------------------------------------------------------------------------------- /src/types/Flex.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {AccessibilityProps, StyleProp, ViewStyle} from 'react-native'; 3 | import {LayoutChildrenType} from './layout-children-type'; 4 | import {SpaceType} from './space-type'; 5 | import { colorTypes } from './colors-type'; 6 | 7 | interface FlexProp extends AccessibilityProps { 8 | style?: StyleProp; 9 | background?: keyof colorTypes | string, 10 | space?: SpaceType; 11 | children: LayoutChildrenType; 12 | flex?: number; 13 | flexWrap?: 'no-wrap' | 'wrap' | 'wrap-reverse'; 14 | flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse'; 15 | alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'; 16 | alignSelf?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'; 17 | justifyContent?: 18 | | 'flex-start' 19 | | 'flex-end' 20 | | 'center' 21 | | 'space-between' 22 | | 'space-around' 23 | | 'space-evenly'; 24 | alignContent?: 25 | | 'flex-start' 26 | | 'flex-end' 27 | | 'center' 28 | | 'space-between' 29 | | 'space-around' 30 | | 'space-evenly'; 31 | } 32 | 33 | export const Flex: React.FC; 34 | -------------------------------------------------------------------------------- /src/types/FullScreenLoader.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {AccessibilityProps, StyleProp, ViewStyle} from 'react-native'; 3 | import {colorTypes} from './colors-type'; 4 | 5 | interface FullScreenLoaderProps extends AccessibilityProps { 6 | loading?: boolean; 7 | style?: StyleProp; 8 | children?: React.ReactNode; 9 | indicatorColor?: string; 10 | background?: keyof colorTypes | string; 11 | size?: 'sm' | 'lg'; 12 | } 13 | 14 | export const FullScreenLoader: React.FC; 15 | -------------------------------------------------------------------------------- /src/types/Header.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | AccessibilityProps, 4 | StyleProp, 5 | TextStyle, 6 | ViewStyle, 7 | } from 'react-native'; 8 | import {IconNode} from './icon-type'; 9 | import {ShadowType, SizeType} from './size-type'; 10 | import {TextAlignType} from './text-align-type'; 11 | import {colorTypes} from './colors-type'; 12 | 13 | interface HeaderProps extends AccessibilityProps { 14 | style?: StyleProp; 15 | textStyle?: StyleProp; 16 | textAlign?: TextAlignType; 17 | fontSize?: SizeType; 18 | children?: string; 19 | color?: keyof colorTypes | string; 20 | leftIcon?: IconNode; 21 | onleftIconPress?: () => void; 22 | rightIcon?: IconNode; 23 | onRightIconPress?: () => void; 24 | iconStyle?: StyleProp; 25 | barColor?: string; 26 | barStyle?: 'default' | 'dark-content' | 'light-content'; 27 | shadow?: ShadowType; 28 | } 29 | 30 | export const Header: React.FC; 31 | -------------------------------------------------------------------------------- /src/types/IconButton.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | ViewStyle, 4 | TextStyle, 5 | StyleProp, 6 | AccessibilityProps, 7 | } from 'react-native'; 8 | 9 | import {RadiusType, ShadowType, SizeType} from './size-type'; 10 | import {IconNode} from './icon-type'; 11 | import {colorTypes} from './colors-type'; 12 | 13 | interface IconButtonProps extends AccessibilityProps { 14 | style?: StyleProp; 15 | textStyle?: StyleProp; 16 | icon?: IconNode; 17 | size?: SizeType; 18 | background?: colorTypes; 19 | color?: colorTypes; 20 | onPress: () => void; 21 | onLongPress?: () => void; 22 | rounded?: boolean; 23 | outline?: boolean; 24 | transparent?: boolean; 25 | disabled?: boolean; 26 | radius?: RadiusType; 27 | shadow?: ShadowType; 28 | } 29 | 30 | export const IconButton: React.FC; 31 | -------------------------------------------------------------------------------- /src/types/Image.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {StyleProp, ViewStyle} from 'react-native'; 3 | import {colorTypes} from './colors-type'; 4 | import {RadiusType, ShadowType} from './size-type'; 5 | import {SpaceType} from './space-type'; 6 | 7 | interface ImageProps extends ImageProps { 8 | style?: StyleProp; 9 | space?: SpaceType; 10 | shadow?: ShadowType; 11 | radius?: RadiusType; 12 | background?: colorTypes; 13 | borderColor?: colorTypes; 14 | borderWidth?: Number; 15 | width?: Number | String; 16 | height?: Number | String; 17 | aspectRatio?: Number; 18 | outline?: boolean; 19 | onPress: () => void; 20 | } 21 | 22 | export const Image: React.FC; 23 | -------------------------------------------------------------------------------- /src/types/Input.d.ts: -------------------------------------------------------------------------------- 1 | import React, {ReactElement} from 'react'; 2 | import {TextStyle, StyleProp, TextInputProps} from 'react-native'; 3 | 4 | import {RadiusType, ShadowType, SizeType} from './size-type'; 5 | import {IconNode} from './icon-type'; 6 | import {colorTypes} from './colors-type'; 7 | 8 | interface InputProps extends TextInputProps { 9 | textStyle?: StyleProp; 10 | textColor?: keyof colorTypes | string; 11 | floatingLabel?: boolean; 12 | labelStyle?: StyleProp; 13 | labelColor?: string; 14 | label?: string | ReactElement | ReactElement[]; 15 | color?: keyof colorTypes | string; 16 | round?: boolean; 17 | outline?: boolean; 18 | error?: boolean; 19 | errorCaption?: string | ReactElement | ReactElement[]; 20 | size?: SizeType; 21 | disabled?: boolean; 22 | leftIcon?: IconNode; 23 | rightIcon?: IconNode; 24 | background?: keyof colorTypes | string; 25 | outlineColor?: keyof colorTypes | string; 26 | textAlign?: 'left' | 'center' | 'right'; 27 | labelHintStyle?: StyleProp; 28 | labelHintColor?: string; 29 | labelHint?: string | ReactElement | ReactElement[]; 30 | shadow?: ShadowType; 31 | radius?: RadiusType; 32 | } 33 | 34 | export const Input: React.FC; 35 | -------------------------------------------------------------------------------- /src/types/ListItem.d.ts: -------------------------------------------------------------------------------- 1 | import React, {ReactNode} from 'react'; 2 | import { 3 | AccessibilityProps, 4 | StyleProp, 5 | TextStyle, 6 | ViewStyle, 7 | } from 'react-native'; 8 | import {IconNode} from './icon-type'; 9 | import {RadiusType, ShadowType, SizeType} from './size-type'; 10 | import {ListSpaceType} from './space-type'; 11 | import {TextAlignType} from './text-align-type'; 12 | import {colorTypes} from './colors-type'; 13 | import {fontBaseType, fontVariantType} from './typography-type'; 14 | 15 | interface ListItemProps extends AccessibilityProps { 16 | style?: StyleProp; 17 | textStyle?: StyleProp; 18 | subtitleStyle?: StyleProp; 19 | iconStyle?: StyleProp; 20 | textAlign?: TextAlignType; 21 | children: ReactNode; 22 | subtitle?: ReactNode; 23 | background?: keyof colorTypes | string; 24 | textColor?: keyof colorTypes | string; 25 | subtitleColor?: string; 26 | chevronColor?: string; 27 | size?: SizeType; 28 | space?: ListSpaceType; 29 | onPress?: () => void; 30 | avatarSource?: object; 31 | leftIcon?: IconNode; 32 | rightIcon?: IconNode; 33 | chevron?: boolean; 34 | disabled?: boolean; 35 | activeOpacity?: number; 36 | shadow?: ShadowType; 37 | radius?: RadiusType; 38 | fontBase?: fontBaseType; 39 | fontVariant?: fontVariantType; 40 | subtitleFontBase?: fontBaseType; 41 | subtitleFontVariant?: fontVariantType; 42 | subtitleSize?: SizeType; 43 | } 44 | 45 | export const ListItem: React.FC; 46 | -------------------------------------------------------------------------------- /src/types/MenuAddButton.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {ViewStyle, TextStyle, StyleProp} from 'react-native'; 3 | 4 | import {RadiusType, ShadowType, SizeType} from './size-type'; 5 | 6 | interface MenuAddButtonProps { 7 | style?: StyleProp; 8 | textStyle?: StyleProp; 9 | count: number; 10 | onIncrement: () => void; 11 | onDecrement: () => void; 12 | plusIcon?: React.ReactNode; 13 | minusIcon?: React.ReactNode; 14 | iconColor?: string; 15 | disabled?: boolean; 16 | size: SizeType; 17 | shadow?: ShadowType; 18 | radius?: RadiusType; 19 | } 20 | 21 | export const MenuAddButton: React.FC; 22 | -------------------------------------------------------------------------------- /src/types/Overlay.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {AccessibilityProps, StyleProp, ViewStyle} from 'react-native'; 3 | import {RadiusType} from './size-type'; 4 | 5 | interface OverlayProps extends AccessibilityProps { 6 | style?: StyleProp; 7 | overlayStyle?: StyleProp; 8 | children: React.ReactNode; 9 | background?: string; 10 | overlayBackground?: string; 11 | radius?: RadiusType; 12 | width?: string | number; 13 | height?: string | number; 14 | onPressOutside?: () => void; 15 | } 16 | 17 | export const Overlay: React.FC; 18 | -------------------------------------------------------------------------------- /src/types/RadioButton.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | AccessibilityProps, 4 | StyleProp, 5 | TextStyle, 6 | ViewStyle, 7 | } from 'react-native'; 8 | import {IconNode} from './icon-type'; 9 | import {LayoutChildrenType} from './layout-children-type'; 10 | import {SizeType} from './size-type'; 11 | import { colorTypes } from './colors-type'; 12 | 13 | interface RadioButtonProps extends AccessibilityProps { 14 | style?: StyleProp; 15 | textStyle?: StyleProp; 16 | children: LayoutChildrenType; 17 | activeId: number | string; 18 | iconRight?: boolean; 19 | color?: keyof colorTypes | string, 20 | textColor?: keyof colorTypes | string, 21 | size?: SizeType; 22 | selectItem: (id: number | string) => void; 23 | checkedIcon?: IconNode; 24 | uncheckedIcon?: IconNode; 25 | } 26 | 27 | export const RadioButton: React.FC; 28 | -------------------------------------------------------------------------------- /src/types/RadioItem.d.ts: -------------------------------------------------------------------------------- 1 | import React, {ReactNode} from 'react'; 2 | 3 | interface RadioItemProps { 4 | id: number | string; 5 | children: ReactNode; 6 | } 7 | 8 | export const RadioItem: React.FC; 9 | -------------------------------------------------------------------------------- /src/types/SearchBar.d.ts: -------------------------------------------------------------------------------- 1 | import React, {Ref} from 'react'; 2 | import {TextInput} from 'react-native'; 3 | import {InputProps} from './Input'; 4 | interface SearchBarProps extends InputProps { 5 | indicatorColor?: string; 6 | loading?: boolean; 7 | onCancel?: () => void; 8 | ref?: Ref; 9 | } 10 | 11 | export const SearchBar: React.FC; 12 | -------------------------------------------------------------------------------- /src/types/Spacer.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ViewStyle, StyleProp } from 'react-native'; 3 | import { SpaceType } from './space-type'; 4 | import { LayoutChildrenType } from './layout-children-type'; 5 | 6 | interface FlexProp { 7 | style?: StyleProp, 8 | m?: SpaceType, 9 | mv?: SpaceType, 10 | mh?: SpaceType, 11 | mt?: SpaceType, 12 | mb?: SpaceType, 13 | ml?: SpaceType, 14 | mr?: SpaceType, 15 | p?: SpaceType, 16 | pv?: SpaceType, 17 | ph?: SpaceType, 18 | pt?: SpaceType, 19 | pb?: SpaceType, 20 | pl?: SpaceType, 21 | pr?: SpaceType, 22 | children: LayoutChildrenType, 23 | } 24 | 25 | export const Flex: React.FC; 26 | -------------------------------------------------------------------------------- /src/types/Stack.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {AccessibilityProps, StyleProp, ViewStyle} from 'react-native'; 3 | import {DirectionType} from './direction-type'; 4 | import {LayoutChildrenType} from './layout-children-type'; 5 | import {HorizontalSpaceType, SpaceType, VerticalSpaceType} from './space-type'; 6 | import { colorTypes } from './colors-type'; 7 | 8 | interface StackProps extends AccessibilityProps { 9 | style?: StyleProp; 10 | space?: SpaceType; 11 | horizontalSpace?: HorizontalSpaceType; 12 | verticalSpace?: VerticalSpaceType; 13 | direction?: DirectionType; 14 | children: LayoutChildrenType; 15 | cropEndSpace?: boolean; 16 | scrollable?: boolean, 17 | background?: keyof colorTypes | string 18 | } 19 | 20 | export const Stack: React.FC; 21 | -------------------------------------------------------------------------------- /src/types/StackList.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | ViewStyle, 4 | StyleProp, 5 | FlatListProps, 6 | ScrollViewComponent, 7 | } from 'react-native'; 8 | 9 | import {SpaceType, HorizontalSpaceType, VerticalSpaceType} from './space-type'; 10 | import {DirectionType} from './direction-type'; 11 | import {colorTypes} from './colors-type'; 12 | 13 | interface StackListProps extends FlatListProps { 14 | style?: StyleProp; 15 | space?: SpaceType; 16 | horizontalSpace?: HorizontalSpaceType; 17 | verticalSpace?: VerticalSpaceType; 18 | direction?: DirectionType; 19 | cropEndSpace?: boolean; 20 | ref?: React.RefObject; 21 | background?: keyof colorTypes | string; 22 | } 23 | 24 | export const StackList: React.FC; 25 | -------------------------------------------------------------------------------- /src/types/Text.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {TextProps as RNTextProps} from 'react-native'; 3 | import {colorTypes} from './colors-type'; 4 | 5 | import {FontSizeType} from './size-type'; 6 | import {fontBaseType, fontVariantType} from './typography-type'; 7 | 8 | interface TextProps extends RNTextProps { 9 | size?: FontSizeType | string; 10 | color?: keyof colorTypes | string; 11 | scale?: boolean; 12 | textAlign?: 'left' | 'center' | 'right'; 13 | fontWeight?: string; 14 | fontFamily?: string; 15 | fontBase?: fontBaseType; 16 | fontVariant?: fontVariantType; 17 | } 18 | 19 | export const Text: React.FC; 20 | -------------------------------------------------------------------------------- /src/types/align-type.d.ts: -------------------------------------------------------------------------------- 1 | export type AlignType = 'center' | 'left' | 'right'; 2 | -------------------------------------------------------------------------------- /src/types/colors-type.d.ts: -------------------------------------------------------------------------------- 1 | type colors = 2 | | 'stone' 3 | | 'slate' 4 | | 'zinc' 5 | | 'red' 6 | | 'pink' 7 | | 'purple' 8 | | 'deeppurple' 9 | | 'indigo' 10 | | 'blue' 11 | | 'lightblue' 12 | | 'cyan' 13 | | 'teal' 14 | | 'green' 15 | | 'lightgreen' 16 | | 'lime' 17 | | 'yellow' 18 | | 'amber' 19 | | 'orange' 20 | | 'deeporange' 21 | | 'brown' 22 | | 'green' 23 | | 'emerald' 24 | | 'sky' 25 | | 'voilet' 26 | | 'fuchsia' 27 | | 'rose' 28 | | 'gray' 29 | | 'neutral' 30 | | 'lightBlue' 31 | | 'warmGray' 32 | | 'coolGray' 33 | | 'blueGray'; 34 | 35 | type shades = 36 | | '50' 37 | | '100' 38 | | '200' 39 | | '300' 40 | | '400' 41 | | '500' 42 | | '600' 43 | | '700' 44 | | '800' 45 | | '900'; 46 | 47 | type brandColors = 48 | | 'primary' 49 | | 'seconday' 50 | | 'success' 51 | | 'error' 52 | | 'warning' 53 | | 'disabled' 54 | | 'disabledText' 55 | | 'heading' 56 | | 'body' 57 | | 'subtle' 58 | | 'transparent' 59 | | 'semitransparent' 60 | | 'outline' 61 | | 'white' 62 | | 'black' 63 | | 'shadowColor' 64 | | 'bgInput' 65 | | 'bgImage' 66 | 67 | type backgroundShade = '100' | '200' | '300'; 68 | type backgroundColors = `bg${backgroundShade}` 69 | 70 | type colorShades = `${colors}${shades}` 71 | 72 | type genericColorsType = { [K in colorShades]: string }; 73 | 74 | type lightBrandColorsType = { [K in brandColors]: string }; 75 | type unknownLightBrandColors = { 76 | [color: string]: string; 77 | }; 78 | 79 | type darkBrandColorsType = {dark: {[K in brandColors]: string}}; 80 | 81 | export type colorTypes = genericColorsType & 82 | lightBrandColorsType & 83 | unknownLightBrandColors & 84 | darkBrandColorsType & 85 | backgroundColors 86 | 87 | -------------------------------------------------------------------------------- /src/types/direction-type.d.ts: -------------------------------------------------------------------------------- 1 | export type DirectionType = 'vertical' | 'horizontal'; 2 | -------------------------------------------------------------------------------- /src/types/icon-type.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export type IconNode = React.ReactNode; 3 | -------------------------------------------------------------------------------- /src/types/layout-children-type.d.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export type LayoutChildrenType = React.ReactNode | Array; 3 | -------------------------------------------------------------------------------- /src/types/length-type.d.ts: -------------------------------------------------------------------------------- 1 | export type LengthType = 'long' | 'short'; -------------------------------------------------------------------------------- /src/types/size-type.d.ts: -------------------------------------------------------------------------------- 1 | export type SizeType = 2 | | 'xs' 3 | | 'sm' 4 | | 'md' 5 | | 'lg' 6 | | 'xl' 7 | | '2xl' 8 | | '3xl' 9 | | '4xl' 10 | | '5xl'; 11 | 12 | export type FontSizeType = 13 | | 'xs' 14 | | 'sm' 15 | | 'md' 16 | | 'lg' 17 | | 'xl' 18 | | '2xl' 19 | | '3xl' 20 | | '4xl' 21 | | '5xl' 22 | | '6xl' 23 | | '7xl' 24 | | '8xl' 25 | | '9xl'; 26 | 27 | export type ShadowType = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'; 28 | export type RadiusType = 29 | | 'none' 30 | | 'xs' 31 | | 'sm' 32 | | 'md' 33 | | 'lg' 34 | | 'xl' 35 | | '2xl' 36 | | '3xl' 37 | | 'full'; 38 | -------------------------------------------------------------------------------- /src/types/space-type.d.ts: -------------------------------------------------------------------------------- 1 | export type SpaceType = 2 | | 'none' 3 | | 'xs' 4 | | 'sm' 5 | | 'md' 6 | | 'lg' 7 | | 'xl' 8 | | '2xl' 9 | | '3xl' 10 | | '4xl' 11 | | '5xl' 12 | | '6xl' 13 | | '7xl' 14 | | '8xl' 15 | | '9xl'; 16 | export type HorizontalSpaceType = SpaceType; 17 | export type VerticalSpaceType = SpaceType; 18 | export type ListSpaceType = SpaceType; 19 | -------------------------------------------------------------------------------- /src/types/text-align-type.d.ts: -------------------------------------------------------------------------------- 1 | export type TextAlignType = 'auto'| 'left'| 'center'| 'right'| 'justify'; 2 | -------------------------------------------------------------------------------- /src/types/theme.d.ts: -------------------------------------------------------------------------------- 1 | import {colorTypes} from './colors-type'; 2 | import {FontSizeType, RadiusType, ShadowType, SizeType} from './size-type'; 3 | import {SpaceType} from './space-type'; 4 | import {FontThemeType} from './typography-type'; 5 | 6 | type knownScale = {[k in T]: number}; 7 | 8 | type unknownScale = { 9 | [size: string]: number; 10 | }; 11 | 12 | type unknownColors = { 13 | [color: string]: string; 14 | }; 15 | 16 | type possibleSizes = knownScale & unknownScale; 17 | type possibleFontSizes = knownScale & unknownScale; 18 | type possibleSpaces = knownScale & unknownScale; 19 | type possibleColors = colorTypes & unknownColors; 20 | 21 | type ShadowObject = { 22 | shadowColor: string; 23 | shadowOffset: { 24 | width: number; 25 | height: number; 26 | }; 27 | shadowOpacity: number; 28 | shadowRadius: number; 29 | elevation: number; 30 | }; 31 | 32 | export interface themeType { 33 | fontSize: possibleFontSizes; 34 | lineHeight: possibleFontSizes; 35 | size: possibleSizes; 36 | actionButtonSize: possibleSizes; 37 | buttonSize: { 38 | paddingHorizontal: possibleSizes; 39 | paddingVertical: possibleSizes; 40 | }; 41 | iconSize: possibleSizes; 42 | avatarSize: possibleSizes; 43 | badgeSize: possibleSizes; 44 | miniBadgeSize: possibleSizes; 45 | space: possibleSpaces; 46 | indicatorSize: possibleSizes; 47 | colors: possibleColors; 48 | shadow: {[T in ShadowType]: ShadowObject}; 49 | radius: {[T in RadiusType]: number}; 50 | font: FontThemeType; 51 | } 52 | -------------------------------------------------------------------------------- /src/types/typography-type.d.ts: -------------------------------------------------------------------------------- 1 | export type fontBaseType = 'heading' | 'body'; 2 | export type fontVariantType = 3 | | 'light' 4 | | 'medium' 5 | | 'regular' 6 | | 'semibold' 7 | | 'bold' 8 | | 'extrabold' 9 | | 'italic' 10 | | 'bolditalic'; 11 | 12 | export type FontThemeType = { 13 | [K in fontBaseType]: {[T in fontVariantType]: string} 14 | }; 15 | -------------------------------------------------------------------------------- /src/types/width-type.d.ts: -------------------------------------------------------------------------------- 1 | export type WidthType = 'xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'; 2 | -------------------------------------------------------------------------------- /src/util/ThemeProvider.js: -------------------------------------------------------------------------------- 1 | import React, {useEffect} from 'react'; 2 | export const ThemeContext = React.createContext(); 3 | export const ColorSchemeContext = React.createContext(); 4 | export const ComponentContext = React.createContext(); 5 | 6 | export const useThemeContext = () => { 7 | const theme = React.useContext(ThemeContext); 8 | if (theme === undefined) { 9 | throw new Error('useThemeContext must be used within a ThemeProvider'); 10 | } 11 | return theme; 12 | }; 13 | 14 | export const useThemeMode = () => { 15 | const themeInfo = React.useContext(ColorSchemeContext); 16 | if (themeInfo === undefined) { 17 | throw new Error('useThemeMode must be used within a ThemeProvider'); 18 | } 19 | return themeInfo; 20 | }; 21 | 22 | export const useCustomComponent = () => { 23 | const components = React.useContext(ComponentContext); 24 | if (components === undefined) { 25 | throw new Error('useCustomComponent must be used within a ThemeProvider'); 26 | } 27 | return components; 28 | }; 29 | 30 | const ThemeProvider = ({theme, colorMode, children, components}) => { 31 | if (theme === undefined) { 32 | throw new Error('theme value must be provided within a ThemeProvider'); 33 | } 34 | const [isDarkMode, setIsDarkMode] = React.useState(colorMode !== 'light'); 35 | const toggleDarkMode = mode => { 36 | setIsDarkMode(prevValue => (mode ? mode === 'dark' : !prevValue)); 37 | }; 38 | 39 | useEffect(() => { 40 | setIsDarkMode(colorMode === 'dark'); 41 | }, [colorMode]); 42 | 43 | const currentTheme = React.useMemo(() => { 44 | let _theme = {...theme}; 45 | if (isDarkMode) { 46 | _theme = {...theme, colors: {...theme.colors, ...theme.colors.dark}}; 47 | } 48 | return _theme; 49 | }, [isDarkMode, theme]); 50 | 51 | return ( 52 | 53 | 54 | 55 | {children} 56 | 57 | 58 | 59 | ); 60 | }; 61 | 62 | ThemeProvider.defaultProps = { 63 | colorMode: 'light', 64 | }; 65 | 66 | export default ThemeProvider; 67 | -------------------------------------------------------------------------------- /src/util/accessibility.js: -------------------------------------------------------------------------------- 1 | export const extractAccessibilityPropsFromProps = props => { 2 | if (!props) { 3 | return {}; 4 | } 5 | 6 | return { 7 | accessible: props.accessible, 8 | 9 | accessibilityLabel: props.accessibilityLabel, 10 | 11 | accessibilityRole: props.accessibilityRole, 12 | 13 | accessibilityStates: props.accessibilityStates, 14 | 15 | accessibilityHint: props.accessibilityHint, 16 | accessibilityComponentType: props.accessibilityComponentType, 17 | accessibilityLiveRegion: props.importantForAccessibility, 18 | importantForAccessibility: props.accessibilityLiveRegion, 19 | accessibilityElementsHidden: props.accessibilityElementsHidden, 20 | accessibilityTraits: props.accessibilityTraits, 21 | onAccessibilityTap: props.onAccessibilityTap, 22 | onMagicTap: props.onMagicTap, 23 | accessibilityIgnoresInvertColors: props.accessibilityIgnoresInvertColors, 24 | 25 | }; 26 | }; 27 | 28 | export const removeAccessibilityPropsFromProps = props => { 29 | if (!props) { 30 | return {}; 31 | } 32 | const { 33 | accessible, 34 | accessibilityLabel, 35 | accessibilityRole, 36 | accessibilityStates, 37 | accessibilityHint, 38 | accessibilityComponentType, importantForAccessibility, 39 | accessibilityLiveRegion, 40 | accessibilityTraits, 41 | onAccessibilityTap, 42 | onMagicTap, 43 | accessibilityIgnoresInvertColors, 44 | ...otherProps 45 | } = props; 46 | 47 | return { 48 | ...otherProps, 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /src/util/prop-types.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | export const sizeArray = [ 4 | 'xs', 5 | 'sm', 6 | 'md', 7 | 'lg', 8 | 'xl', 9 | '2xl', 10 | '3xl', 11 | '4xl', 12 | '5xl', 13 | ]; 14 | 15 | export const fontSizeArray = [ 16 | 'xs', 17 | 'sm', 18 | 'md', 19 | 'lg', 20 | 'xl', 21 | '2xl', 22 | '3xl', 23 | '4xl', 24 | '5xl', 25 | '6xl', 26 | '7xl', 27 | '8xl', 28 | '9xl', 29 | ]; 30 | 31 | export const spaceArray = [ 32 | 'none', 33 | 'xs', 34 | 'sm', 35 | 'md', 36 | 'lg', 37 | 'xl', 38 | '2xl', 39 | '3xl', 40 | '4xl', 41 | '5xl', 42 | '6xl', 43 | '7xl', 44 | '8xl', 45 | '9xl', 46 | ]; 47 | 48 | export const radiusArray = [ 49 | 'none', 50 | 'xs', 51 | 'sm', 52 | 'md', 53 | 'lg', 54 | 'xl', 55 | '2xl', 56 | '3xl', 57 | 'full', 58 | ]; 59 | 60 | export const fontBaseArray = ['heading', 'body']; 61 | export const fontVariantArray = [ 62 | 'light', 63 | 'medium', 64 | 'regular', 65 | 'semibold', 66 | 'bold', 67 | 'extrabold', 68 | 'italic', 69 | 'bolditalic', 70 | ]; 71 | 72 | export const shadowArray = ['none', 'xs', 'sm', 'md', 'lg', 'xl']; 73 | 74 | export const sizes = PropTypes.oneOf(sizeArray); 75 | export const fontSizes = PropTypes.oneOf(fontSizeArray); 76 | 77 | export const spaces = PropTypes.oneOf(spaceArray); 78 | export const shadows = PropTypes.oneOf(shadowArray); 79 | export const radii = PropTypes.oneOf(radiusArray); 80 | export const fontBases = PropTypes.oneOf(fontBaseArray); 81 | export const fontVariants = PropTypes.oneOf(fontVariantArray); 82 | -------------------------------------------------------------------------------- /src/util/touchable.js: -------------------------------------------------------------------------------- 1 | export const removeBackgroundProp = ({background, ...props}) => { 2 | return { 3 | ...props, 4 | }; 5 | }; 6 | --------------------------------------------------------------------------------