├── .travis.yml ├── CHANGELOG.md ├── src ├── index.js └── main.jsx ├── .babelrc ├── examples ├── styles.css ├── run.jsx ├── base.html └── main.jsx ├── .eslintrc ├── LICENSE ├── test └── Back2TopTest.js ├── karma.config.js ├── webpack.examples.cfg.js ├── webpack.server.js ├── .gitignore ├── .npmignore ├── package.json └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6.11" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | 3 | * **0.1.0** Initial release -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Back2Top from './main'; 2 | 3 | export default Back2Top -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false 7 | } 8 | ], 9 | "react", 10 | "stage-0" 11 | ], 12 | "plugins": [ 13 | "transform-object-assign", 14 | "transform-react-display-name", 15 | "transform-runtime" 16 | ] 17 | } -------------------------------------------------------------------------------- /examples/styles.css: -------------------------------------------------------------------------------- 1 | .back-to-top { 2 | position: fixed; 3 | top: 100px; 4 | right: 15px; 5 | z-index: 1000; 6 | display: none; 7 | padding-top: 13px; 8 | width: 50px; 9 | height: 40px; 10 | /*border: 0;*/ 11 | /*border-radius: 50%;*/ 12 | /*background: #00A79D;*/ 13 | /*box-shadow: 0 0 9px rgba(153, 153, 153, 0.8);*/ 14 | /*color: white;*/ 15 | text-align: center; 16 | font-size: 20px; 17 | transform: translate(0, 0); 18 | text-rendering: auto; 19 | -webkit-font-smoothing: antialiased; 20 | -moz-osx-font-smoothing: grayscale; 21 | } 22 | 23 | .back-to-top:hover { 24 | background: transparent; 25 | color: white; 26 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "react", 5 | "eslint-plugin-react" 6 | ], 7 | "env": { 8 | "browser": true, 9 | "amd": true, 10 | "es6": true, 11 | "node": false 12 | }, 13 | "rules": { 14 | "comma-dangle": 1, 15 | "quotes": [ 16 | 1, 17 | "single" 18 | ], 19 | "no-undef": 1, 20 | "global-strict": 0, 21 | "no-extra-semi": 1, 22 | "no-underscore-dangle": 0, 23 | "no-extra-parens": 0, 24 | "no-console": 1, 25 | "no-unused-vars": 1, 26 | "no-trailing-spaces": [ 27 | 1, 28 | { 29 | "skipBlankLines": true 30 | } 31 | ], 32 | "no-alert": 0, 33 | "no-unreachable": 1, 34 | "react/jsx-uses-react": 1, 35 | "react/jsx-uses-vars": 1 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Thomas Bolis 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 | -------------------------------------------------------------------------------- /examples/run.jsx: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | 'use strict'; 3 | (function () { 4 | let React = require('react'); 5 | let ReactDOM = require('react-dom'); 6 | let AppContainer = require('react-hot-loader').AppContainer; 7 | let injectTapEventPlugin = require('react-tap-event-plugin'); 8 | let DemoApp = require('./main').default; 9 | 10 | // Needed for React Developer Tools (Chrome Extension) 11 | window.React = React; 12 | 13 | /* Some components use react-tap-event-plugin to listen for touch events. 14 | This dependency is temporary and will go away once react v1.0 is released. 15 | Until then, be sure to inject this plugin at the start of your app */ 16 | injectTapEventPlugin(); 17 | 18 | const containerEl = document.getElementById('container'); 19 | 20 | // Render the main app react component into the app div 21 | ReactDOM.render(, containerEl); 22 | 23 | // HRM 24 | if (module && module.hot) { 25 | module.hot.accept('./main.jsx', () => { 26 | const Demo = require('./main.jsx').default; 27 | ReactDOM.render(, containerEl); 28 | }); 29 | } 30 | })(); -------------------------------------------------------------------------------- /examples/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 20 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/Back2TopTest.js: -------------------------------------------------------------------------------- 1 | /*global descibe*/ 2 | /* eslint no-console: 0 */ 3 | /* eslint-env node, mocha */ 4 | 5 | 'use strict'; 6 | 7 | import React from 'react'; 8 | import TestUtils from 'react-dom/test-utils'; 9 | import Back2Top from 'react-back2top'; 10 | import {isNumber} from '../src/main'; 11 | import {describe, it} from 'mocha'; 12 | 13 | describe('Back2Top Component', () => { 14 | 15 | it('loads normally', () => { 16 | expect(require('../src/main')).to.exist; 17 | }); 18 | 19 | it('has default className', () => { 20 | const MyBack2Top = TestUtils.renderIntoDocument(); 21 | expect(TestUtils.findRenderedDOMComponentWithClass(MyBack2Top, 'back-to-top')).to.exist; 22 | }); 23 | 24 | it('can change className', () => { 25 | const MyBack2Top = TestUtils.renderIntoDocument(); 26 | expect(TestUtils.findRenderedDOMComponentWithClass(MyBack2Top, 'my-class-name')).to.exist; 27 | }); 28 | 29 | it('custom onClick is executed', () => { 30 | let clicked = false; 31 | const MyBack2Top = TestUtils.renderIntoDocument( clicked = true}/>); 33 | TestUtils.Simulate.click(TestUtils.findRenderedDOMComponentWithTag(MyBack2Top, 'a')); 34 | expect(clicked).to.be.true; 35 | }); 36 | 37 | }); 38 | 39 | describe('isNumber', () => { 40 | 41 | it('finds number objects properly', () => { 42 | expect(isNumber(3)).to.be.true; 43 | expect(isNumber('not a number')).to.be.false; 44 | }) 45 | 46 | }); -------------------------------------------------------------------------------- /karma.config.js: -------------------------------------------------------------------------------- 1 | /*global __dirname,module*/ 2 | 3 | const path = require('path'); 4 | const srcPath = path.join(__dirname, 'src'); 5 | const testPath = path.join(__dirname, 'test'); 6 | 7 | module.exports = function (config) { 8 | config.set({ 9 | basePath: './', 10 | browsers: ['jsdom'], 11 | // Continuous Integration mode 12 | // if true, Karma captures browsers, runs the tests and exits 13 | singleRun: true, 14 | concurrency: Infinity, 15 | frameworks: ['mocha', 'chai'], 16 | files: [ 17 | 'test/**/*Test.js' 18 | ], 19 | preprocessors: { 20 | 'test/**/*Test.js': ['webpack', 'sourcemap'] 21 | }, 22 | captureTimeout: 60000, 23 | client: { 24 | mocha: {}, 25 | captureConsole: false 26 | }, 27 | reporters: ['mocha'], //, 'coverage' 28 | webpack: { 29 | node: { 30 | fs: 'empty' 31 | }, 32 | devtool: 'inline-source-map', 33 | resolve: { 34 | extensions: ['.js', '.jsx'], 35 | alias: { 36 | 'react-back2top': srcPath 37 | } 38 | }, 39 | module: { 40 | loaders: [ 41 | { 42 | test: /\.(js|jsx)$/, 43 | include: [srcPath, testPath], 44 | exclude: /(node_modules|bower_components|examples)/, 45 | loaders: ['babel-loader'] 46 | } 47 | ] 48 | }, 49 | stats: { 50 | colors: true, 51 | reasons: true 52 | } 53 | }, 54 | webpackServer: { 55 | noInfo: true 56 | }, 57 | webpackMiddleware: { 58 | noInfo: true, 59 | stats: { 60 | chunks: false 61 | } 62 | }, 63 | coverageReporter: { 64 | dir: 'coverage/', 65 | reporters: [ 66 | {type: 'html'}, 67 | {type: 'text'} 68 | ] 69 | } 70 | }); 71 | }; 72 | -------------------------------------------------------------------------------- /webpack.examples.cfg.js: -------------------------------------------------------------------------------- 1 | /*global __dirname,module*/ 2 | /*eslint no-console:0 */ 3 | 4 | const path = require('path'); 5 | const srcPath = path.join(__dirname, 'src'); 6 | const examplesPath = path.join(__dirname, 'examples'); 7 | 8 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 9 | const DefinePlugin = require('webpack/lib/DefinePlugin'); 10 | const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin'); 11 | const NoEmitOnErrorsPlugin = require('webpack/lib/NoEmitOnErrorsPlugin'); 12 | const AggressiveMergingPlugin = require('webpack/lib/optimize/AggressiveMergingPlugin'); 13 | 14 | const config = { 15 | entry: { 16 | examples: path.join(examplesPath, 'run') 17 | }, 18 | output: { 19 | path: path.join(__dirname, '/build'), 20 | filename: 'index.js', 21 | publicPath: '' 22 | }, 23 | resolve: { 24 | extensions: ['.js', '.jsx'] 25 | }, 26 | cache: true, 27 | devtool: 'sourcemap', 28 | module: { 29 | rules: [ 30 | {test: /\.html$/, loader: 'html-loader', include: [examplesPath], exclude: /base\.html$/}, 31 | {test: /\.css$/, loader: 'style-loader!css-loader'}, 32 | { 33 | test: /\.(js|jsx)$/, 34 | include: [srcPath, examplesPath], 35 | exclude: /(node_modules|bower_components|lib)/, 36 | loaders: ['babel-loader'] 37 | } 38 | ] 39 | }, 40 | plugins: [ 41 | new DefinePlugin({ 42 | 'process.env': { 43 | NODE_ENV: JSON.stringify('production') 44 | } 45 | }), 46 | new NoEmitOnErrorsPlugin(), 47 | new AggressiveMergingPlugin(), 48 | new UglifyJsPlugin({ 49 | sourceMap: true, 50 | compress: { 51 | warnings: false, 52 | screw_ie8: true 53 | } 54 | }), 55 | new HtmlWebpackPlugin({ 56 | title: 'React-Back2Top Button', 57 | description: 'React based back to top button', 58 | keywords: ['React', 'back', 'top', 'scroll-up'], 59 | template: path.join(examplesPath, 'base.html'), 60 | inject: 'body', 61 | filename: 'index.html', 62 | chunks: ['examples'] 63 | }) 64 | ] 65 | }; 66 | 67 | module.exports = config; -------------------------------------------------------------------------------- /webpack.server.js: -------------------------------------------------------------------------------- 1 | /*global __dirname*/ 2 | /*eslint no-console:0 */ 3 | 4 | const path = require('path'); 5 | const webpack = require('webpack'); 6 | const WebpackDevServer = require('webpack-dev-server'); 7 | 8 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 9 | const NoEmitOnErrorsPlugin = require('webpack/lib/NoEmitOnErrorsPlugin'); 10 | const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin'); 11 | 12 | const srcPath = path.join(__dirname, 'src'); 13 | const examplesPath = path.join(__dirname, 'examples'); 14 | 15 | const OpenBrowserPlugin = require('open-browser-webpack-plugin'); 16 | 17 | const port = 23000; 18 | 19 | const config = { 20 | entry: { 21 | examples: [ 22 | 'webpack-dev-server/client?http://localhost:' + port, 23 | 'webpack/hot/only-dev-server', 24 | path.join(examplesPath, 'run') 25 | ] 26 | }, 27 | output: { 28 | path: path.join(__dirname, '/build'), 29 | filename: 'index.js', 30 | publicPath: '/' 31 | }, 32 | resolve: { 33 | extensions: ['.js', '.jsx'], 34 | alias: { 35 | 'react-back2top': path.join(__dirname, '/src') 36 | } 37 | }, 38 | cache: true, 39 | devtool: 'sourcemap', 40 | devServer: { 41 | historyApiFallback: true, 42 | stats: {colors: true}, 43 | publicPath: '/', 44 | noInfo: false, 45 | port: port, 46 | hot: true 47 | }, 48 | module: { 49 | rules: [ 50 | {test: /\.html$/, loader: 'html-loader', include: [examplesPath], exclude: /base\.html$/}, 51 | {test: /\.css$/, loader: 'style-loader!css-loader'}, 52 | { 53 | test: /\.(js|jsx)$/, 54 | include: [srcPath, examplesPath], 55 | exclude: /(node_modules|bower_components)/, 56 | loaders: ['babel-loader'] 57 | } 58 | ] 59 | }, 60 | plugins: [ 61 | new HotModuleReplacementPlugin(), 62 | new NoEmitOnErrorsPlugin(), 63 | new HtmlWebpackPlugin({ 64 | title: 'React-Back2Top Button', 65 | description: 'React based back to top button', 66 | keywords: ['React', 'back', 'top', 'scroll-up'], 67 | template: path.join(examplesPath, 'base.html'), 68 | inject: 'body', 69 | filename: 'index.html', 70 | chunks: ['examples'] 71 | }), 72 | new OpenBrowserPlugin({url: 'http://localhost:' + port}) 73 | ] 74 | }; 75 | 76 | new WebpackDevServer(webpack(config), config.devServer) 77 | .listen(port, 'localhost', function (err) { 78 | if (err) { 79 | console.log(err); 80 | } 81 | console.log('Serving from http://localhost:' + port); 82 | } 83 | ); 84 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Linux template 2 | *~ 3 | 4 | # KDE directory preferences 5 | .directory 6 | 7 | # Linux trash folder which might appear on any partition or disk 8 | .Trash-* 9 | 10 | 11 | ### Node template 12 | # Logs 13 | logs 14 | *.log 15 | npm-debug.log* 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | 28 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (http://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directory 38 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 39 | node_modules/ 40 | 41 | #Yeoman 42 | bower_components/ 43 | build/ 44 | dist/ 45 | lib/ 46 | 47 | yarn.lock 48 | 49 | ### OSX template 50 | .DS_Store 51 | .AppleDouble 52 | .LSOverride 53 | 54 | # Icon must end with two \r 55 | Icon 56 | 57 | # Thumbnails 58 | ._* 59 | 60 | # Files that might appear in the root of a volume 61 | .DocumentRevisions-V100 62 | .fseventsd 63 | .Spotlight-V100 64 | .TemporaryItems 65 | .Trashes 66 | .VolumeIcon.icns 67 | 68 | # Directories potentially created on remote AFP share 69 | .AppleDB 70 | .AppleDesktop 71 | Network Trash Folder 72 | Temporary Items 73 | .apdisk 74 | ### JetBrains template 75 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 76 | 77 | *.iml 78 | 79 | ## Directory-based project format: 80 | .idea/ 81 | # if you remove the above rule, at least ignore the following: 82 | 83 | # User-specific stuff: 84 | # .idea/workspace.xml 85 | # .idea/tasks.xml 86 | # .idea/dictionaries 87 | 88 | # Sensitive or high-churn files: 89 | # .idea/dataSources.ids 90 | # .idea/dataSources.xml 91 | # .idea/sqlDataSources.xml 92 | # .idea/dynamic.xml 93 | # .idea/uiDesigner.xml 94 | 95 | # Gradle: 96 | # .idea/gradle.xml 97 | # .idea/libraries 98 | 99 | # Mongo Explorer plugin: 100 | # .idea/mongoSettings.xml 101 | 102 | ## File-based project format: 103 | *.ipr 104 | *.iws 105 | 106 | ## Plugin-specific files: 107 | 108 | # IntelliJ 109 | /out/ 110 | 111 | # mpeltonen/sbt-idea plugin 112 | .idea_modules/ 113 | 114 | # JIRA plugin 115 | atlassian-ide-plugin.xml 116 | 117 | # Crashlytics plugin (for Android Studio and IntelliJ) 118 | com_crashlytics_export_strings.xml 119 | crashlytics.properties 120 | crashlytics-build.properties 121 | 122 | 123 | ### Windows template 124 | # Windows image file caches 125 | Thumbs.db 126 | ehthumbs.db 127 | 128 | # Folder config file 129 | Desktop.ini 130 | 131 | # Recycle Bin used on file shares 132 | $RECYCLE.BIN/ 133 | 134 | # Windows Installer files 135 | *.cab 136 | *.msi 137 | *.msm 138 | *.msp 139 | 140 | # Windows shortcuts 141 | *.lnk 142 | 143 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | examples/ 2 | test/ 3 | .travis.yml 4 | 5 | 6 | 7 | ### Linux template 8 | *~ 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | 17 | ### Node template 18 | # Logs 19 | logs 20 | *.log 21 | npm-debug.log* 22 | 23 | # Runtime data 24 | pids 25 | *.pid 26 | *.seed 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | lib-cov 30 | 31 | # Coverage directory used by tools like istanbul 32 | coverage 33 | 34 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 35 | .grunt 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (http://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directory 44 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 45 | node_modules/ 46 | 47 | #Yeoman 48 | bower_components/ 49 | build/ 50 | dist/ 51 | 52 | 53 | ### OSX template 54 | .DS_Store 55 | .AppleDouble 56 | .LSOverride 57 | 58 | # Icon must end with two \r 59 | Icon 60 | 61 | # Thumbnails 62 | ._* 63 | 64 | # Files that might appear in the root of a volume 65 | .DocumentRevisions-V100 66 | .fseventsd 67 | .Spotlight-V100 68 | .TemporaryItems 69 | .Trashes 70 | .VolumeIcon.icns 71 | 72 | # Directories potentially created on remote AFP share 73 | .AppleDB 74 | .AppleDesktop 75 | Network Trash Folder 76 | Temporary Items 77 | .apdisk 78 | ### JetBrains template 79 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 80 | 81 | *.iml 82 | 83 | ## Directory-based project format: 84 | .idea/ 85 | # if you remove the above rule, at least ignore the following: 86 | 87 | # User-specific stuff: 88 | # .idea/workspace.xml 89 | # .idea/tasks.xml 90 | # .idea/dictionaries 91 | 92 | # Sensitive or high-churn files: 93 | # .idea/dataSources.ids 94 | # .idea/dataSources.xml 95 | # .idea/sqlDataSources.xml 96 | # .idea/dynamic.xml 97 | # .idea/uiDesigner.xml 98 | 99 | # Gradle: 100 | # .idea/gradle.xml 101 | # .idea/libraries 102 | 103 | # Mongo Explorer plugin: 104 | # .idea/mongoSettings.xml 105 | 106 | ## File-based project format: 107 | *.ipr 108 | *.iws 109 | 110 | ## Plugin-specific files: 111 | 112 | # IntelliJ 113 | /out/ 114 | 115 | # mpeltonen/sbt-idea plugin 116 | .idea_modules/ 117 | 118 | # JIRA plugin 119 | atlassian-ide-plugin.xml 120 | 121 | # Crashlytics plugin (for Android Studio and IntelliJ) 122 | com_crashlytics_export_strings.xml 123 | crashlytics.properties 124 | crashlytics-build.properties 125 | 126 | 127 | ### Windows template 128 | # Windows image file caches 129 | Thumbs.db 130 | ehthumbs.db 131 | 132 | # Folder config file 133 | Desktop.ini 134 | 135 | # Recycle Bin used on file shares 136 | $RECYCLE.BIN/ 137 | 138 | # Windows Installer files 139 | *.cab 140 | *.msi 141 | *.msm 142 | *.msp 143 | 144 | # Windows shortcuts 145 | *.lnk 146 | 147 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-back2top", 3 | "version": "0.1.6", 4 | "description": "A React component for Back-To-Top button/link functionality", 5 | "keywords": [ 6 | "back", 7 | "top", 8 | "react", 9 | "back-to-top", 10 | "back2top", 11 | "back-2-top", 12 | "button" 13 | ], 14 | "homepage": "https://github.com/tbolis/react-back2top", 15 | "bugs": "https://github.com/tbolis/react-back2top/issues", 16 | "author": { 17 | "name": "Thomas Bolis", 18 | "email": "thomas.bolis@gmail.com" 19 | }, 20 | "license": "MIT", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/tbolis/react-back2top.git" 24 | }, 25 | "main": "lib/index.js", 26 | "scripts": { 27 | "clean": "rimraf build/ & rimraf lib/", 28 | "prebuild": "rimraf lib", 29 | "build": "babel ./src --out-dir ./lib", 30 | "build:examples": "webpack --config webpack.examples.cfg.js", 31 | "prepublish": "npm run test && npm run build", 32 | "lint": "eslint ./src", 33 | "lint:fix": "eslint --fix ./src", 34 | "start": "node webpack.server.js", 35 | "test": "NODE_ENV=testing karma start karma.config.js" 36 | }, 37 | "peerDependencies": { 38 | "prop-types": "latest", 39 | "react": "^16.0.0", 40 | "react-dom": "^16.0.0" 41 | }, 42 | "devDependencies": { 43 | "babel-cli": "^6.26.0", 44 | "babel-core": "^6.26.0", 45 | "babel-eslint": "^8.0.1", 46 | "babel-loader": "^7.1.2", 47 | "babel-plugin-transform-object-assign": "^6.22.0", 48 | "babel-plugin-transform-react-display-name": "^6.25.0", 49 | "babel-plugin-transform-runtime": "^6.23.0", 50 | "babel-polyfill": "^6.26.0", 51 | "babel-preset-env": "^1.6.1", 52 | "babel-preset-react": "^6.24.1", 53 | "babel-preset-stage-0": "^6.24.1", 54 | "chai": "^4.1.2", 55 | "css-loader": "^0.28.7", 56 | "eslint": "^4.9.0", 57 | "eslint-loader": "^1.9.0", 58 | "eslint-plugin-react": "^7.4.0", 59 | "html-loader": "^0.5.1", 60 | "html-webpack-plugin": "^2.30.1", 61 | "jsdom": "^11.3.0", 62 | "karma": "^1.7.1", 63 | "karma-babel-preprocessor": "^7.0.0", 64 | "karma-chai": "^0.1.0", 65 | "karma-coverage": "^1.1.1", 66 | "karma-jsdom-launcher": "^6.1.2", 67 | "karma-mocha": "^1.3.0", 68 | "karma-mocha-reporter": "^2.2.5", 69 | "karma-sourcemap-loader": "^0.3.7", 70 | "karma-webpack": "^2.0.5", 71 | "material-ui": "^0.19.4", 72 | "mocha": "^4.0.1", 73 | "open-browser-webpack-plugin": "0.0.5", 74 | "prop-types": "^15.6.0", 75 | "react": "^16.0.0", 76 | "react-dom": "^16.0.0", 77 | "react-hot-loader": "^3.1.1", 78 | "react-tap-event-plugin": "^3.0.2", 79 | "react-test-renderer": "^16.0.0", 80 | "react-testutils-additions": "^15.3.0", 81 | "rimraf": "^2.6.2", 82 | "style-loader": "^0.19.0", 83 | "webpack": "^3.8.1", 84 | "webpack-dev-server": "^2.9.3" 85 | }, 86 | "dependencies": { 87 | "easing-js": "1.1.2", 88 | "lodash": "4.17.4", 89 | "performance-now": "2.1.0", 90 | "raf": "3.4.0" 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Back To Top React Component 2 | 3 | [![GitHub release][github-image]][github-url] 4 | [![NPM downloads][downloads-image]][downloads-url] 5 | [![Build status][travis-image]][travis-url] 6 | 7 | A react component to perform a "back to top" action 8 | 9 | ## Installation 10 | 11 | npm install --save react-back2top 12 | 13 | ## Usage 14 | 15 | Import the relevant Back2Top component and use it, you can find more on the examples folder of the project 16 | 17 | ```javascript 18 | import React from 'react'; 19 | import Back2Top from 'react-back2top'; 20 | import {FloatingActionButton} from 'material-ui'; 21 | import UpIcon from 'material-ui/lib/svg-icons/navigation/arrow-upward'; 22 | 23 | class Demo extends React.Component { 24 | render() { 25 | return ( 26 |
27 | 28 |

29 | Scroll down for the button to appear 30 |

31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |

39 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis consectetur turpis in arcu 40 | consectetur, a mollis erat rhoncus. Suspendisse quam turpis, cursus et sapien dignissim, ornare 41 | suscipit lectus. Ut elementum felis ac magna fringilla, a semper lacus commodo. Vivamus et vehicula 42 | orci. Pellentesque porta tincidunt arcu, a consectetur risus maximus in. Aliquam at justo molestie, 43 | mattis nibh in, varius neque. Quisque ac tellus egestas, malesuada tortor ut, luctus dolor. Sed 44 | facilisis mauris quis fringilla pellentesque. Curabitur ullamcorper ut quam vel commodo. In 45 | tincidunt placerat tempus. Morbi nisi ligula, tristique in lorem quis, blandit iaculis libero. Duis 46 | sodales, purus eget pretium suscipit, massa lorem lobortis augue, in porta sem felis at lacus. 47 | Praesent ut condimentum ex. 48 |

49 | 50 | .... 51 | 52 | {/* A Long page */} 53 | 54 |
55 | 56 | ) 57 | } 58 | } 59 | 60 | ``` 61 | 62 | ## Example 63 | 64 | The project includes a webpack server for running the examples, just run: 65 | 66 | ```sh 67 | git clone https://github.com/tbolis/react-back2top.git 68 | npm install 69 | npm start 70 | ``` 71 | 72 | You can also check the live showcase here: http://tbolis.github.io/showcase/react-back2top/ 73 | 74 | ## Features 75 | 76 | You can control the behavior of the button with the following component properties 77 | 78 | | Property | Description | 79 | |----------|-------------| 80 | | alwaysVisible | Make the button always visible | 81 | | fadeDuration | Duration of fade effect | 82 | | scrollDuration | Duration of scroll-to-top effect | 83 | | visibilityHeight | Height page where button becomes visible | 84 | 85 | ## Issues 86 | 87 | See https://github.com/tbolis/react-back2top/issues 88 | 89 | ## Changelog 90 | 91 | See https://github.com/tbolis/react-back2top/blob/master/CHANGELOG.md 92 | 93 | ## License 94 | 95 | MIT, do remember to add a reference if you find it useful :) 96 | 97 | [github-image]: https://img.shields.io/github/release/tbolis/react-back2top.svg 98 | [github-url]: https://github.com/tbolis/react-back2top/releases 99 | [npm-image]: https://img.shields.io/npm/v/react-back2top.svg?style=flat 100 | [npm-url]: https://www.npmjs.com/package/react-back2top 101 | [downloads-image]: https://img.shields.io/npm/dm/react-back2top.svg?style=flat 102 | [downloads-url]: https://www.npmjs.com/package/react-back2top 103 | [travis-image]: https://img.shields.io/travis/tbolis/react-back2top.svg?style=flat 104 | [travis-url]: https://travis-ci.org/tbolis/react-back2top 105 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | /* eslint no-unused-vars:0 */ 2 | 3 | 'use strict'; 4 | 5 | import React, {Component} from 'react'; 6 | import PropTypes from 'prop-types'; 7 | import now from 'performance-now'; 8 | import Easing from 'easing-js'; 9 | import raf from 'raf'; 10 | import _ from 'lodash'; 11 | 12 | const privates = new WeakMap(); 13 | 14 | export const isNumber = (obj) => { 15 | return typeof obj === 'number' && !Number.isNaN(obj); 16 | }; 17 | 18 | export const strip = (number) => { 19 | return parseFloat(number.toPrecision(12)); 20 | }; 21 | 22 | export const isAnimating = (animations) => { 23 | for (var [, animation] of animations) { 24 | if (animation.isAnimating) return true; 25 | } 26 | return false; 27 | }; 28 | 29 | const scheduleAnimation = (context) => { 30 | raf(() => { 31 | var animations = privates.get(context); 32 | var currentTime = now(); 33 | var shouldUpdate = false; 34 | animations && animations.forEach(function (animation, name) { 35 | var isFunction = typeof name === 'function'; 36 | if (!animation.isAnimating) return; 37 | var {duration, easing, endValue, startTime, startValue} = animation; 38 | var deltaTime = currentTime - startTime; 39 | if (deltaTime >= duration) { 40 | Object.assign(animation, {isAnimating: false, startTime: currentTime, value: endValue}); 41 | } else { 42 | animation.value = strip(Easing[easing](deltaTime, startValue, endValue - startValue, duration)); 43 | } 44 | shouldUpdate = shouldUpdate || !isFunction; 45 | if (isFunction) name(animation.value); 46 | }); 47 | if (animations && isAnimating(animations)) scheduleAnimation(context); 48 | if (shouldUpdate) context.forceUpdate(); 49 | }); 50 | }; 51 | 52 | class Back2Top extends Component { 53 | 54 | static propTypes = { 55 | 56 | // Make the button visible 57 | alwaysVisible: PropTypes.bool, 58 | 59 | // Duration of fade effect 60 | fadeDuration: PropTypes.number, 61 | 62 | // Duration of scroll-to-top effect 63 | scrollDuration: PropTypes.number, 64 | 65 | // Height of button to become visible 66 | visibilityHeight: PropTypes.number 67 | 68 | }; 69 | 70 | static FADE_DURATION = 300; 71 | static SCROLL_DURATION = 800; 72 | static VISIBILITY_HEIGHT = 400; 73 | 74 | constructor(props) { 75 | super(props); 76 | 77 | this.animate = this.animate.bind(this); 78 | this.scrollToTop = this.scrollToTop.bind(this); 79 | this.updateScroll = this.updateScroll.bind(this); 80 | this.shouldAnimate = this.shouldAnimate.bind(this); 81 | this.animate = this.animate.bind(this); 82 | this.scrollToTop = this.scrollToTop.bind(this); 83 | this.getScrollTop = this.getScrollTop.bind(this); 84 | this.setScrollTop = this.setScrollTop.bind(this); 85 | 86 | this.state = { 87 | visible: false 88 | }; 89 | } 90 | 91 | componentDidMount() { 92 | this.throttledUpdateScroll = _.throttle(this.updateScroll, 100); 93 | window.addEventListener('scroll', this.throttledUpdateScroll); 94 | } 95 | 96 | componentWillUnmount() { 97 | privates.delete(this); 98 | window.removeEventListener('scroll', this.throttledUpdateScroll); 99 | } 100 | 101 | shouldAnimate() { 102 | return true; 103 | } 104 | 105 | animate(name, endValue, duration, options = {}) { 106 | var animations = privates.get(this); 107 | if (!animations) { 108 | privates.set(this, animations = new Map()); 109 | } 110 | var animation = animations.get(name); 111 | var shouldAnimate = this.shouldAnimate() && options.animation !== false; 112 | if (!animation || !shouldAnimate || !isNumber(endValue)) { 113 | let easing = options.easing || 'linear'; 114 | let startValue = isNumber(options.startValue) && shouldAnimate ? options.startValue : endValue; 115 | animation = {duration, easing, endValue, isAnimating: false, startValue, value: startValue}; 116 | animations.set(name, animation); 117 | } 118 | if (!duration) { 119 | Object.assign(animation, {endValue, value: endValue}); 120 | animations.set(name, animation); 121 | } 122 | if (animation.value !== endValue && !animation.isAnimating) { 123 | if (!isAnimating(animations)) scheduleAnimation(this); 124 | var startTime = 'startTime' in options ? options.startTime : now(); 125 | duration = duration || animation.duration; 126 | let easing = options.easing || animation.easing; 127 | let startValue = animation.value; 128 | Object.assign(animation, {isAnimating: true, endValue, startValue, startTime, duration, easing}); 129 | } 130 | return animation.value; 131 | } 132 | 133 | updateScroll() { 134 | let {visibilityHeight} = this.props; 135 | this.setState({visible: this.getScrollTop() > (visibilityHeight || Back2Top.VISIBILITY_HEIGHT)}); 136 | } 137 | 138 | scrollToTop(e) { 139 | if (e) e.preventDefault(); 140 | let {scrollDuration,onClick} = this.props; 141 | this.animate(value => this.setScrollTop(value), 0, 142 | scrollDuration || Back2Top.SCROLL_DURATION, {startValue: this.getScrollTop()}); 143 | if (onClick) { 144 | onClick(e); 145 | } 146 | } 147 | 148 | getScrollTop() { 149 | return document.documentElement.scrollTop; 150 | } 151 | 152 | setScrollTop(value) { 153 | document.body.scrollTop = value; 154 | document.documentElement.scrollTop = value; 155 | } 156 | 157 | render() { 158 | var visible = this.props.alwaysVisible || this.state.visible; 159 | let {href, 160 | style, 161 | target, 162 | onClick, 163 | className, 164 | fadeDuration, 165 | visibilityHeight, 166 | scrollDuration, 167 | children, 168 | ...options 169 | } = this.props; 170 | let opacity = this.animate('opacity', visible ? 1 : 0, fadeDuration || Back2Top.FADE_DURATION); 171 | if (opacity === 0) return false; 172 | return ( 173 | 179 | {children} 180 | 181 | ); 182 | } 183 | } 184 | 185 | Back2Top.prototype.displayName = 'Back2Top'; 186 | 187 | export default Back2Top; -------------------------------------------------------------------------------- /examples/main.jsx: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | 3 | import React, {Component} from 'react'; 4 | 5 | import Back2Top from '../src/main'; 6 | import {FloatingActionButton} from 'material-ui'; 7 | 8 | import getMuiTheme from 'material-ui/styles/getMuiTheme'; 9 | import UpIcon from 'material-ui/svg-icons/navigation/arrow-upward'; 10 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 11 | 12 | import './styles.css'; 13 | 14 | class Demo extends Component { 15 | constructor(props) { 16 | super(props); 17 | } 18 | 19 | render() { 20 | return ( 21 | 22 |
23 | 24 |

25 | Scroll down for the button to appear 26 |

27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |

35 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis consectetur turpis in arcu 36 | consectetur, a mollis erat rhoncus. Suspendisse quam turpis, cursus et sapien dignissim, ornare 37 | suscipit lectus. Ut elementum felis ac magna fringilla, a semper lacus commodo. Vivamus et 38 | vehicula 39 | orci. Pellentesque porta tincidunt arcu, a consectetur risus maximus in. Aliquam at justo 40 | molestie, 41 | mattis nibh in, varius neque. Quisque ac tellus egestas, malesuada tortor ut, luctus dolor. Sed 42 | facilisis mauris quis fringilla pellentesque. Curabitur ullamcorper ut quam vel commodo. In 43 | tincidunt placerat tempus. Morbi nisi ligula, tristique in lorem quis, blandit iaculis libero. 44 | Duis 45 | sodales, purus eget pretium suscipit, massa lorem lobortis augue, in porta sem felis at lacus. 46 | Praesent ut condimentum ex. 47 |

48 | 49 |

50 | Sed fringilla est tempus, ornare risus non, lobortis quam. Aliquam scelerisque dignissim 51 | hendrerit. 52 | Fusce sem tortor, vestibulum ac luctus a, pulvinar feugiat eros. Suspendisse viverra orci vel 53 | odio 54 | facilisis, laoreet vulputate diam lacinia. Curabitur nulla odio, condimentum a dapibus ac, 55 | venenatis 56 | a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos 57 | himenaeos. 58 | Cras sapien felis, sagittis in vehicula sit amet, maximus nec ex. Vivamus id velit eu tortor 59 | lobortis imperdiet. Morbi efficitur congue sem. Pellentesque vitae tortor at lectus pharetra 60 | vulputate. Nulla posuere leo vel massa consectetur, sit amet volutpat diam euismod. Phasellus ut 61 | enim viverra libero viverra dictum. 62 |

63 | 64 |

65 | Integer sapien velit, laoreet laoreet magna eget, tincidunt rutrum turpis. Curabitur eu lorem 66 | vestibulum dolor feugiat feugiat et congue metus. Quisque vehicula posuere libero. Curabitur a 67 | suscipit erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget pulvinar odio. 68 | Curabitur in magna nec est ultricies varius. Ut euismod suscipit condimentum. Nunc sit amet 69 | risus 70 | tortor. Vivamus pretium, odio ut volutpat tempor, metus mi facilisis metus, ac pretium nunc nibh 71 | id 72 | mi. Suspendisse consectetur erat id elit ullamcorper tristique. 73 |

74 | 75 |

76 | Suspendisse porttitor porta metus quis congue. Morbi in venenatis nunc, vitae lacinia leo. Fusce 77 | vulputate tincidunt urna vel egestas. Sed sit amet est sit amet lectus rutrum elementum non eu 78 | ipsum. Quisque vulputate, ligula nec tincidunt maximus, massa lorem mattis purus, hendrerit 79 | egestas 80 | augue mi ac odio. Donec finibus dui ac arcu accumsan, a bibendum mi porttitor. Fusce odio eros, 81 | egestas quis urna ut, imperdiet maximus ligula. Fusce nisi turpis, rutrum et cursus et, 82 | porttitor 83 | non lectus. Sed tempor risus non ultricies dapibus. Suspendisse potenti. Cum sociis natoque 84 | penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer vestibulum urna sit 85 | amet 86 | auctor vestibulum. Aenean quam augue, accumsan a imperdiet vitae, porttitor sed sem. 87 |

88 | 89 |

90 | Suspendisse posuere finibus neque, quis efficitur est facilisis in. Sed hendrerit tellus massa, 91 | eget 92 | pulvinar neque efficitur ac. Mauris nibh est, venenatis non sollicitudin in, fermentum et ipsum. 93 | Quisque massa libero, rhoncus nec lobortis et, semper sit amet lacus. Donec suscipit interdum 94 | varius. Maecenas dui metus, gravida sed libero quis, suscipit blandit magna. Suspendisse 95 | faucibus 96 | enim non massa consectetur, fermentum suscipit risus venenatis. Ut suscipit hendrerit sem, eu 97 | semper 98 | quam gravida id. Curabitur elementum felis ac lorem elementum porttitor vitae vel metus. Morbi 99 | in 100 | facilisis purus, sed ornare felis. Nam eros nisi, vestibulum nec luctus gravida, molestie in 101 | erat. 102 | Proin ac orci consequat, elementum tortor sed, fringilla nisl. Sed nec eros sit amet lacus 103 | rutrum 104 | posuere eu quis leo. Aliquam erat volutpat. Maecenas tempus massa at viverra vulputate. Etiam 105 | vitae 106 | iaculis lectus. 107 |

108 | 109 |

110 | Etiam non mattis nisi, at molestie velit. Curabitur ut est lectus. Ut lobortis est aliquam porta 111 | vulputate. Nunc porttitor nulla augue, eget feugiat leo convallis sed. Nullam in semper leo. 112 | Nunc ac 113 | cursus lacus. Praesent feugiat ex sed sapien sodales blandit. Morbi mollis massa dignissim augue 114 | molestie, quis vulputate risus hendrerit. Aliquam porttitor nulla dui, vel ultrices libero 115 | convallis 116 | sed. Curabitur dapibus, neque vel aliquet scelerisque, libero ligula vestibulum ligula, vel 117 | pellentesque tortor risus ut augue. Phasellus viverra ullamcorper nulla quis molestie. 118 |

119 | 120 |

121 | Suspendisse potenti. Ut consectetur, sem ac laoreet rutrum, sem ipsum egestas metus, vel feugiat 122 | justo turpis non dolor. Vestibulum eros erat, rhoncus in ligula a, vulputate pretium ante. Morbi 123 | ut 124 | mauris ex. Aenean erat tortor, hendrerit vitae pulvinar eget, gravida vitae nisi. Fusce placerat 125 | sit 126 | amet neque eu pharetra. Quisque lacinia dignissim ligula in pulvinar. Nulla non sapien congue 127 | ipsum 128 | tempus euismod. Nulla finibus nisl a metus commodo blandit. Praesent orci massa, convallis a 129 | vehicula a, euismod et nunc. 130 |

131 | 132 |

133 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis consectetur turpis in arcu 134 | consectetur, a mollis erat rhoncus. Suspendisse quam turpis, cursus et sapien dignissim, ornare 135 | suscipit lectus. Ut elementum felis ac magna fringilla, a semper lacus commodo. Vivamus et 136 | vehicula 137 | orci. Pellentesque porta tincidunt arcu, a consectetur risus maximus in. Aliquam at justo 138 | molestie, 139 | mattis nibh in, varius neque. Quisque ac tellus egestas, malesuada tortor ut, luctus dolor. Sed 140 | facilisis mauris quis fringilla pellentesque. Curabitur ullamcorper ut quam vel commodo. In 141 | tincidunt placerat tempus. Morbi nisi ligula, tristique in lorem quis, blandit iaculis libero. 142 | Duis 143 | sodales, purus eget pretium suscipit, massa lorem lobortis augue, in porta sem felis at lacus. 144 | Praesent ut condimentum ex. 145 |

146 | 147 |

148 | Sed fringilla est tempus, ornare risus non, lobortis quam. Aliquam scelerisque dignissim 149 | hendrerit. 150 | Fusce sem tortor, vestibulum ac luctus a, pulvinar feugiat eros. Suspendisse viverra orci vel 151 | odio 152 | facilisis, laoreet vulputate diam lacinia. Curabitur nulla odio, condimentum a dapibus ac, 153 | venenatis 154 | a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos 155 | himenaeos. 156 | Cras sapien felis, sagittis in vehicula sit amet, maximus nec ex. Vivamus id velit eu tortor 157 | lobortis imperdiet. Morbi efficitur congue sem. Pellentesque vitae tortor at lectus pharetra 158 | vulputate. Nulla posuere leo vel massa consectetur, sit amet volutpat diam euismod. Phasellus ut 159 | enim viverra libero viverra dictum. 160 |

161 | 162 |

163 | Integer sapien velit, laoreet laoreet magna eget, tincidunt rutrum turpis. Curabitur eu lorem 164 | vestibulum dolor feugiat feugiat et congue metus. Quisque vehicula posuere libero. Curabitur a 165 | suscipit erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget pulvinar odio. 166 | Curabitur in magna nec est ultricies varius. Ut euismod suscipit condimentum. Nunc sit amet 167 | risus 168 | tortor. Vivamus pretium, odio ut volutpat tempor, metus mi facilisis metus, ac pretium nunc nibh 169 | id 170 | mi. Suspendisse consectetur erat id elit ullamcorper tristique. 171 |

172 | 173 |

174 | Suspendisse porttitor porta metus quis congue. Morbi in venenatis nunc, vitae lacinia leo. Fusce 175 | vulputate tincidunt urna vel egestas. Sed sit amet est sit amet lectus rutrum elementum non eu 176 | ipsum. Quisque vulputate, ligula nec tincidunt maximus, massa lorem mattis purus, hendrerit 177 | egestas 178 | augue mi ac odio. Donec finibus dui ac arcu accumsan, a bibendum mi porttitor. Fusce odio eros, 179 | egestas quis urna ut, imperdiet maximus ligula. Fusce nisi turpis, rutrum et cursus et, 180 | porttitor 181 | non lectus. Sed tempor risus non ultricies dapibus. Suspendisse potenti. Cum sociis natoque 182 | penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer vestibulum urna sit 183 | amet 184 | auctor vestibulum. Aenean quam augue, accumsan a imperdiet vitae, porttitor sed sem. 185 |

186 | 187 |

188 | Suspendisse posuere finibus neque, quis efficitur est facilisis in. Sed hendrerit tellus massa, 189 | eget 190 | pulvinar neque efficitur ac. Mauris nibh est, venenatis non sollicitudin in, fermentum et ipsum. 191 | Quisque massa libero, rhoncus nec lobortis et, semper sit amet lacus. Donec suscipit interdum 192 | varius. Maecenas dui metus, gravida sed libero quis, suscipit blandit magna. Suspendisse 193 | faucibus 194 | enim non massa consectetur, fermentum suscipit risus venenatis. Ut suscipit hendrerit sem, eu 195 | semper 196 | quam gravida id. Curabitur elementum felis ac lorem elementum porttitor vitae vel metus. Morbi 197 | in 198 | facilisis purus, sed ornare felis. Nam eros nisi, vestibulum nec luctus gravida, molestie in 199 | erat. 200 | Proin ac orci consequat, elementum tortor sed, fringilla nisl. Sed nec eros sit amet lacus 201 | rutrum 202 | posuere eu quis leo. Aliquam erat volutpat. Maecenas tempus massa at viverra vulputate. Etiam 203 | vitae 204 | iaculis lectus. 205 |

206 | 207 |

208 | Etiam non mattis nisi, at molestie velit. Curabitur ut est lectus. Ut lobortis est aliquam porta 209 | vulputate. Nunc porttitor nulla augue, eget feugiat leo convallis sed. Nullam in semper leo. 210 | Nunc ac 211 | cursus lacus. Praesent feugiat ex sed sapien sodales blandit. Morbi mollis massa dignissim augue 212 | molestie, quis vulputate risus hendrerit. Aliquam porttitor nulla dui, vel ultrices libero 213 | convallis 214 | sed. Curabitur dapibus, neque vel aliquet scelerisque, libero ligula vestibulum ligula, vel 215 | pellentesque tortor risus ut augue. Phasellus viverra ullamcorper nulla quis molestie. 216 |

217 | 218 |

219 | Suspendisse potenti. Ut consectetur, sem ac laoreet rutrum, sem ipsum egestas metus, vel feugiat 220 | justo turpis non dolor. Vestibulum eros erat, rhoncus in ligula a, vulputate pretium ante. Morbi 221 | ut 222 | mauris ex. Aenean erat tortor, hendrerit vitae pulvinar eget, gravida vitae nisi. Fusce placerat 223 | sit 224 | amet neque eu pharetra. Quisque lacinia dignissim ligula in pulvinar. Nulla non sapien congue 225 | ipsum 226 | tempus euismod. Nulla finibus nisl a metus commodo blandit. Praesent orci massa, convallis a 227 | vehicula a, euismod et nunc. 228 |

229 | 230 |

231 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis consectetur turpis in arcu 232 | consectetur, a mollis erat rhoncus. Suspendisse quam turpis, cursus et sapien dignissim, ornare 233 | suscipit lectus. Ut elementum felis ac magna fringilla, a semper lacus commodo. Vivamus et 234 | vehicula 235 | orci. Pellentesque porta tincidunt arcu, a consectetur risus maximus in. Aliquam at justo 236 | molestie, 237 | mattis nibh in, varius neque. Quisque ac tellus egestas, malesuada tortor ut, luctus dolor. Sed 238 | facilisis mauris quis fringilla pellentesque. Curabitur ullamcorper ut quam vel commodo. In 239 | tincidunt placerat tempus. Morbi nisi ligula, tristique in lorem quis, blandit iaculis libero. 240 | Duis 241 | sodales, purus eget pretium suscipit, massa lorem lobortis augue, in porta sem felis at lacus. 242 | Praesent ut condimentum ex. 243 |

244 | 245 |

246 | Sed fringilla est tempus, ornare risus non, lobortis quam. Aliquam scelerisque dignissim 247 | hendrerit. 248 | Fusce sem tortor, vestibulum ac luctus a, pulvinar feugiat eros. Suspendisse viverra orci vel 249 | odio 250 | facilisis, laoreet vulputate diam lacinia. Curabitur nulla odio, condimentum a dapibus ac, 251 | venenatis 252 | a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos 253 | himenaeos. 254 | Cras sapien felis, sagittis in vehicula sit amet, maximus nec ex. Vivamus id velit eu tortor 255 | lobortis imperdiet. Morbi efficitur congue sem. Pellentesque vitae tortor at lectus pharetra 256 | vulputate. Nulla posuere leo vel massa consectetur, sit amet volutpat diam euismod. Phasellus ut 257 | enim viverra libero viverra dictum. 258 |

259 | 260 |

261 | Integer sapien velit, laoreet laoreet magna eget, tincidunt rutrum turpis. Curabitur eu lorem 262 | vestibulum dolor feugiat feugiat et congue metus. Quisque vehicula posuere libero. Curabitur a 263 | suscipit erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget pulvinar odio. 264 | Curabitur in magna nec est ultricies varius. Ut euismod suscipit condimentum. Nunc sit amet 265 | risus 266 | tortor. Vivamus pretium, odio ut volutpat tempor, metus mi facilisis metus, ac pretium nunc nibh 267 | id 268 | mi. Suspendisse consectetur erat id elit ullamcorper tristique. 269 |

270 | 271 |

272 | Suspendisse porttitor porta metus quis congue. Morbi in venenatis nunc, vitae lacinia leo. Fusce 273 | vulputate tincidunt urna vel egestas. Sed sit amet est sit amet lectus rutrum elementum non eu 274 | ipsum. Quisque vulputate, ligula nec tincidunt maximus, massa lorem mattis purus, hendrerit 275 | egestas 276 | augue mi ac odio. Donec finibus dui ac arcu accumsan, a bibendum mi porttitor. Fusce odio eros, 277 | egestas quis urna ut, imperdiet maximus ligula. Fusce nisi turpis, rutrum et cursus et, 278 | porttitor 279 | non lectus. Sed tempor risus non ultricies dapibus. Suspendisse potenti. Cum sociis natoque 280 | penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer vestibulum urna sit 281 | amet 282 | auctor vestibulum. Aenean quam augue, accumsan a imperdiet vitae, porttitor sed sem. 283 |

284 | 285 |

286 | Suspendisse posuere finibus neque, quis efficitur est facilisis in. Sed hendrerit tellus massa, 287 | eget 288 | pulvinar neque efficitur ac. Mauris nibh est, venenatis non sollicitudin in, fermentum et ipsum. 289 | Quisque massa libero, rhoncus nec lobortis et, semper sit amet lacus. Donec suscipit interdum 290 | varius. Maecenas dui metus, gravida sed libero quis, suscipit blandit magna. Suspendisse 291 | faucibus 292 | enim non massa consectetur, fermentum suscipit risus venenatis. Ut suscipit hendrerit sem, eu 293 | semper 294 | quam gravida id. Curabitur elementum felis ac lorem elementum porttitor vitae vel metus. Morbi 295 | in 296 | facilisis purus, sed ornare felis. Nam eros nisi, vestibulum nec luctus gravida, molestie in 297 | erat. 298 | Proin ac orci consequat, elementum tortor sed, fringilla nisl. Sed nec eros sit amet lacus 299 | rutrum 300 | posuere eu quis leo. Aliquam erat volutpat. Maecenas tempus massa at viverra vulputate. Etiam 301 | vitae 302 | iaculis lectus. 303 |

304 | 305 |

306 | Etiam non mattis nisi, at molestie velit. Curabitur ut est lectus. Ut lobortis est aliquam porta 307 | vulputate. Nunc porttitor nulla augue, eget feugiat leo convallis sed. Nullam in semper leo. 308 | Nunc ac 309 | cursus lacus. Praesent feugiat ex sed sapien sodales blandit. Morbi mollis massa dignissim augue 310 | molestie, quis vulputate risus hendrerit. Aliquam porttitor nulla dui, vel ultrices libero 311 | convallis 312 | sed. Curabitur dapibus, neque vel aliquet scelerisque, libero ligula vestibulum ligula, vel 313 | pellentesque tortor risus ut augue. Phasellus viverra ullamcorper nulla quis molestie. 314 |

315 | 316 |

317 | Suspendisse potenti. Ut consectetur, sem ac laoreet rutrum, sem ipsum egestas metus, vel feugiat 318 | justo turpis non dolor. Vestibulum eros erat, rhoncus in ligula a, vulputate pretium ante. Morbi 319 | ut 320 | mauris ex. Aenean erat tortor, hendrerit vitae pulvinar eget, gravida vitae nisi. Fusce placerat 321 | sit 322 | amet neque eu pharetra. Quisque lacinia dignissim ligula in pulvinar. Nulla non sapien congue 323 | ipsum 324 | tempus euismod. Nulla finibus nisl a metus commodo blandit. Praesent orci massa, convallis a 325 | vehicula a, euismod et nunc. 326 |

327 |

328 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis consectetur turpis in arcu 329 | consectetur, a mollis erat rhoncus. Suspendisse quam turpis, cursus et sapien dignissim, ornare 330 | suscipit lectus. Ut elementum felis ac magna fringilla, a semper lacus commodo. Vivamus et 331 | vehicula 332 | orci. Pellentesque porta tincidunt arcu, a consectetur risus maximus in. Aliquam at justo 333 | molestie, 334 | mattis nibh in, varius neque. Quisque ac tellus egestas, malesuada tortor ut, luctus dolor. Sed 335 | facilisis mauris quis fringilla pellentesque. Curabitur ullamcorper ut quam vel commodo. In 336 | tincidunt placerat tempus. Morbi nisi ligula, tristique in lorem quis, blandit iaculis libero. 337 | Duis 338 | sodales, purus eget pretium suscipit, massa lorem lobortis augue, in porta sem felis at lacus. 339 | Praesent ut condimentum ex. 340 |

341 | 342 |

343 | Sed fringilla est tempus, ornare risus non, lobortis quam. Aliquam scelerisque dignissim 344 | hendrerit. 345 | Fusce sem tortor, vestibulum ac luctus a, pulvinar feugiat eros. Suspendisse viverra orci vel 346 | odio 347 | facilisis, laoreet vulputate diam lacinia. Curabitur nulla odio, condimentum a dapibus ac, 348 | venenatis 349 | a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos 350 | himenaeos. 351 | Cras sapien felis, sagittis in vehicula sit amet, maximus nec ex. Vivamus id velit eu tortor 352 | lobortis imperdiet. Morbi efficitur congue sem. Pellentesque vitae tortor at lectus pharetra 353 | vulputate. Nulla posuere leo vel massa consectetur, sit amet volutpat diam euismod. Phasellus ut 354 | enim viverra libero viverra dictum. 355 |

356 | 357 |

358 | Integer sapien velit, laoreet laoreet magna eget, tincidunt rutrum turpis. Curabitur eu lorem 359 | vestibulum dolor feugiat feugiat et congue metus. Quisque vehicula posuere libero. Curabitur a 360 | suscipit erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget pulvinar odio. 361 | Curabitur in magna nec est ultricies varius. Ut euismod suscipit condimentum. Nunc sit amet 362 | risus 363 | tortor. Vivamus pretium, odio ut volutpat tempor, metus mi facilisis metus, ac pretium nunc nibh 364 | id 365 | mi. Suspendisse consectetur erat id elit ullamcorper tristique. 366 |

367 | 368 |

369 | Suspendisse porttitor porta metus quis congue. Morbi in venenatis nunc, vitae lacinia leo. Fusce 370 | vulputate tincidunt urna vel egestas. Sed sit amet est sit amet lectus rutrum elementum non eu 371 | ipsum. Quisque vulputate, ligula nec tincidunt maximus, massa lorem mattis purus, hendrerit 372 | egestas 373 | augue mi ac odio. Donec finibus dui ac arcu accumsan, a bibendum mi porttitor. Fusce odio eros, 374 | egestas quis urna ut, imperdiet maximus ligula. Fusce nisi turpis, rutrum et cursus et, 375 | porttitor 376 | non lectus. Sed tempor risus non ultricies dapibus. Suspendisse potenti. Cum sociis natoque 377 | penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer vestibulum urna sit 378 | amet 379 | auctor vestibulum. Aenean quam augue, accumsan a imperdiet vitae, porttitor sed sem. 380 |

381 | 382 |

383 | Suspendisse posuere finibus neque, quis efficitur est facilisis in. Sed hendrerit tellus massa, 384 | eget 385 | pulvinar neque efficitur ac. Mauris nibh est, venenatis non sollicitudin in, fermentum et ipsum. 386 | Quisque massa libero, rhoncus nec lobortis et, semper sit amet lacus. Donec suscipit interdum 387 | varius. Maecenas dui metus, gravida sed libero quis, suscipit blandit magna. Suspendisse 388 | faucibus 389 | enim non massa consectetur, fermentum suscipit risus venenatis. Ut suscipit hendrerit sem, eu 390 | semper 391 | quam gravida id. Curabitur elementum felis ac lorem elementum porttitor vitae vel metus. Morbi 392 | in 393 | facilisis purus, sed ornare felis. Nam eros nisi, vestibulum nec luctus gravida, molestie in 394 | erat. 395 | Proin ac orci consequat, elementum tortor sed, fringilla nisl. Sed nec eros sit amet lacus 396 | rutrum 397 | posuere eu quis leo. Aliquam erat volutpat. Maecenas tempus massa at viverra vulputate. Etiam 398 | vitae 399 | iaculis lectus. 400 |

401 | 402 |

403 | Etiam non mattis nisi, at molestie velit. Curabitur ut est lectus. Ut lobortis est aliquam porta 404 | vulputate. Nunc porttitor nulla augue, eget feugiat leo convallis sed. Nullam in semper leo. 405 | Nunc ac 406 | cursus lacus. Praesent feugiat ex sed sapien sodales blandit. Morbi mollis massa dignissim augue 407 | molestie, quis vulputate risus hendrerit. Aliquam porttitor nulla dui, vel ultrices libero 408 | convallis 409 | sed. Curabitur dapibus, neque vel aliquet scelerisque, libero ligula vestibulum ligula, vel 410 | pellentesque tortor risus ut augue. Phasellus viverra ullamcorper nulla quis molestie. 411 |

412 | 413 |

414 | Suspendisse potenti. Ut consectetur, sem ac laoreet rutrum, sem ipsum egestas metus, vel feugiat 415 | justo turpis non dolor. Vestibulum eros erat, rhoncus in ligula a, vulputate pretium ante. Morbi 416 | ut 417 | mauris ex. Aenean erat tortor, hendrerit vitae pulvinar eget, gravida vitae nisi. Fusce placerat 418 | sit 419 | amet neque eu pharetra. Quisque lacinia dignissim ligula in pulvinar. Nulla non sapien congue 420 | ipsum 421 | tempus euismod. Nulla finibus nisl a metus commodo blandit. Praesent orci massa, convallis a 422 | vehicula a, euismod et nunc. 423 |

424 | 425 |

426 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis consectetur turpis in arcu 427 | consectetur, a mollis erat rhoncus. Suspendisse quam turpis, cursus et sapien dignissim, ornare 428 | suscipit lectus. Ut elementum felis ac magna fringilla, a semper lacus commodo. Vivamus et 429 | vehicula 430 | orci. Pellentesque porta tincidunt arcu, a consectetur risus maximus in. Aliquam at justo 431 | molestie, 432 | mattis nibh in, varius neque. Quisque ac tellus egestas, malesuada tortor ut, luctus dolor. Sed 433 | facilisis mauris quis fringilla pellentesque. Curabitur ullamcorper ut quam vel commodo. In 434 | tincidunt placerat tempus. Morbi nisi ligula, tristique in lorem quis, blandit iaculis libero. 435 | Duis 436 | sodales, purus eget pretium suscipit, massa lorem lobortis augue, in porta sem felis at lacus. 437 | Praesent ut condimentum ex. 438 |

439 | 440 |

441 | Sed fringilla est tempus, ornare risus non, lobortis quam. Aliquam scelerisque dignissim 442 | hendrerit. 443 | Fusce sem tortor, vestibulum ac luctus a, pulvinar feugiat eros. Suspendisse viverra orci vel 444 | odio 445 | facilisis, laoreet vulputate diam lacinia. Curabitur nulla odio, condimentum a dapibus ac, 446 | venenatis 447 | a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos 448 | himenaeos. 449 | Cras sapien felis, sagittis in vehicula sit amet, maximus nec ex. Vivamus id velit eu tortor 450 | lobortis imperdiet. Morbi efficitur congue sem. Pellentesque vitae tortor at lectus pharetra 451 | vulputate. Nulla posuere leo vel massa consectetur, sit amet volutpat diam euismod. Phasellus ut 452 | enim viverra libero viverra dictum. 453 |

454 | 455 |

456 | Integer sapien velit, laoreet laoreet magna eget, tincidunt rutrum turpis. Curabitur eu lorem 457 | vestibulum dolor feugiat feugiat et congue metus. Quisque vehicula posuere libero. Curabitur a 458 | suscipit erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget pulvinar odio. 459 | Curabitur in magna nec est ultricies varius. Ut euismod suscipit condimentum. Nunc sit amet 460 | risus 461 | tortor. Vivamus pretium, odio ut volutpat tempor, metus mi facilisis metus, ac pretium nunc nibh 462 | id 463 | mi. Suspendisse consectetur erat id elit ullamcorper tristique. 464 |

465 | 466 |

467 | Suspendisse porttitor porta metus quis congue. Morbi in venenatis nunc, vitae lacinia leo. Fusce 468 | vulputate tincidunt urna vel egestas. Sed sit amet est sit amet lectus rutrum elementum non eu 469 | ipsum. Quisque vulputate, ligula nec tincidunt maximus, massa lorem mattis purus, hendrerit 470 | egestas 471 | augue mi ac odio. Donec finibus dui ac arcu accumsan, a bibendum mi porttitor. Fusce odio eros, 472 | egestas quis urna ut, imperdiet maximus ligula. Fusce nisi turpis, rutrum et cursus et, 473 | porttitor 474 | non lectus. Sed tempor risus non ultricies dapibus. Suspendisse potenti. Cum sociis natoque 475 | penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer vestibulum urna sit 476 | amet 477 | auctor vestibulum. Aenean quam augue, accumsan a imperdiet vitae, porttitor sed sem. 478 |

479 | 480 |

481 | Suspendisse posuere finibus neque, quis efficitur est facilisis in. Sed hendrerit tellus massa, 482 | eget 483 | pulvinar neque efficitur ac. Mauris nibh est, venenatis non sollicitudin in, fermentum et ipsum. 484 | Quisque massa libero, rhoncus nec lobortis et, semper sit amet lacus. Donec suscipit interdum 485 | varius. Maecenas dui metus, gravida sed libero quis, suscipit blandit magna. Suspendisse 486 | faucibus 487 | enim non massa consectetur, fermentum suscipit risus venenatis. Ut suscipit hendrerit sem, eu 488 | semper 489 | quam gravida id. Curabitur elementum felis ac lorem elementum porttitor vitae vel metus. Morbi 490 | in 491 | facilisis purus, sed ornare felis. Nam eros nisi, vestibulum nec luctus gravida, molestie in 492 | erat. 493 | Proin ac orci consequat, elementum tortor sed, fringilla nisl. Sed nec eros sit amet lacus 494 | rutrum 495 | posuere eu quis leo. Aliquam erat volutpat. Maecenas tempus massa at viverra vulputate. Etiam 496 | vitae 497 | iaculis lectus. 498 |

499 | 500 |

501 | Etiam non mattis nisi, at molestie velit. Curabitur ut est lectus. Ut lobortis est aliquam porta 502 | vulputate. Nunc porttitor nulla augue, eget feugiat leo convallis sed. Nullam in semper leo. 503 | Nunc ac 504 | cursus lacus. Praesent feugiat ex sed sapien sodales blandit. Morbi mollis massa dignissim augue 505 | molestie, quis vulputate risus hendrerit. Aliquam porttitor nulla dui, vel ultrices libero 506 | convallis 507 | sed. Curabitur dapibus, neque vel aliquet scelerisque, libero ligula vestibulum ligula, vel 508 | pellentesque tortor risus ut augue. Phasellus viverra ullamcorper nulla quis molestie. 509 |

510 | 511 |

512 | Suspendisse potenti. Ut consectetur, sem ac laoreet rutrum, sem ipsum egestas metus, vel feugiat 513 | justo turpis non dolor. Vestibulum eros erat, rhoncus in ligula a, vulputate pretium ante. Morbi 514 | ut 515 | mauris ex. Aenean erat tortor, hendrerit vitae pulvinar eget, gravida vitae nisi. Fusce placerat 516 | sit 517 | amet neque eu pharetra. Quisque lacinia dignissim ligula in pulvinar. Nulla non sapien congue 518 | ipsum 519 | tempus euismod. Nulla finibus nisl a metus commodo blandit. Praesent orci massa, convallis a 520 | vehicula a, euismod et nunc. 521 |

522 | 523 |

524 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis consectetur turpis in arcu 525 | consectetur, a mollis erat rhoncus. Suspendisse quam turpis, cursus et sapien dignissim, ornare 526 | suscipit lectus. Ut elementum felis ac magna fringilla, a semper lacus commodo. Vivamus et 527 | vehicula 528 | orci. Pellentesque porta tincidunt arcu, a consectetur risus maximus in. Aliquam at justo 529 | molestie, 530 | mattis nibh in, varius neque. Quisque ac tellus egestas, malesuada tortor ut, luctus dolor. Sed 531 | facilisis mauris quis fringilla pellentesque. Curabitur ullamcorper ut quam vel commodo. In 532 | tincidunt placerat tempus. Morbi nisi ligula, tristique in lorem quis, blandit iaculis libero. 533 | Duis 534 | sodales, purus eget pretium suscipit, massa lorem lobortis augue, in porta sem felis at lacus. 535 | Praesent ut condimentum ex. 536 |

537 | 538 |

539 | Sed fringilla est tempus, ornare risus non, lobortis quam. Aliquam scelerisque dignissim 540 | hendrerit. 541 | Fusce sem tortor, vestibulum ac luctus a, pulvinar feugiat eros. Suspendisse viverra orci vel 542 | odio 543 | facilisis, laoreet vulputate diam lacinia. Curabitur nulla odio, condimentum a dapibus ac, 544 | venenatis 545 | a odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos 546 | himenaeos. 547 | Cras sapien felis, sagittis in vehicula sit amet, maximus nec ex. Vivamus id velit eu tortor 548 | lobortis imperdiet. Morbi efficitur congue sem. Pellentesque vitae tortor at lectus pharetra 549 | vulputate. Nulla posuere leo vel massa consectetur, sit amet volutpat diam euismod. Phasellus ut 550 | enim viverra libero viverra dictum. 551 |

552 | 553 |

554 | Integer sapien velit, laoreet laoreet magna eget, tincidunt rutrum turpis. Curabitur eu lorem 555 | vestibulum dolor feugiat feugiat et congue metus. Quisque vehicula posuere libero. Curabitur a 556 | suscipit erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget pulvinar odio. 557 | Curabitur in magna nec est ultricies varius. Ut euismod suscipit condimentum. Nunc sit amet 558 | risus 559 | tortor. Vivamus pretium, odio ut volutpat tempor, metus mi facilisis metus, ac pretium nunc nibh 560 | id 561 | mi. Suspendisse consectetur erat id elit ullamcorper tristique. 562 |

563 | 564 |

565 | Suspendisse porttitor porta metus quis congue. Morbi in venenatis nunc, vitae lacinia leo. Fusce 566 | vulputate tincidunt urna vel egestas. Sed sit amet est sit amet lectus rutrum elementum non eu 567 | ipsum. Quisque vulputate, ligula nec tincidunt maximus, massa lorem mattis purus, hendrerit 568 | egestas 569 | augue mi ac odio. Donec finibus dui ac arcu accumsan, a bibendum mi porttitor. Fusce odio eros, 570 | egestas quis urna ut, imperdiet maximus ligula. Fusce nisi turpis, rutrum et cursus et, 571 | porttitor 572 | non lectus. Sed tempor risus non ultricies dapibus. Suspendisse potenti. Cum sociis natoque 573 | penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer vestibulum urna sit 574 | amet 575 | auctor vestibulum. Aenean quam augue, accumsan a imperdiet vitae, porttitor sed sem. 576 |

577 | 578 |

579 | Suspendisse posuere finibus neque, quis efficitur est facilisis in. Sed hendrerit tellus massa, 580 | eget 581 | pulvinar neque efficitur ac. Mauris nibh est, venenatis non sollicitudin in, fermentum et ipsum. 582 | Quisque massa libero, rhoncus nec lobortis et, semper sit amet lacus. Donec suscipit interdum 583 | varius. Maecenas dui metus, gravida sed libero quis, suscipit blandit magna. Suspendisse 584 | faucibus 585 | enim non massa consectetur, fermentum suscipit risus venenatis. Ut suscipit hendrerit sem, eu 586 | semper 587 | quam gravida id. Curabitur elementum felis ac lorem elementum porttitor vitae vel metus. Morbi 588 | in 589 | facilisis purus, sed ornare felis. Nam eros nisi, vestibulum nec luctus gravida, molestie in 590 | erat. 591 | Proin ac orci consequat, elementum tortor sed, fringilla nisl. Sed nec eros sit amet lacus 592 | rutrum 593 | posuere eu quis leo. Aliquam erat volutpat. Maecenas tempus massa at viverra vulputate. Etiam 594 | vitae 595 | iaculis lectus. 596 |

597 | 598 |

599 | Etiam non mattis nisi, at molestie velit. Curabitur ut est lectus. Ut lobortis est aliquam porta 600 | vulputate. Nunc porttitor nulla augue, eget feugiat leo convallis sed. Nullam in semper leo. 601 | Nunc ac 602 | cursus lacus. Praesent feugiat ex sed sapien sodales blandit. Morbi mollis massa dignissim augue 603 | molestie, quis vulputate risus hendrerit. Aliquam porttitor nulla dui, vel ultrices libero 604 | convallis 605 | sed. Curabitur dapibus, neque vel aliquet scelerisque, libero ligula vestibulum ligula, vel 606 | pellentesque tortor risus ut augue. Phasellus viverra ullamcorper nulla quis molestie. 607 |

608 | 609 |

610 | Suspendisse potenti. Ut consectetur, sem ac laoreet rutrum, sem ipsum egestas metus, vel feugiat 611 | justo turpis non dolor. Vestibulum eros erat, rhoncus in ligula a, vulputate pretium ante. Morbi 612 | ut 613 | mauris ex. Aenean erat tortor, hendrerit vitae pulvinar eget, gravida vitae nisi. Fusce placerat 614 | sit 615 | amet neque eu pharetra. Quisque lacinia dignissim ligula in pulvinar. Nulla non sapien congue 616 | ipsum 617 | tempus euismod. Nulla finibus nisl a metus commodo blandit. Praesent orci massa, convallis a 618 | vehicula a, euismod et nunc. 619 |

620 | 621 | 622 |
623 |
624 | ) 625 | } 626 | } 627 | 628 | export default Demo; --------------------------------------------------------------------------------