├── .travis.yml ├── src ├── .eslintrc ├── index.test.js ├── components │ ├── ButtonsList.js │ ├── Button.js │ └── Toggler.js ├── index.js └── index.css ├── .eslintignore ├── screenshots ├── 270.gif ├── 360.gif ├── up.gif ├── left.gif ├── right.gif ├── down-180.gif └── down-90.gif ├── example ├── public │ ├── logo.png │ ├── manifest.json │ ├── index.html │ └── style.css ├── src │ ├── index.js │ ├── App.test.js │ ├── index.css │ ├── assets │ │ ├── linkedin.svg │ │ ├── medium.svg │ │ ├── github.svg │ │ ├── spotify.svg │ │ ├── dribbble.svg │ │ ├── instagram.svg │ │ ├── twitter.svg │ │ └── share.svg │ └── App.js ├── README.md └── package.json ├── .npmignore ├── .editorconfig ├── .prettierrc ├── rollup.config.js ├── .eslintrc ├── .gitignore ├── LICENSE ├── package.json └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 12 4 | - 10 5 | -------------------------------------------------------------------------------- /src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | node_modules/ 4 | .snapshots/ 5 | *.min.js -------------------------------------------------------------------------------- /screenshots/270.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AM-77/react-floating-buttons/HEAD/screenshots/270.gif -------------------------------------------------------------------------------- /screenshots/360.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AM-77/react-floating-buttons/HEAD/screenshots/360.gif -------------------------------------------------------------------------------- /screenshots/up.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AM-77/react-floating-buttons/HEAD/screenshots/up.gif -------------------------------------------------------------------------------- /screenshots/left.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AM-77/react-floating-buttons/HEAD/screenshots/left.gif -------------------------------------------------------------------------------- /screenshots/right.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AM-77/react-floating-buttons/HEAD/screenshots/right.gif -------------------------------------------------------------------------------- /example/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AM-77/react-floating-buttons/HEAD/example/public/logo.png -------------------------------------------------------------------------------- /screenshots/down-180.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AM-77/react-floating-buttons/HEAD/screenshots/down-180.gif -------------------------------------------------------------------------------- /screenshots/down-90.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AM-77/react-floating-buttons/HEAD/screenshots/down-90.gif -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | dist 2 | .babelrc 3 | .storybook 4 | .gitignore 5 | .prettierrc 6 | rollup.config.js 7 | tsconfig.json 8 | -------------------------------------------------------------------------------- /src/index.test.js: -------------------------------------------------------------------------------- 1 | import FloatingButtons from '.' 2 | 3 | describe('FloatingButtons', () => { 4 | it('is truthy', () => { 5 | expect(FloatingButtons).toBeTruthy() 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import './index.css' 2 | 3 | import React from 'react' 4 | import ReactDOM from 'react-dom' 5 | import App from './App' 6 | 7 | ReactDOM.render(, document.getElementById('root')) 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": true, 4 | "semi": false, 5 | "tabWidth": 2, 6 | "bracketSpacing": true, 7 | "jsxBracketSameLine": false, 8 | "arrowParens": "always", 9 | "trailingComma": "none" 10 | } 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | This example was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | It is linked to the react-nav-button package in the parent directory for development purposes. 4 | 5 | You can run `yarn install` and then `yarn start` to test your package. 6 | -------------------------------------------------------------------------------- /example/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div') 7 | ReactDOM.render(, div) 8 | ReactDOM.unmountComponentAtNode(div) 9 | }) 10 | -------------------------------------------------------------------------------- /example/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "react-nav-button", 3 | "name": "react-nav-button", 4 | "icons": [ 5 | { 6 | "src": "logo.png", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /example/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import sass from 'rollup-plugin-sass' 2 | import typescript from 'rollup-plugin-typescript2' 3 | 4 | import pkg from './package.json' 5 | 6 | export default { 7 | input: 'src/index.tsx', 8 | output: [ 9 | { 10 | file: pkg.main, 11 | format: 'cjs', 12 | exports: 'named', 13 | sourcemap: true, 14 | strict: false 15 | } 16 | ], 17 | plugins: [sass({ insert: true }), typescript()], 18 | external: ['react', 'react-dom'] 19 | } 20 | -------------------------------------------------------------------------------- /example/src/assets/linkedin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | react-floating-buttons exemples 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react", 6 | "plugin:prettier/recommended", 7 | "prettier/standard", 8 | "prettier/react" 9 | ], 10 | "env": { 11 | "node": true 12 | }, 13 | "parserOptions": { 14 | "ecmaVersion": 2020, 15 | "ecmaFeatures": { 16 | "legacyDecorators": true, 17 | "jsx": true 18 | } 19 | }, 20 | "settings": { 21 | "react": { 22 | "version": "16" 23 | } 24 | }, 25 | "rules": { 26 | "space-before-function-paren": 0, 27 | "react/prop-types": 0, 28 | "react/jsx-handler-names": 0, 29 | "react/jsx-fragments": 0, 30 | "react/no-unused-prop-types": 0, 31 | "import/export": 0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /example/src/assets/medium.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Directory for instrumented libs generated by jscoverage/JSCover 10 | lib-cov 11 | 12 | # Coverage directory used by tools like istanbul 13 | coverage 14 | *.lcov 15 | 16 | # nyc test coverage 17 | .nyc_output 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (https://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directories 26 | node_modules/ 27 | jspm_packages/ 28 | 29 | # TypeScript v1 declaration files 30 | typings/ 31 | 32 | # TypeScript cache 33 | *.tsbuildinfo 34 | 35 | # Optional npm cache directory 36 | .npm 37 | 38 | # Optional eslint cache 39 | .eslintcache 40 | 41 | # Output of 'npm pack' 42 | *.tgz 43 | 44 | # Yarn Integrity file 45 | .yarn-integrity 46 | 47 | # generate output 48 | dist 49 | -------------------------------------------------------------------------------- /example/src/assets/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-floating-buttons-example", 3 | "homepage": "https://AM-77.github.io/react-floating-buttons", 4 | "version": "1.0.0", 5 | "private": true, 6 | "dependencies": { 7 | "react": "link:../node_modules/react", 8 | "react-dom": "link:../node_modules/react-dom", 9 | "react-scripts": "link:../node_modules/react-scripts", 10 | "react-floating-buttons": "link:.." 11 | }, 12 | "scripts": { 13 | "start": "node ../node_modules/react-scripts/bin/react-scripts.js start", 14 | "build": "node ../node_modules/react-scripts/bin/react-scripts.js build", 15 | "test": "node ../node_modules/react-scripts/bin/react-scripts.js test", 16 | "eject": "node ../node_modules/react-scripts/bin/react-scripts.js eject" 17 | }, 18 | "eslintConfig": { 19 | "extends": "react-app" 20 | }, 21 | "browserslist": [ 22 | ">0.2%", 23 | "not dead", 24 | "not ie <= 11", 25 | "not op_mini all" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /example/src/assets/spotify.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/src/assets/dribbble.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vincent Mancini 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 | -------------------------------------------------------------------------------- /example/public/style.css: -------------------------------------------------------------------------------- 1 | *{ 2 | padding: 0; 3 | margin: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | #root{ 8 | padding: 50px 0; 9 | overflow: hidden; 10 | background-color: #fdfdfd 11 | } 12 | 13 | h1, h2{ 14 | text-align: center; 15 | color: #2d2d2d; 16 | font-weight: 300; 17 | text-decoration: underline 18 | } 19 | 20 | .wrapper{ 21 | display: block; 22 | padding: 5%; 23 | width: 100% 24 | } 25 | 26 | .exemple-wrapper .exemples{ 27 | margin: 30px 0; 28 | } 29 | 30 | .exemple-wrapper .exemples .exemple{ 31 | display: block; 32 | width: 100%; 33 | position: relative 34 | } 35 | 36 | .exemple-wrapper .exemples .exemple code{ 37 | display: block; 38 | text-align: center; 39 | font-size: 14px; 40 | background-color: #efefef; 41 | padding: 10px; 42 | line-height: 3; 43 | border-radius: 5px; 44 | margin: 0 auto; 45 | } 46 | 47 | .exemple-wrapper .component{ 48 | position: relative; 49 | height: 150px; 50 | } 51 | 52 | .exemple-wrapper.vertical .exemples, 53 | .exemple-wrapper.circular .exemples{ 54 | flex: wrap row; 55 | width: 100%; 56 | } 57 | 58 | .exemple-wrapper.vertical .component{ 59 | height: 350px; 60 | } 61 | 62 | .exemple-wrapper.circular .component{ 63 | height: 450px; 64 | } 65 | 66 | .exemple-wrapper.circular .component.half{ 67 | height: 250px; 68 | } 69 | 70 | .red{ 71 | background: red 72 | } -------------------------------------------------------------------------------- /example/src/assets/instagram.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ButtonsList.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import PropTypes from 'prop-types' 3 | import Button from './Button' 4 | 5 | class ButtonsList extends Component { 6 | 7 | render() { 8 | const { dimension, buttonsList, itemBackgroundColor, direction, degree, distance, isOpen} = this.props 9 | return ( 10 | { 11 | buttonsList.map((item, index) => ) 137 | } 138 | } 139 | 140 | Button.defaultProps = { 141 | onClick: () => {}, 142 | } 143 | 144 | Button.propTypes = { 145 | distance: PropTypes.number, 146 | degree: PropTypes.number.isRequired, 147 | dimension: PropTypes.number.isRequired, 148 | itemBackgroundColor: PropTypes.string, 149 | onClick: PropTypes.func, 150 | src: PropTypes.string.isRequired, 151 | index: PropTypes.number.isRequired, 152 | nbrItems: PropTypes.number.isRequired, 153 | isOpen: PropTypes.bool.isRequired, 154 | direction: PropTypes.string.isRequired, 155 | } 156 | 157 | export default Button -------------------------------------------------------------------------------- /src/components/Toggler.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | class Toggler extends Component { 5 | 6 | constructor(props){ 7 | super(props) 8 | const { dimension, backgroundColor, buttonColor } = this.props 9 | 10 | this.initButtonStyle = { 11 | display: 'flex', 12 | flexFlow: 'column wrap', 13 | justifyContent: 'space-around', 14 | alignItems: 'center', 15 | height: `${dimension}px`, 16 | width: `${dimension}px`, 17 | backgroundColor, 18 | borderRadius: `${dimension * 0.5}px`, 19 | padding: `${(dimension * 0.2) - 1}px`, 20 | cursor: 'pointer', 21 | zIndex: 2, 22 | position: "relative", 23 | opacity: "0.9", 24 | borderWidth: '1px', 25 | borderColor: 'rgba(0, 0, 0, 0.2)', 26 | boxShadow: '0 0 0 1px rgba(0, 0, 0, .08), 0 2px 2px rgba(0, 0, 0, .15)', 27 | transition: 'all 350ms cubic-bezier(0.25, 0, 0, 1)', 28 | outline: 'none' 29 | } 30 | 31 | this.initSpanStyle = { 32 | display: 'block', 33 | backgroundColor: buttonColor, 34 | width: `${dimension * .6}px`, 35 | height: `${dimension * 0.075}px`, 36 | borderRadius: `${(dimension * 0.075) / 2}px`, 37 | transformOrigin: 'center left', 38 | transition: 'all 350ms cubic-bezier(0.25, 0, 0, 1)', 39 | position: 'relative' 40 | } 41 | 42 | this.state = { 43 | buttonStyle: this.initButtonStyle, 44 | spanStyle: this.initSpanStyle, 45 | spanOneStyle: {}, 46 | spanTwoStyle: {}, 47 | spanThreeStyle: {} 48 | } 49 | 50 | } 51 | 52 | componentDidMount() { 53 | const { dimension, buttonType } = this.props 54 | 55 | if(buttonType === 'plus'){ 56 | this.setState((state) => ({ 57 | ...state, 58 | spanStyle:{ 59 | ...state.spanStyle, 60 | width: (dimension * .5), 61 | height: dimension * 0.075, 62 | position: 'absolute', 63 | transformOrigin: 'center center' 64 | }, 65 | spanTwoStyle:{ display: 'none'}, 66 | spanThreeStyle:{ transform: 'rotate(90deg)' } 67 | })) 68 | }else{ 69 | if(buttonType === 'hori-dots' || buttonType === 'vert-dots'){ 70 | this.setState((state) => ({ 71 | ...state, 72 | spanStyle:{ 73 | ...state.spanStyle, 74 | width: dimension * 0.1, 75 | height: dimension * 0.1, 76 | borderRadius: dimension * 0.1 77 | } 78 | })) 79 | 80 | if(buttonType === 'hori-dots'){ 81 | this.setState((state) => ({ 82 | spanStyle:{ 83 | ...state.spanStyle, 84 | position: 'absolute' 85 | }, 86 | spanOneStyle:{ 87 | left: '25%' 88 | }, 89 | spanThreeStyle:{ 90 | right: '25%' 91 | } 92 | })) 93 | } 94 | } 95 | } 96 | 97 | } 98 | 99 | toggleOpen = () => { 100 | const { buttonType, toggleOpen } = this.props 101 | toggleOpen() 102 | 103 | if(buttonType === 'plus'){ 104 | this.animatePlusButton() 105 | }else if(buttonType === 'hamburger'){ 106 | this.animateHmburgerButton() 107 | } 108 | } 109 | 110 | animatePlusButton = () => { 111 | const { isOpen } = this.props 112 | if(!isOpen){ 113 | this.setState((state) => ({ 114 | ...state, 115 | buttonStyle: { 116 | ...state.buttonStyle, 117 | transform: 'rotate(135deg)' 118 | } 119 | })) 120 | }else{ 121 | this.setState((state) => ({ 122 | ...state, 123 | buttonStyle: { 124 | ...state.buttonStyle, 125 | transform: 'rotate(0deg)' 126 | } 127 | })) 128 | } 129 | } 130 | 131 | animateHmburgerButton = () => { 132 | const { isOpen } = this.props 133 | if(!isOpen){ 134 | this.setState((state) => ({ 135 | ...state, 136 | spanOneStyle:{ 137 | transform: 'rotate(45deg)', 138 | left: '12.5%', 139 | top: '-2.5%' 140 | }, 141 | spanTwoStyle:{ 142 | transform: 'rotateY(90deg)', 143 | opacity: 0 144 | }, 145 | spanThreeStyle:{ 146 | transform: 'rotate(-45deg)', 147 | left: '12.5%', 148 | top: '2.5%' 149 | } 150 | })) 151 | }else{ 152 | this.setState((state) => ({ 153 | ...state, 154 | spanOneStyle:{ 155 | transform: 'rotate(0deg)', 156 | left: '0%', 157 | top: '0%' 158 | }, 159 | spanTwoStyle:{ 160 | transform: 'rotateY(0deg)', 161 | opacity: 1 162 | }, 163 | spanThreeStyle:{ 164 | transform: 'rotate(0deg)', 165 | left: '0%', 166 | top: '0%' 167 | } 168 | })) 169 | } 170 | } 171 | 172 | mouseEnter = () => { 173 | this.setState((state) => ({ 174 | ...state, 175 | buttonStyle: { 176 | ...state.buttonStyle, 177 | opacity: '1', 178 | boxShadow: 'none' 179 | } 180 | })) 181 | } 182 | 183 | mouseLeave = () => { 184 | const { isOpen } = this.props 185 | if(isOpen){ 186 | this.setState((state) => ({ 187 | ...state, 188 | buttonStyle: { ...state.buttonStyle} 189 | })) 190 | }else{ 191 | this.setState((state) => ({ 192 | ...state, 193 | buttonStyle: { ...this.initButtonStyle} 194 | })) 195 | } 196 | } 197 | 198 | render() { 199 | return ( ) 208 | } 209 | } 210 | 211 | Toggler.defaultProps = { 212 | dimension: 80, 213 | backgroundColor: '#f8f9fa', 214 | buttonColor: '#313131' 215 | } 216 | 217 | Toggler.propTypes = { 218 | buttonType: PropTypes.string.isRequired, 219 | toggleOpen: PropTypes.func.isRequired, 220 | isOpen: PropTypes.bool.isRequired, 221 | dimension: PropTypes.number, 222 | backgroundColor: PropTypes.string, 223 | buttonColor: PropTypes.string 224 | } 225 | 226 | export default Toggler 227 | -------------------------------------------------------------------------------- /example/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import FloatingButtons from 'react-floating-buttons' 3 | 4 | import instagram from './assets/instagram.svg' 5 | import github from './assets/github.svg' 6 | import dribbble from './assets/dribbble.svg' 7 | import linkedin from './assets/linkedin.svg' 8 | import medium from './assets/medium.svg' 9 | import spotify from './assets/spotify.svg' 10 | import twitter from './assets/twitter.svg' 11 | 12 | 13 | function App () { 14 | 15 | const buttonsList = [ 16 | { onClick: ()=> alert('clicked instagram'), src: instagram }, 17 | { onClick: ()=> alert('clicked medium'), src: medium }, 18 | { onClick: ()=> alert('clicked dribbble'), src: dribbble }, 19 | { onClick: ()=> alert('clicked github'), src: github }, 20 | { onClick: ()=> alert('clicked linkedin'), src: linkedin }, 21 | { onClick: ()=> alert('clicked spotify'), src: spotify }, 22 | { onClick: ()=> alert('clicked twitter'), src: twitter }, 23 | ] 24 | 25 | return (<> 26 |

react-floating-buttons exemples

27 |
28 |
29 |

Horizantal floating button

30 |
31 |
32 | 33 | {` `} 40 | 41 |
42 | 50 |
51 |
52 | 53 |
54 | 55 | {` `} 62 | 63 |
64 | 71 |
72 |
73 |
74 |
75 | 76 |
77 |

vertical floating button

78 |
79 |
80 | 81 | {` `} 91 | 92 |
93 | 103 |
104 |
105 | 106 |
107 | 108 | {` `} 118 | 119 |
120 | 131 |
132 |
133 |
134 |
135 | 136 |
137 |

circular floating button

138 |
139 |
140 | 141 | {` `} 150 | 151 |
152 | 161 |
162 |
163 | 164 |
165 | 166 | {` `} 174 | 175 |
176 | 184 |
185 |
186 | 187 |
188 | 189 | {` `} 197 | 198 |
199 | 207 |
208 |
209 | 210 |
211 | 212 | {` `} 221 | 222 |
223 | 232 |
233 |
234 | 235 |
236 | 237 | {` `} 246 | 247 |
248 | 257 |
258 |
259 | 260 |
261 | 262 | {` `} 271 | 272 |
273 | 274 | 283 |
284 |
285 |
286 |
287 | 288 |
289 | ) 290 | } 291 | 292 | export default App 293 | --------------------------------------------------------------------------------