From 1fdc4e17f67de98978a8122a7aae404cdc80f4aa Mon Sep 17 00:00:00 2001 From: Alexander Bell Date: Mon, 4 Jun 2018 12:59:23 -0700 Subject: [PATCH] Initial commit --- README.md | 16 ++- package-lock.json | 51 +++++++++ package.json | 3 +- src/components/Menu.js | 232 +++++++++++++++++++++++++++++++++++++++++ src/index.js | 21 +--- src/styles/Menu.css | 78 ++++++++++++++ 6 files changed, 379 insertions(+), 22 deletions(-) create mode 100644 src/components/Menu.js create mode 100644 src/styles/Menu.css diff --git a/README.md b/README.md index 54908fe..b4e842b 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,25 @@ Never ever worry about a fancy dropdown menu. This component does it for you! # Usage +`import Menu from 'react-animated-menus'` + +Component usage: + +`` + +Replace `width` optionally width `height` but don't use both at the same time. +To keep the ratio between height and width one has to be given and the other one is calculated by the component. + +One example with height: + +`` + +`color` is optional. The defaul value is `rgb(255, 255, 255)` if it's not defined. # Contact **Github:** https://github.com/aleabodo -**Wesite:** https://alexbell.de +**Wesite:** https://alexbell.ninja **Email:** mail@alexbell.de diff --git a/package-lock.json b/package-lock.json index 51626ae..676faaf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3060,6 +3060,57 @@ "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", "dev": true }, + "css-loader": { + "version": "0.28.11", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.11.tgz", + "integrity": "sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "css-selector-tokenizer": "0.7.0", + "cssnano": "3.10.0", + "icss-utils": "2.1.0", + "loader-utils": "1.1.0", + "lodash.camelcase": "4.3.0", + "object-assign": "4.1.1", + "postcss": "5.2.18", + "postcss-modules-extract-imports": "1.2.0", + "postcss-modules-local-by-default": "1.2.0", + "postcss-modules-scope": "1.1.0", + "postcss-modules-values": "1.3.0", + "postcss-value-parser": "3.3.0", + "source-list-map": "2.0.0" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "1.1.3", + "js-base64": "2.4.5", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, "css-select": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", diff --git a/package.json b/package.json index d1c3cf6..092f5ee 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "./lib/index.js", "license": "MIT", "scripts": { - "build": "webpack" + "build": "webpack" }, "peerDependencies": { "prop-types": "^15.6.0", @@ -20,6 +20,7 @@ "babel-preset-env": "^1.6.1", "babel-preset-react": "^6.16.0", "babel-preset-stage-0": "^6.24.1", + "css-loader": "^0.28.11", "path": "^0.12.7", "prop-types": "^15.6.0", "react": "^16.0.0", diff --git a/src/components/Menu.js b/src/components/Menu.js new file mode 100644 index 0000000..7f7d9cd --- /dev/null +++ b/src/components/Menu.js @@ -0,0 +1,232 @@ +import React, { Component } from 'react'; +import anime from 'animejs' + +/* +* css +*/ +import '../styles/Menu.css' + + +class App extends Component { + constructor(props) { + super(props); + + /* + * Expected props: + * - width: Int in percentage + * - OR height: Int in percentage + * - color: String + */ + + this.state = { + id: this.getId(), + open: false + } + } + + + componentDidMount() { + //Event listener for click + document.addEventListener("click", (event) => { + const id = this.state.id; + const open = this.state.open; + + if(event.target.closest('#'+id) && !open) { + this.setState({ + open: true + }); + } + + if(!event.target.closest('#'+id) && open) { + this.setState({ + open: false + }); + } + }); + } + + + componentDidUpdate() { + const id = this.state.id; + + //Targets that will be triggered + var targetDots = document.querySelectorAll('#'+id+' .Menu_dot'); + var targetElement = document.querySelectorAll('#'+id+' .Menu_element'); + var targetElements = document.querySelector('#'+id+' .Menu_elements'); + var targetMenu = document.querySelector('#'+id+'.Menu'); + + + + if(this.state.open) { + var animation = anime.timeline(); + + //Display elements + targetElements.style.display = "block"; + + //Remove hover effect + targetMenu.classList.remove("Menu_closed"); + + animation + .add({ + targets: targetDots, + scaleX: 9, + scaleY: 10, + borderRadius: 0, + duration: 1300, + translateY: "40%", + backgroundColor: "rgb(255, 255, 255)", + easing: 'easeOutExpo' + }) + .add({ + targets: targetElement, + scaleX: [2,1], + opacity: 1, + duration: function(targetElements, i, l) { + return 500 + (i * 200); + }, + easing: 'easeInOutQuart', + offset: '-=1100' + }); + } else { + animation = anime.timeline(); + const color = this.getColor(); + + //Remove hover effect + targetMenu.classList.add("Menu_closed"); + + animation + .add({ + targets: targetElement, + scaleX: [1,2], + opacity: 0, + duration: function(targetElements, i, l) { + return 500 + (i * 200); + }, + easing: 'easeInOutQuart' + }) + .add({ + targets: targetDots, + scaleX: 1, + scaleY: 1, + borderRadius: "100%", + duration: 1300, + translateY: 0, + backgroundColor: color, + easing: 'easeOutExpo', + offset: '-=500' + }); + + //Remove menu after animation finished + animation.complete = function() { + targetElements.style.display = "none"; + }; + } + } + + + getId() { + var random = ""; + var possible = "abcdefghijklmnopqrstuvwxyz"; + + for (var i = 0; i < 5; i++) + random += possible.charAt(Math.floor(Math.random() * possible.length)); + + while(true) { + if(!document.getElementById(random)) { + return random; + } + } + } + + + getDimensions() { + //Input values + const inputWidth = this.props.width; + const inputHeight = this.props.height; + + if(!(inputWidth ||inputHeight)) { + console.log("Please define a height OR width!"); + } +console.log(inputWidth) + //Units and values seperated + if(inputWidth !== undefined) { + //Width + const unitWidth = inputWidth.replace(/[\d]+/g,""); + const valueWidth = parseFloat(inputWidth); + //Height + const unitHeight = unitWidth; + const valueHeight = valueWidth * 2.5; + + return { + width: String(valueWidth) + unitWidth, + height: String(valueHeight) + unitHeight + } + } + + //Height + const unitHeight = inputHeight.replace(/[\d]+/g,""); + const valueHeight = parseFloat(inputHeight); + //Width + const unitWidth = unitHeight; + const valueWidth = valueHeight / 2.5; + + return { + width: String(valueWidth) + unitWidth, + height: String(valueHeight) + unitHeight + } + } + + + getColor() { + return this.props.color ? this.props.color : "rgb(255, 255, 255)"; + } + + + render() { + const style = { + width: this.getDimensions().width, + height: this.getDimensions().height + }; + + console.log(style.height); + const styleDot = { + backgroundColor: this.getColor() + }; + + return ( +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+ Button +
+
+ Button +
+
+ Button +
+
+
+ ); + } +} + +export default App; diff --git a/src/index.js b/src/index.js index 5ec7cc3..b4a0b30 100644 --- a/src/index.js +++ b/src/index.js @@ -1,24 +1,5 @@ import React, { Component } from 'react'; - -class Menu extends Component { - constructor(props) { - super(props); - - /* - * Expected props: - * / - */ - this.currentImageIs_A = true; - } - - render() { - return ( -
- Hello -
- ); - } -} +import Menu from './components/Menu'; export default Menu; diff --git a/src/styles/Menu.css b/src/styles/Menu.css new file mode 100644 index 0000000..2253188 --- /dev/null +++ b/src/styles/Menu.css @@ -0,0 +1,78 @@ +.Menu { + position: relative; + background-color: transparent; + overflow: visible; + transition: opacity 0.5s; + border-radius: 20%; + cursor: pointer; +} + +.Menu_closed:hover { + opacity: 0.7; +} + +.Menu_dots { + position: absolute; + top: 0; + width: 100%; + height: 100%; + overflow: visible; +} + +.Menu_dotBox { + position: relative; + width: 100%; + height: 33.33%; + background-color: transparent; +} + +.Menu_dot { + position: absolute; + width: 70%; + height: 70%; + border-radius: 100%; + top: 15%; + left: 15%; + transition: opacity 0.4s; +} + +.Menu:hover .Menu_dot { + opacity: 1; +} + +.Menu_elements { + position: absolute; + top: -6.5%; + left: -265%; + width: 644%; + height: 306%; + background-color: transparent; + display: none; + overflow: visible; +} + +.Menu_element { + position: relative; + width: 100%; + height: 33.33%; + font-size: 0.8em; + text-align: center; + padding-top: 15%; + box-sizing: border-box; +} + +.Menu_button { + width: 100%; + background-color: white; + transition: background-color 0.5s, padding 0.5s; + opacity: 0; +} +.Menu_button:hover { + background-color: rgb(227, 227, 227); + padding-left: 5%; +} +.Menu_button:active { + transition: background-color 0.1s; + background-color: rgb(207, 207, 207); + padding-left: 5%; +}