Giter Club home page Giter Club logo

vaul's People

Contributors

abdul535 avatar andrejilderda avatar arsaizdihar avatar artemis-prime avatar cervantes-x avatar choeqq avatar cuzart avatar dcyoung avatar emilkowalski avatar emirhangumus avatar erisleci avatar grantclark1999 avatar gumbee avatar helkyle avatar henriqemalheiros avatar huozhi avatar innei avatar jacobclyne avatar joaom00 avatar kajszy avatar keeganpotgieter avatar khajimatov avatar kinbaum avatar ofekashery avatar rortan134 avatar shkumbinhasani avatar suphon-t avatar telmen avatar ze-kel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vaul's Issues

Testing with vaul drawer

Hey, I just want to propose a section in README.md explaining on how to test components that use the drawer.

I had an issue testing one of my components where jest/testing-library would error out because JSOM does not have a shim of visualViewport and HTMLElement.prototype.setPointerCapture.

I have added the following to a setup-after-env.js file and now tests work!

/**
 * JSDOM doesn't support visualViewport, so we need to mock it globally.
 */
global.visualViewport = {
  addEventListener: jest.fn(),
  removeEventListener: jest.fn(),
  height: 800, // Any height you would like
  width: 400, // Any width you would like
}

/**
 * JSDOM doesn't support HTMLElement.prototype.setPointerCapture, so we need to mock it globally.
 */
global.HTMLElement.prototype.setPointerCapture = jest.fn()

Probably not the best implementation, but it works well enough.

bug: drawer not receiving focus on open

If you load up any of the sandboxes from the readme and trigger the drawer to open, the first tab-able element within the drawer does not receive focus. This is actually breaking the a11y radix gives us. The focus is actually remaining on the trigger. Any tab-able elements after the trigger will receive focus first as you tab around before eventually landing in the drawer with the focus trap.

Here is a video of the behavior as well as a sandbox which is a direct fork of the example:
https://codesandbox.io/p/sandbox/drawer-with-scale-forked-6ss9nx?file=/app/page.tsx:8,10

Screen.Recording.2023-09-22.at.8.41.24.AM.mov

Multiple directions or Modal options

Hey there! Thinking about user experience and all the different devices out there, do you think we could have an option to let the drawer slide from any side, for example, from right to left or top to bottom? And when someone's on a PC, maybe it could pop up as a modal? This sounds a bit easier as I saw you were using Radix Dialog as the base. It just seems like that might look better on bigger screens. If for any reason you can't do it or aren't interested, could you maybe give me a quick pointer on how I might approach it? What do you think? I'd really appreciate your thoughts and help on this.

Opening a drawer scrolls to the top

I have a button that opens up a drawer near the bottom of a page.

Whenever I open the drawer, it will automatically scroll to the top of the page, which is unwanted behavior. Can you make this opt in?

The code I used is the Without scaled background codesandbox example and I'm using Next JS.

seeing strange scroll behavior when tray is open / closes

experiencing a weird background scroll when the tray is open

RPReplay_Final1693409757.mov

context: recently refactored the element scrolling to be the document root, rather than a scrollable div a few children down. problem only started occurring after this change

seeing it happen on iOS safari, mobile chrome, embedded instagram browser... wondering if it is a vaul thing or a radix thing or a browser thing

Support for Svelte

Although it is intended to be a React component, could I use it in Svelte?

experimentalSafariThemeAnimation throws Error: Invalid color string

This is the code for the drawer, the error occurs on IOS 16.6.1 and I'm using Next.js with app route

"use client";
import { RainbowSvg } from "@/app/_components/RainbowSvg";
import { Button, cn } from "@nextui-org/react";
import { useState } from "react";
import { Drawer } from "vaul";

export default function Features() {
  const [snap, setSnap] = useState<number | string | null>("70%");

  return (
    <Drawer.Root
      shouldScaleBackground
      experimentalSafariThemeAnimation
      snapPoints={[0.7, 1]}
      activeSnapPoint={snap}
      setActiveSnapPoint={setSnap}
    >
      <Drawer.Trigger asChild>
        <Button variant="light" size="sm" isIconOnly radius="full">
          <RainbowSvg>
            <path
              d="M21.947 9.179a1.001 1.001 0 0 0-.868-.676l-5.701-.453-2.467-5.461a.998.998 0 0 0-1.822-.001L8.622 8.05l-5.701.453a1 1 0 0 0-.619 1.713l4.213 4.107-1.49 6.452a1 1 0 0 0 1.53 1.057L12 18.202l5.445 3.63a1.001 1.001 0 0 0 1.517-1.106l-1.829-6.4 4.536-4.082c.297-.268.406-.686.278-1.065z"
              fill="white"
            ></path>
          </RainbowSvg>
        </Button>
      </Drawer.Trigger>
      <Drawer.Overlay className="fixed inset-0 bg-black/40" />
      <Drawer.Portal>
        <Drawer.Content className="fixed flex flex-col bg-white border border-gray-200 border-b-none rounded-t-[10px] bottom-0 left-0 right-0 h-full max-h-[97%] mx-[-1px]">
          <div
            className={cn("flex flex-col max-w-md mx-auto w-full p-4 pt-5", {
              "overflow-y-auto": snap === 1,
              "overflow-hidden": snap !== 1,
            })}
          >
            <div>hgallo</div>
          </div>
        </Drawer.Content>
      </Drawer.Portal>
    </Drawer.Root>
  );
}

Keep it sticky

Hi,

Does it's possible to keep the drawer opened and sticky, but that can be opened bigger?

Something like this:

image

Regards

padding-right on Chrome with overflowing elements

When triggering the component on mobile devices using Chrome, and there's an element exceeding the screen's width, the browser automatically adds a padding-right to the html tag. On other browsers the drawer exhibits a lag before it's positioned correctly.

Steps to reproduce:

  1. Open the demo on a mobile device or mobile view in Chrome: Demo Link
  2. Trigger the Drawer.
  3. Observe the padding-right added to the html tag which will affect the black div.

This issue is less likely to be spotted on fully responsive websites.

2023-08-19 at 20 45 32@2x

2023-08-19 at 20 51 47@2x

Drawer input field not visible on native iPhone12Mini Screen when selected

When testing the example with scrollable content and inputs, the keyboard pushes the field so much to the top that a user cannot see what's being typed: https://73f8jw-3000.csb.app/

If you try to drag it a bit down to get the field into view it closes the whole drawer. In the codebox example the lowest field is possible. I am not sure if there's an easy tailwind fix or if this goes a bit deeper.

RPReplay_Final1691137529-converted.MP4

feature: allow nested root to be open/closed programmatically

I have a use case where I need to have a controlled nested root. In my situation I need to programmatically close the nested root. Can you expose the open prop and forward it to the root component?

vaul/src/index.tsx

Lines 725 to 753 in ecb3e24

function NestedRoot({ children, onDrag, onOpenChange }: DialogProps) {
const { onNestedDrag, onNestedOpenChange, onNestedRelease } = useDrawerContext();
if (!onNestedDrag) {
throw new Error('Drawer.NestedRoot must be placed in another drawer');
}
return (
<Root
nested
onClose={() => {
onNestedOpenChange(false);
}}
onDrag={(e, p) => {
onNestedDrag(e, p);
onDrag?.(e, p);
}}
onOpenChange={(o) => {
if (o) {
onNestedOpenChange(o);
}
onOpenChange?.(o);
}}
onRelease={onNestedRelease}
>
{children}
</Root>
);
}

Prop to fine-tune or disable innerHeight threshold

Hi, I've been using Vaul as a dialog replacement for some forms. The issue I've been running into is that once there's a couple of input fields, the submit button is past the 75% innerHeight threshold, which means any misclick and drag, no matter how small, will cause the Drawer to close.

I've been able to implement a workaround by adding onMouseEnter and onMouseLeave handlers on the button to toggle the dismissible prop, but it isn't foolproof as a misclick outside the button will still cause it to close.

Would it be possible to add a prop to fine-tune this innerHeight threshold and optionally disable it if required.

Drawer is not pushed above keyboard if the drawer content becomes scrollable through keyboard open

drawer-scroll.mp4

If:

  • the content of the drawer is potentially scrollable but has no overflowing content while the keyboard is invisible
  • and contains a text-input ...

... in that case, I was expecting the drawer to increase it's height by the keyboard height.

Example: https://codesandbox.io/p/sandbox/drawer-scrollable-forked-wr6r9p?file=%2Fapp%2Fmy-drawer.tsx%3A30%2C15

I tried to fix it by setting the drawer max-height as height when the keyboard is open. That kind of works:
https://codesandbox.io/p/sandbox/drawer-scrollable-forked-4878pm?file=%2Fapp%2Fmy-drawer.tsx%3A6%2C29

Also: I've recognized that #21 arises randomly (have seen it on ios and android). My guess is that it happens when an input at the bottom of the drawer content is focused. In that case, browsers seems to add extra margin to the drawer bottom, in order to push the input above the keyboard.
Btw: Issue #21 constantly arises on ios when focusing the bottom input in the "fixed" example.

Modal prop not giving drawer expected behavior

Hello,

When I set the modal property on the Drawer's Root component to true, clicking outside of the drawer still causes it to close.

I believe the issue is in onPointerDownOutside prop of DialogPrimitive.Content in src/index.tsx, but I wasn't able to get the library to build on my machine, so haven't tested it.

Thanks

Support multiple drawers

I would like to use multiple drawers one on top of the other and close them accordingly. Is this possible in the current version?

Drawer cannot be closed with gesture after scrolling down on Firefox

If you open the drawer with the trigger being in overflowed part of the page (you have to scroll to see it) on Firefox, you cannot swipe it down to close it. As far as i've tested, the bug does not appear in Chrome or Safari.

Tested on

Firefox 117.0 (Desktop)
Firefox 116.3.0 (Mobile)
Vaul version 0.4.5 (latest at the time of writing)

Bug occurs on both firefox versions

Example

Open the codesandbox example below while using Firefox and try to swipe down the drawer after opening it
https://codesandbox.io/p/sandbox/misty-snowflake-gp8kfc
The codesandbox features drawer markup from the "With scaled background" readme example but the issue also occurs without the scaling background

Remove default animations for custom animations

Hello I was wondering if there's a way to properly disable the default animations. I've been using this component as a base for our Drawer component and I absolutely love it since it fits most our needs. I've added the ability to position the components on different parts of the screen "top" | "right" | "bottom" | "left" and have added the styles for it, however i would like to also add the corresponding sliding animations. (when positioned at top, it should slide in from the top etc...)

The problem is that the [vaul-drawer] and [vaul-drawer][data-state="closed"] css classes are taking priority over my own styles, and if i try to set "animation: none" on the component, that rule is always taking priority and no new animations are being applied. However, if I try to add my own animations without removing the default vaul animations using "animation: none", some of the vaul-animation settings like duration or transform, which my animation styles may not override are still being applied.

I know in the future you might add the positioning as a feature yourself but is there a way to remove the default animations instead of manually overriding all the css properties set by [vaul-drawer] and [vaul-drawer][data-state="open"] classes? any advice is appreciated.

Scrollable content inside drawer

I have a lot of content within the drawer, and want to make it possible to scroll down (by dragging up).
Seems like this is currently not possible, and is cut off at the end of the screen without any possibility to scroll beyond the height of the screen.

I found a solution that involves Radix's ScrollArea component, but when that is implemented, we're unable to drag to close the drawer component.

Is there any way to implement this functionality, so we can have scrollable content within the drawer, while still maintaining the "drag to close" functionality?

Vue js

Hello
Thanks for a very good library!
Are there any plans to make an option for Vue 2/3?

issues with next router and react-router navigation hooks

Hello there,

Thank you for the amazing stuff.

We found a couple of issues during the usage.

The first one is background scaling is not restoring the position of the background after manual navigation on latest Chrome.

The second one is in iOS Safari body scroll locked after manual navigation. The reason is locking styles (position: fixed !important; top: 0px; left: 0px; right: 0px; background-color: black;) remain on the body tag on the iOS Safari 15.5/16.6

The same issues with react-router v6.

Here is the example on Codesandbox.

Scrolling issue in firefox

I noticed that in the shouldDrag function there is a check element.role === "dialog", but in the firefox browser it does not work, the value can only be obtained through element.getAttribute("role"), which is why the cycle of getting parentNode reaches html, and if the page has a scroll, then shouldDrag returns false.

Example to reproduce (problem only in firefox browser on pc):
https://codesandbox.io/p/sandbox/drawer-without-scale-forked-7w3sl4?file=%2Fapp%2Fmy-drawer.tsx%3A12%2C29

React 17 compatibility

The peer dependencies are set to React v18. Is it possible to support React 17.x too ? Radix does support React 16-18.

Autofocus isnt working.

Radix default behavior for dialog is it should focus the first focusable element for accessibility purposes. I tested vaul and the trap focus function seems to work, but the autofocus doesnt for some reason. Is this on purpose? if not I would like to try and fix it

Have slider peak out

Add a prop or option to have the slider peak into the visible viewport as minimum default height. Clicking the visible slider would bring it to full height, sliding down would slide back down to minimum default height.

IMG_7810

Prevent max opening

Hi,

Inside snapPoints={["150px", "290px", "650px", 1]}, if I remove the last 1, the drawer still be openable at 100% but without animation, does it's possible to prevent an opening of 100%?

Regards

Change cursor on hover + on drag

I really love this project , and I am willing to use it in the future .
Just one thing , it would be better if you could change the cursor to 'grab' when you're hovering on that icon in the top :

image

And also , change it to grabbing , when you're grabbing it to the bottom (I couldn't take a screenshot of it :) )

bug: drawer not not animating in, only out

I'm not sure what's going on with this, perhaps you can help me look. I only upgraded from 0.6.5 - 0.6.7 and between these two versions, my drawers are no long sliding up, they just appear. The closing animation works just fine.

I tried replicating this in a sandbox, but I haven't had any luck in doing so. I just lifted the example off your website and ran it in my env and it doesn't animate in anymore.

Any ideas as to where I might be able to look?

Screen.Recording.2023-09-25.at.3.28.38.PM.mov

Here is my my two files:

// layout.tsx
export default async function RootLayout({ children, params }: {
    children: React.ReactNode;
    params: { locale: Locale };
}) {
    const locale = params.locale;

    return (
        <html
            className={ `motion-safe:!scroll-smooth ${inter.variable}` }
            dir={ locale === 'ar' ? 'rtl' : undefined }
            lang={ locale }
            suppressHydrationWarning>
            <body>
                <main vaul-drawer-wrapper="">{ children }</main>
            </body>
        </html>
    );
}
// page.tsx
'use client';

import { Drawer } from 'vaul';

export default function HomePage() {
    return (
        <Drawer.Root shouldScaleBackground>
            <Drawer.Trigger asChild>
                <button
                    className="rounded-full bg-white px-4 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
                    type="button">
                    Open Drawer
                </button>
            </Drawer.Trigger>
            <Drawer.Portal>
                <Drawer.Overlay className="fixed inset-0 bg-black/40" />
                <Drawer.Content className="fixed inset-x-0 bottom-0 mt-24 flex h-full max-h-[96%] flex-col rounded-t-[10px] bg-gray-100">
                    <div className="flex-1 rounded-t-[10px] bg-white p-4">
                        <div className="mx-auto mb-8 h-1.5 w-12 shrink-0 rounded-full bg-gray-300" />
                        <div className="mx-auto max-w-md">
                            <Drawer.Title className="mb-4 font-medium">Drawer for React.</Drawer.Title>
                            <p className="mb-2 text-gray-600">
                                This component can be used as a Dialog replacement on mobile and tablet devices.
                            </p>
                            <p className="mb-2 text-gray-600">
                                It comes unstyled, has gesture-driven animations, and is made by{ ' ' }
                                <a
                                    className="underline"
                                    href="https://emilkowal.ski/"
                                    target="_blank">
                                    Emil Kowalski
                                </a>
                                .
                            </p>
                            <p className="mb-8 text-gray-600">
                                It uses{ ' ' }
                                <a
                                    className="underline"
                                    href="https://www.radix-ui.com/docs/primitives/components/dialog"
                                    target="_blank">
                                    Radix&apos;s Dialog primitive
                                </a>{ ' ' }
                                under the hood and is inspired by{ ' ' }
                                <a
                                    className="underline"
                                    href="https://twitter.com/devongovett/status/1674470185783402496"
                                    target="_blank">
                                    this tweet.
                                </a>
                            </p>
                        </div>
                    </div>
                    <div className="mt-auto border-t border-gray-200 bg-gray-100 p-4">
                        <div className="mx-auto flex max-w-md justify-end gap-6">
                            <a
                                className="gap-0.25 flex items-center text-xs text-gray-600"
                                href="https://github.com/emilkowalski/vaul"
                                target="_blank">
                                GitHub
                                <svg
                                    aria-hidden="true"
                                    className="ml-1 h-3 w-3"
                                    fill="none"
                                    height="16"
                                    stroke="currentColor"
                                    strokeLinecap="round"
                                    strokeLinejoin="round"
                                    strokeWidth="2"
                                    viewBox="0 0 24 24"
                                    width="16">
                                    <path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" />
                                    <path d="M15 3h6v6" />
                                    <path d="M10 14L21 3" />
                                </svg>
                            </a>
                            <a
                                className="gap-0.25 flex items-center text-xs text-gray-600"
                                href="https://twitter.com/emilkowalski_"
                                target="_blank">
                                Twitter
                                <svg
                                    aria-hidden="true"
                                    className="ml-1 h-3 w-3"
                                    fill="none"
                                    height="16"
                                    stroke="currentColor"
                                    strokeLinecap="round"
                                    strokeLinejoin="round"
                                    strokeWidth="2"
                                    viewBox="0 0 24 24"
                                    width="16">
                                    <path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" />
                                    <path d="M15 3h6v6" />
                                    <path d="M10 14L21 3" />
                                </svg>
                            </a>
                        </div>
                    </div>
                </Drawer.Content>
            </Drawer.Portal>
        </Drawer.Root>
    );
}

Concept / Suggestion - PC Restyle

I absolutely love this library, and it’s super helpful for app-like interaction on mobile, however;
I think there’s no debate that it’s not as useful on desktop.

My suggestion is to create a side drawer instead of a bottom sheet when Vaul is opened on desktop, it would function virtually the same but it would rest at (and animate out of) the right of the screen.

Regardless, this library is great. Thanks.

Support multi-touch drag gesture

Starting a drag gesture with a single finger and then initiating another touch causes the drawer to jump. I'd expect for the drawer to maintain it's position and upgrade to a multi-touch gesture. I've recorded the following video on an Android phone to demonstrate:

screen-20230726-154152.2.mp4

TypeError: (void 0) is not a function

Hi! Thanks for the awesome library!

I encountered a bug with 0.6.6 version that causes next build to throw TypeError: (void 0) is not a function. Going back to 0.6.5 fixes the issue.

My node.js version: 18.16.0

TypeError: (void 0) is not a function
    at Je (/home/ubuntu/apps/xd/releases/xd/node_modules/vaul/dist/index.js:3:9113)

Bugs with input

There are multiple bugs when using input on mobile: I tested with (safari)

  1. When clicking on input, the keyboard comes out as it focuses the input, however the input stays behind the keyboard until I start typing.
  2. After inputting something and clicking done on the keyboard, the position of the drawer doesnt return to the bottom and hangs.
trim.85DAF860-64FB-4D91-AFBE-CDA3AA3F6FF9.MOV

[bag] Blinking while closing

Steps to reproduce:

Result: drawer will blink on closing.
Expected result: drawer should close smoothly without blinking.

IMG_4894.MP4

Browser: IOS Safari 16.0.2

useLayoutEffect() throws SSR warnings when not in Next js with server components

The usePreventScroll() hook makes use of useLayoutEffect() when the <Drawer.Root> component is mounted. For anyone not using NextJs with server components or explicitly mounting on client side only, this will throw SSR warnings. An easy fix could be to switch this out for an isomorphic layout effect.

import { useEffect, useLayoutEffect } from 'react'

export const useIsomorphicLayoutEffect =
  typeof window !== 'undefined' ? useLayoutEffect : useEffect

Drawer cannot be closed with gesture after dragging horizontally

Description
Sometimes, after dragging horizontally, the drawer cannot be closed by dragging downwards. As you can see from the video, it doesn't happen every time.

Steps

  1. Go to https://vaul.emilkowal.ski/
  2. Click Open Drawer
  3. Click and drag the mouse horizontally
  4. Attempt to close the drawer by dragging downwards
recording.mp4

Environment
Browser: Firefox (cannot reproduce in Chrome or WebKit)

Weird behavior when clicking on an input on iOS/iPhone

Hey,

First of all, thank you for this awesome drawer component! Really enjoying it so far. Sadly there is one thing that prevents me from using it inside my app:

I am experiencing a weird behavior when clicking on an input field inside the drawer component on my iOS device. The drawer itself is pushed down to the bottom and not visible anymore.

Here is a short demonstration. It uses the bare setup for a next.js app and only typescript, tailwindcss and vaul are installed. The styling of the drawer is similar to the Scrollable with inputs example:

RPReplay_Final1695658103.MP4

Here is the repository for it:

vaul-ios-bug-demo

Proposal: Responsive layout

It is possible to see in the image below that on the iPad we have the same modal with a slightly different layout, I would like to know if it would be interesting to implement this layout in the project?

screenshot with two iOS simulators, one with an iPhone open in a login modal and another iPad simulator open with the same login screen but with a slightly different layout

body scroll delay after closing

noticing a delay in body scrollability after closing the drawer, maybe a half second or so

RPReplay_Final1692883821.mov

pictured: after the first close of the menu, I try to scroll the body and it is locked. after the second, i wait half a second, and it works.

is there a setting I can pass to decrease this threshold? noticed there was scrollLockThreshold but that looks like it's more for the content inside the drawer instead of the scroll lock on the body content

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.