Initial commit
This commit is contained in:
parent
36f2c92c35
commit
1fdc4e17f6
16
README.md
16
README.md
@ -11,11 +11,25 @@ Never ever worry about a fancy dropdown menu. This component does it for you!
|
|||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
|
`import Menu from 'react-animated-menus'`
|
||||||
|
|
||||||
|
Component usage:
|
||||||
|
|
||||||
|
`<Menu width={"20px"} color="rgb(123, 192, 222)" />`
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
`<Menu height={"50px"}" />`
|
||||||
|
|
||||||
|
`color` is optional. The defaul value is `rgb(255, 255, 255)` if it's not defined.
|
||||||
|
|
||||||
# Contact
|
# Contact
|
||||||
|
|
||||||
**Github:** https://github.com/aleabodo
|
**Github:** https://github.com/aleabodo
|
||||||
|
|
||||||
**Wesite:** https://alexbell.de
|
**Wesite:** https://alexbell.ninja
|
||||||
|
|
||||||
**Email:** mail@alexbell.de
|
**Email:** mail@alexbell.de
|
||||||
|
51
package-lock.json
generated
51
package-lock.json
generated
@ -3060,6 +3060,57 @@
|
|||||||
"integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
|
"integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
|
||||||
"dev": true
|
"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": {
|
"css-select": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack"
|
"build": "webpack"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
@ -20,6 +20,7 @@
|
|||||||
"babel-preset-env": "^1.6.1",
|
"babel-preset-env": "^1.6.1",
|
||||||
"babel-preset-react": "^6.16.0",
|
"babel-preset-react": "^6.16.0",
|
||||||
"babel-preset-stage-0": "^6.24.1",
|
"babel-preset-stage-0": "^6.24.1",
|
||||||
|
"css-loader": "^0.28.11",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
"react": "^16.0.0",
|
"react": "^16.0.0",
|
||||||
|
232
src/components/Menu.js
Normal file
232
src/components/Menu.js
Normal file
@ -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 (
|
||||||
|
<div style={style} id={this.state.id} className="Menu Menu_closed">
|
||||||
|
<div className="Menu_dots">
|
||||||
|
<div className="Menu_dotBox">
|
||||||
|
<div style={styleDot} className="Menu_dot">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="Menu_dotBox">
|
||||||
|
<div style={styleDot} className="Menu_dot">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="Menu_dotBox">
|
||||||
|
<div style={styleDot} className="Menu_dot">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="Menu_elements">
|
||||||
|
<div className="Menu_button Menu_element">
|
||||||
|
Button
|
||||||
|
</div>
|
||||||
|
<div className="Menu_button Menu_element">
|
||||||
|
Button
|
||||||
|
</div>
|
||||||
|
<div className="Menu_button Menu_element">
|
||||||
|
Button
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
21
src/index.js
21
src/index.js
@ -1,24 +1,5 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import Menu from './components/Menu';
|
||||||
class Menu extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Expected props:
|
|
||||||
* /
|
|
||||||
*/
|
|
||||||
this.currentImageIs_A = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
Hello
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Menu;
|
export default Menu;
|
||||||
|
78
src/styles/Menu.css
Normal file
78
src/styles/Menu.css
Normal file
@ -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%;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user