🥪

shadcn/uiのDrawerを使うことで得たTips

2024/06/28に公開

はじめに

現在、手書き文字を入力できる画面をMobile用に作成しているのですがPWAで作成している兼ね合いでユーザーに機能を使ってもらいたいタイミングでスマホを横に向けてもらい画面がLandscapeモードに切り替わるというのがUXとして(そうして使ってくださいねって前段にアナウンスいれるのが)うーん🧐な気持ちだったのとPWAではアプリの用に画面毎に縦と横の使い分けを固定できないので困っていたのですがそれなら縦画面を横向きのレイアウトで作ればユーザーは勝手に横向きでという天啓アドバイスを得たことと、更に下からグイっとスライドしてくるUXにしたいですよねってメンバーとキャッキャしていたことから、下からのスライドに関しては(楽をしようと)使ってみたかったこともありshadcn/uiのDrawerを使うことにして現在も試行錯誤しながら対応しております。

その中でshadcn/uiのDrawerを使うことで得たTipsがあったので備忘録もかねてご紹介したいと思います。

https://ui.shadcn.com/docs/components/drawer

※Drawerの動きは公式で確認して頂くとイメージが掴みやすいかと

問題1 ドラッグ操作させたくない

手書き文字を書かせる画面なので文字を書くことが即ち画面のドラッグ操作につながり、書いている途中でスィーっと下に要素がドラッグされていき文字を書くことのできる領域が閉じてしまうので困りました。
中身のDialogPropsを見てみるとfixedとかあるので固定とはつまりこれなのでは!!!?

DialogProps 部分抜粋
type DialogProps = {
    activeSnapPoint?: number | string | null;
    setActiveSnapPoint?: (snapPoint: number | string | null) => void;
    children?: React.ReactNode;
    open?: boolean;
    closeThreshold?: number;
    noBodyStyles?: boolean;
    onOpenChange?: (open: boolean) => void;
    shouldScaleBackground?: boolean;
    setBackgroundColorOnScale?: boolean;
    scrollLockTimeout?: number;
    fixed?: boolean;
    dismissible?: boolean;
    handleOnly?: boolean;
    onDrag?: (event: React.PointerEvent<HTMLDivElement>, percentageDragged: number) => void;
    onRelease?: (event: React.PointerEvent<HTMLDivElement>, open: boolean) => void;
    modal?: boolean;
    nested?: boolean;
    onClose?: () => void;
    direction?: 'top' | 'bottom' | 'left' | 'right';
    preventScrollRestoration?: boolean;
    disablePreventScroll?: boolean;
} & (WithFadeFromProps | WithoutFadeFromProps);

「やっぱ中身確認するのが大事」とか独り言を呟きながらpropsに渡してみても、、、ぬぅ!!!!!!?
「動く、、こいつ滑らかに滑っていきやがる、、、」という状態になってしまったので色々調べた結果

ここに解決策は書いており
https://github.com/shadcn-ui/ui/issues/2605

正解はこれdata-vaul-no-drag={false}でした

sample.ts 部分抜粋
<Drawer>
  <DrawerTrigger>開く</DrawerTrigger>
  <DrawerContent data-vaul-no-drag={false}>
    <Signature />
  </DrawerContent>
</Drawer>

問題2 Defaultのスピードだと開閉がちょっと早い気がする

歳のせいでしょうか。。なんだかそのままのDefault設定では開閉の速度が早くシュパッと出てくるのはかっこいいのですが使ってもらうユーザーのことを考えてももう少しゆっくりな方が優しくない?っという気持ちが芽生えスピードを緩めてみるか!!という試みをおこないました

またもめげない気持ちで中身をみて(しかも今度は実際にcomponent生成されてるので)
DrawerPrimitive.ContentにclassName渡せる!!!っと思い

drawer.tsx 部分抜粋
<DrawerPortal>
  <DrawerOverlay />
  <DrawerPrimitive.Content
   ref={ref}
   className={cn("fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",className)}
      {...props}
  >
  <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
    {children}
  </DrawerPrimitive.Content>
</DrawerPortal>

じゃあこれで一旦、classNameから
transition-transform duration-500 transformこんな感じで渡しますかね
まずは500ぐらいで試しますかね🤠

「ん?、、変わってない、、あぁ Defaultの速度が500なのね(嫌な予感🥶)」

結局、duration-1000にしても全く速度は変わらず、、でした

これも色々調べてみた結果

解決策はこれでした
https://github.com/emilkowalski/vaul/issues/205

Drawerの内部で利用しているvaulが元々スピード調整できる設計では無いようで
しかもshadcn/uiのDrawerからだと余計にできないっぽい感じでした

結局、デフォ設定のスピードをCSSの🔥継承勝ち🔥させるという古来からの試みにより、希望通りのスピードになったように思えます。

global.css
[vaul-drawer] {
  transition: transform 0.8s cubic-bezier(0.32, 0.72, 0, 1) !important;
}

https://vaul.emilkowal.ski/

※というかVaulの公式を見る限り、Drawer作るだけならVaulだけで良さそうだったのですが
今回は他のパーツにもshadcn/ui使ってるのでこちらだけというわけにはいきませんでした。

まとめ

Tipsとしてつらつらと書きましたがそもそも動画などのイメージがないので上手く伝わらずで申し訳ないです(動画をそのまま埋め込みできると嬉しかったのですが、上手くできず、、そもそもやり方わかってないだけな気も。。。)

github.gistのコメント欄に動画イメージ(mobileキャプチャーの動画を貼ったので)
確認いただけると今回のTipsのイメージがつきやすいかなと思います。

view rawの方ではただテキストが出るだけになってしまっているので
zenn記事の動画になりますの方をクリックしていただけると各コメント欄で確認頂けるようにしております。

Discussion