standard-ui/components/dist/hamburger-menu.js
2022-09-04 17:37:45 +05:30

184 lines
4.6 KiB
JavaScript

const hamburgerMenu = document.createElement('template')
hamburgerMenu.innerHTML = `
<style>
*{
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
:host{
display: flex;
width: 100%;
height: 100%;
overflow-y: auto;
scrollbar-width: thin;
--padding: 0 0 3rem 0;
--backdrop-color: rgba(0,0,0,0.5);
}
.backdrop{
position: fixed;
}
.side-nav{
display: flex;
flex-direction: column;
width: 100%;
}
.hide{
display: none !important;
}
@media screen and (max-width: 640px){
:host{
position: fixed;
z-index: 10;
}
.side-nav{
height: 100%;
overflow-y: auto;
width: calc(100% - 4rem);
transition: transform 0.3s;
background-color: rgba(var(--background-color, (255, 255, 255)), 1);
box-shadow: 0.5rem 0 2rem rgba(0,0,0, 0.1);
z-index: 1;
}
.side-nav:not(.reveal){
transform: translateX(-100%);
}
.reveal{
transform: none;
}
.backdrop{
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: var(--backdrop-color);
-webkit-transition: opacity 0.3s;
-o-transition: opacity 0.3s;
transition: opacity 0.3s;
}
}
@media screen and (min-width: 640px){
.backdrop{
pointer-events: none;
}
}
@media (any-hover: hover){
::-webkit-scrollbar{
width: 0.5rem;
}
::-webkit-scrollbar-thumb{
border-radius: 1rem;
background: rgba(var(--text-color, (17,17,17)), 0.3);
&:hover{
background: rgba(var(--text-color, (17,17,17)), 0.5);
}
}
}
</style>
<section class="backdrop hide"></section>
<nav class="side-nav">
<slot></slot>
</nav>
`
class HamburgerMenu extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' }).append(hamburgerMenu.content.cloneNode(true))
this.resumeScrolling = this.resumeScrolling.bind(this)
this.open = this.open.bind(this)
this.close = this.close.bind(this)
this.sideNav = this.shadowRoot.querySelector('.side-nav')
this.backdrop = this.shadowRoot.querySelector('.backdrop')
this.isOpen = false
this.animeOptions = {
duration: 300,
easing: 'ease'
}
}
static get observedAttributes() {
return ['open'];
}
resumeScrolling() {
const scrollY = document.body.style.top;
window.scrollTo(0, parseInt(scrollY || '0') * -1);
setTimeout(() => {
document.body.style.overflow = 'auto';
document.body.style.top = 'initial'
}, 300);
}
open() {
if (this.isOpen) return
document.body.style.overflow = 'hidden';
document.body.style.top = `-${window.scrollY}px`
this.classList.remove('hide')
this.sideNav.classList.add('reveal')
this.backdrop.classList.remove('hide')
this.backdrop.animate([
{
opacity: 0
},
{
opacity: 1
},
],
this.animeOptions)
.onfinish = () => {
this.isOpen = true
this.setAttribute('open', '')
}
}
close() {
if (!this.isOpen) return
this.sideNav.classList.remove('reveal')
this.backdrop.animate([
{
opacity: 1
},
{
opacity: 0
},
],
this.animeOptions)
.onfinish = () => {
this.backdrop.classList.add('hide')
this.classList.add('hide')
this.isOpen = false
this.removeAttribute('open')
}
}
connectedCallback() {
this.backdrop.addEventListener('click', this.close)
const resizeObserver = new ResizeObserver(entries => {
if (window.innerWidth < 640 && this.isOpen) {
this.classList.remove('hide')
}
else {
this.classList.add('hide')
}
if (window.innerWidth > 640) {
this.classList.remove('hide')
}
});
resizeObserver.observe(this)
}
disconnectedCallback() {
this.backdrop.removeEventListener('click', this.close)
}
attributeChangedCallback(name, oldVal, newVal) {
if (name === 'open') {
if (this.hasAttribute('open')) {
this.open()
}
}
}
}
window.customElements.define('hamburger-menu', HamburgerMenu);