<main>
<header>
<h1>Action Sheet Pop-up</h1>
</header>
<article>
<p>Lorem ipsum, dolor, sit amet consectetur adipisicing elit. Repellat illo eum hic possimus, libero voluptates, facere nihil deserunt similique error sunt vero minima enim cupiditate quis velit rem ab repellendus.</p>
<p>Neque hic veniam cum voluptates quae magnam quisquam saepe. Dolorum quasi amet officiis vero aliquid pariatur commodi repellendus. Quos iure nobis doloremque ipsum facere nostrum neque adipisci hic labore voluptates?</p>
<p>Mollitia beatae, repellat est laboriosam officiis? Earum veritatis incidunt explicabo id tempora perspiciatis non doloribus natus nisi asperiores quia error autem laudantium, amet doloremque, vitae quos. Soluta unde numquam id.</p>
<p>Recusandae facere esse quod dolorum maxime corrupti ex quam iure id quis eius cumque fugiat, consequatur autem, excepturi molestias libero velit illo a quo. Sed quae aut inventore quia, ipsa.</p>
<p>Eius id laboriosam, quas iure laborum corrupti optio corporis tempore odit laudantium similique, accusamus, vel! Perspiciatis sed saepe rem. Nihil explicabo ea at vitae rerum eum, corrupti ipsam suscipit, id!</p>
<p>Voluptate pariatur, cum praesentium, veniam tenetur distinctio totam voluptates ea beatae, dicta voluptatum illum sit! Earum harum odio natus perspiciatis. Magni eos temporibus harum quas laborum aspernatur, minus, sunt illum.</p>
<p>Ducimus nobis, libero illum commodi aliquid. Molestias beatae ducimus ratione quod, quis itaque ipsum, illum amet labore, nostrum quisquam enim. Sint aperiam qui nihil eaque id quam odio? Repudiandae, sint!</p>
<p>In rem tenetur accusamus accusantium id, officia quaerat atque, placeat architecto nihil unde, sit cupiditate minima tempore! Magni, atque labore. Dolor voluptatum eius incidunt, enim? Asperiores similique, ut amet atque?</p>
<p>Illum, quam fugiat, veniam officia totam nihil aut dolore quo! Officiis ipsa harum vero voluptatibus eaque repudiandae amet eligendi ducimus laboriosam ab maiores labore, odit, voluptas quos illo sint nulla.</p>
<p>Eius earum nihil officiis, inventore accusantium consequuntur dolor reprehenderit in esse quos eos iste nemo amet facere, mollitia, assumenda cum provident quam. Ipsam, vitae! Excepturi quos possimus enim, quia distinctio.</p>
</article>
</main>
<div id="sheet-pop-up" class="actionsheet" popover>
<div class="actionsheet__header">
<button popovertoggletarget="sheet-pop-up">Actions</button>
</div>
<div class="actionsheet__content">
<ul class="actionsheet__actions">
<li>
<button autofocus class="ripple">Make</button>
</li>
<li>
<button class="ripple">Things</button>
</li>
<li>
<button class="ripple">Pop</button>
</li>
</ul>
<div class="actionsheet__divider"></div>
<div class="actionsheet__footer">
<button popoverhidetarget="sheet-pop-up" class="ripple">Cancel</button>
</div>
</div>
</div>
@layer demo {
.actionsheet {
--bg: var(--surface-2);
--blur: 6px;
border: 0;
padding: 0;
display: block;
top: 100%;
margin: 0;
overflow: visible;
left: 50%;
width: var(--size-content-3);
max-width: 100%;
transition: transform 0.2s;
transform: translate(-50%, calc((0 - var(--open, 0)) * 100%))
translateY(calc(var(--translate, 0) * 1px));
color: var(--text-2);
filter: drop-shadow(0 0 var(--size-1) hsl(var(--gray-8-hsl) / 0.75));
}
.actionsheet:after {
content: "";
position: absolute;
height: 100%;
width: 100%;
background: var(--bg);
top: 100%;
left: 0;
}
.actionsheet::backdrop {
opacity: var(--open, 0);
transition: opacity 0.2s;
background: hsl(0 0% 10% / 0.5);
}
@media (prefers-color-scheme: dark) {
.actionsheet {
filter: drop-shadow(0 0 var(--size-1) hsl(var(--gray-1-hsl) / 0.75));
}
.actionsheet::backdrop {
background: hsl(0 0% 90% / 0.5);
}
}
.actionsheet:open {
--open: 1;
}
.actionsheet:open::backdrop {
--open: 1;
}
.actionsheet__header {
font-weight: var(--font-weight-6);
background: var(--bg);
position: absolute;
bottom: 99%;
left: 0;
padding: var(--size-2) var(--size-4) 0 var(--size-4);
width: 100%;
border-top-right-radius: var(--radius-3);
border-top-left-radius: var(--radius-3);
display: flex;
justify-content: center;
}
.actionsheet__actions li {
padding: 0;
margin: 0;
max-inline-size: 100%;
}
.actionsheet__content {
padding: var(--size-4);
background: var(--bg);
}
.actionsheet button {
width: 100%;
padding: var(--size-4);
background: var(--surface-1);
box-shadow: none;
color: var(--text-1);
border-radius: 0;
}
.actionsheet button {
outline-color: transparent;
}
.actionsheet__header:after {
content: "";
height: 6px;
width: 40px;
border-radius: 2px;
background: var(--text-2);
position: absolute;
top: calc(var(--size-4) * 0.5);
left: 50%;
transform: translateX(-50%);
pointer-events: none;
}
.actionsheet__header [popuptoggletarget] {
width: 100%;
padding: var(--size-4);
background: transparent;
}
.actionsheet__actions {
background: var(--bg);
padding: 0;
display: grid;
gap: 2px;
padding-top: 0;
border: 0;
list-style-type: none;
}
.actionsheet__footer {
width: 100%;
background: var(--bg);
padding-top: var(--size-4);
}
}
@layer base {
*,
*:after,
*:before {
box-sizing: border-box;
/*cursor: none;*/
touch-action: none;
}
body {
display: block;
min-height: 100vh;
font-family: "Google Sans", sans-serif, system-ui;
overflow: auto;
}
:where([popover]) {
margin: auto;
border-width: 0;
border-style: none;
background: transparent;
}
h1 {
margin: 0;
color: var(--gray-0);
}
header {
height: 25vmin;
min-height: 200px;
background: var(--gradient-27);
display: grid;
place-items: center;
color: var(--gray-0);
padding: var(--size-4);
grid-template-columns: 1fr;
}
main {
margin: 0 auto;
}
article {
padding: var(--size-4);
display: flex;
flex-direction: column;
align-items: center;
}
article > * + * {
margin-top: var(--size-4);
}
}
const clamp = (min, max, value) => Math.min(Math.max(value, min), max);
const HEADER = document.querySelector(".actionsheet__header");
const ACTIONSHEET = document.querySelector(".actionsheet");
const STATE = {
active: false,
origin: 0
};
const dragSheet = ({ y }) => {
if (STATE.active) {
let translation;
const { height } = ACTIONSHEET.getBoundingClientRect();
if (ACTIONSHEET.matches(":open")) {
translation = clamp(-height, height, (STATE.origin - y) * -1);
} else {
translation = clamp(-height, 0, (STATE.origin - y) * -1);
}
ACTIONSHEET.style.setProperty("--translate", translation);
}
};
const endDrag = (e) => {
const { y, movementY, pointerType } = e;
STATE.active = false;
STATE.origin = 0;
ACTIONSHEET.removeAttribute("style");
document.body.removeEventListener("pointermove", dragSheet);
document.body.removeEventListener("pointerup", endDrag);
requestAnimationFrame(() => {
if (pointerType === "touch") {
ACTIONSHEET[
ACTIONSHEET.matches(":open") ? "hidePopover" : "showPopover"
]();
}
});
};
const activateDrag = ({ y }) => {
STATE.active = true;
STATE.origin = y;
ACTIONSHEET.style.transition = "none";
document.body.addEventListener("pointermove", dragSheet);
document.body.addEventListener("pointerup", endDrag);
};
HEADER.addEventListener("pointerdown", activateDrag);