Skip to content

Commit

Permalink
feat: drawer component (#191)
Browse files Browse the repository at this point in the history
* feat: drawer component

* fix: transition logic

* fix: mobile drawer

* chore: commitlint/cz-commitlint

* feat: swipe animation for mobile

* refactor: rip lil-x and lil-line, refactor improve code length

* fix: minor changes

* refactor: now emits change events

* fix: if the screen is bigger than drawer component

* fix: minor changes

* fix: color drawer__title

* fix: color name change

* feat: transition drawer

* fix: make compatible with new design

* fix: content will have scroll bar if necessary

* fix: prettier

* fix: revert changes on prettierrc
  • Loading branch information
RafaelLimaC authored May 7, 2024
1 parent df9e615 commit 2504b2e
Show file tree
Hide file tree
Showing 8 changed files with 1,761 additions and 1,455 deletions.
2,906 changes: 1,459 additions & 1,447 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/components/Drawer/images/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/components/Drawer/images/line.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
103 changes: 103 additions & 0 deletions src/components/Drawer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Component } from 'pet-dex-utilities';
import { listenBreakpoint } from '../../utils/breakpoints/breakpoints';
import { makeSwipable } from '../../utils/swiper';
import close from './images/close.svg';
import line from './images/line.svg';
import './index.scss';

const events = ['open', 'close', 'title:change', 'content:change'];

const html = `
<div class="drawer" data-select="drawer">
<div class="drawer__wrapper" data-select="drawer-wrapper">
<div class="drawer__header">
<img class="drawer__close--line" src="${line}">
<div class="drawer__nav">
<span class="drawer__title" data-select="title"></span>
<button class="drawer__close" data-select="close">
<img class="drawer__close--icon" src="${close}">
</button>
</div>
</div>
<div class="drawer__content" data-select="content"></div>
</div>
</div>
`;

export default function Drawer({ title, content }) {
Component.call(this, { html, events });

const drawer = this.selected.get('drawer');
const drawerWrapper = this.selected.get('drawer-wrapper');
this.isOpen = false;

this.selected.get('close').addEventListener('click', () => this.close());

this.setTitle(title);
this.setContent(content);
makeSwipable(drawerWrapper);

listenBreakpoint('from667', (matches) => {
if (matches) {
drawerWrapper.addEventListener('swipe-right', () => this.close());
}
drawerWrapper.addEventListener('swipe-down', () => this.close());
});

this.listen('mount', () => {
requestAnimationFrame(() => {
drawerWrapper.classList.add('drawer__wrapper--open');
drawer.classList.add('drawer--open');
});
window.addEventListener('keydown', this.onEscapeKey);
drawer.addEventListener('click', this.onClickOutside);
});

this.onEscapeKey = (event) => {
if (event.key === 'Escape') this.close();
};

this.onClickOutside = (event) => {
if (event.target === drawer) this.close();
};

this.listen('unmount', () => {
window.removeEventListener('keydown', this.onEscapeKey);
drawer.removeEventListener('click', this.onClickOutside);
});
}

Drawer.prototype = Object.assign(Drawer.prototype, Component.prototype, {
open() {
if (!this.isOpen) {
this.mount(document.body, true);
this.isOpen = true;
this.emit('open');
}
},
close() {
if (this.isOpen) {
const drawerWrapper = this.selected.get('drawer-wrapper');
this.selected.get('drawer').classList.remove('drawer--open');
drawerWrapper.classList.remove('drawer__wrapper--open');
drawerWrapper.addEventListener(
'transitionend',
() => {
this.emit('close');
this.isOpen = false;
this.unmount();
},
{ once: true },
);
}
},
setTitle(title) {
this.selected.get('title').textContent = title;
this.emit('title:change', title);
},
setContent(content) {
const contentDiv = this.selected.get('content');
content.mount(contentDiv);
this.emit('content:change', content);
},
});
149 changes: 149 additions & 0 deletions src/components/Drawer/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
@use '~styles/colors' as colors;
@use '~styles/fonts' as fonts;
@use '~styles/breakpoints.scss' as breakpoints;

.drawer {
overflow: hidden;

position: fixed;

background: rgba(0, 0, 0, 0);
inset: 0;

transition: background 0.3s ease-in-out;

&--open {
background: rgba(0, 0, 0, 0.8);
}

&__wrapper {
width: 100%;
max-height: 90%;

display: flex;
flex-direction: column;

align-items: flex-start;

padding: 1.2rem 2.4rem 2.4rem;
box-sizing: border-box;

position: absolute;
bottom: -100%;

background: colors.$secondary100;
border-top-left-radius: 2.4rem;
border-top-right-radius: 2.4rem;

transition:
right 0.3s ease-in-out,
bottom 0.3s ease-in-out;

&.drawer__wrapper--open {
right: unset;
bottom: 0;
}

.drawer__header {
width: 100%;

display: flex;
flex-direction: column;

align-items: center;

.drawer__nav {
width: 100%;

display: flex;
gap: 2rem;

align-items: center;

justify-content: space-between;

margin: 3rem 0;

.drawer__title {
display: block;

font-family: fonts.$primaryFont;
color: colors.$gray500;
font-weight: 600;
}

.drawer__close {
display: grid;

place-items: center;

padding: 0.5rem;
border: 0;

background: inherit;

cursor: pointer;
}
}
}

.drawer__content {
width: 100%;
overflow-y: auto;

flex-grow: 1;
}
}
}

@include breakpoints.from667 {
.drawer {
&__wrapper {
width: auto;
max-width: 60rem;
max-height: 100%;

padding: 3rem;

inset: 0 -100% 0 auto;

border-top-left-radius: 2.4rem;
border-top-right-radius: 0;

transition: right 0.3s ease-in-out;

&.drawer__wrapper--open {
right: 0;
}

.drawer__header {
width: 100%;

display: block;

padding: 0;

.drawer__nav {
margin: 0 0 3rem;

.drawer__close {
display: grid;

place-items: center;

padding: 0.5rem;
border: 0;

background: inherit;

cursor: pointer;
}
}

.drawer__close--line {
display: none;
}
}
}
}
}
9 changes: 1 addition & 8 deletions src/home/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,11 @@
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700;&family=Wix+Madefor+Display:wght@400;500;600;700&display=swap"
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Noto+Sans:ital,wght@0,100..900;1,100..900&family=Wix+Madefor+Display:wght@400..800&display=swap"
rel="stylesheet"
/>
<title>Pet Hat</title>
<script src="index.js" type="module"></script>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&family=Noto+Sans:wght@500&display=swap"
rel="stylesheet"
/>

<link
rel="icon"
type="image/x-icon"
Expand Down
39 changes: 39 additions & 0 deletions src/stories/Drawer.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Button from '../components/Button';
import Drawer from '../components/Drawer';
import { initializeSwiper } from '../utils/swiper';

export default {
title: 'Components/Drawer',
render: (args) => {
initializeSwiper();
const drawer = new Drawer(args);
const button = new Button({
text: 'Abrir drawer',
isFullWidth: true,
isDisabled: false,
});
const $container = document.createElement('div');
button.mount($container);

button.listen('click', () => {
drawer.open();
});

return $container;
},
argTypes: {
title: { control: 'text', description: 'Title of the drawer' },
content: { control: null, description: 'Component inside drawer' },
},
};

export const Default = {
args: {
title: 'Add dates',
content: new Button({
text: 'Cadastrar pet',
isFullWidth: true,
isDisabled: false,
}),
},
};
4 changes: 4 additions & 0 deletions src/utils/swiper.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,25 @@ export function makeSwipable($element) {

const api = {
left(callback) {
$element.removeEventListener(SWIPE_LEFT, callback);
$element.addEventListener(SWIPE_LEFT, callback);
return api;
},

right(callback) {
$element.removeEventListener(SWIPE_RIGHT, callback);
$element.addEventListener(SWIPE_RIGHT, callback);
return api;
},

up(callback) {
$element.removeEventListener(SWIPE_UP, callback);
$element.addEventListener(SWIPE_UP, callback);
return api;
},

down(callback) {
$element.removeEventListener(SWIPE_DOWN, callback);
$element.addEventListener(SWIPE_DOWN, callback);
return api;
},
Expand Down

0 comments on commit 2504b2e

Please sign in to comment.