Drawer

Drawerは、任意のコンテンツを受け取り、画面の上下左右いずれかの端からスライドインで表示できるコンポーネントです。

プロパティ

drawerは、以下のプロパティをサポートしています。

名前 デフォルト値 説明
direction string "left" Drawer の表示方向
open boolean false Drawer を表示するかどうか
dismissible boolean true Drawer 外をクリックすると閉じるかどうか

インストールの手順

以下のコンポーネントのコードを、使いたいプロジェクトにコピー&ペーストします。
パスは実際のプロジェクトの構成にあわせて更新します。

modules/Drawer.svelte
        <!--
@component
## 概要
- 画面の上下左右いずれかの端からスライドインすることで、補足情報や操作パネルを表示するコンポーネントです

## 機能
- 開閉可能なdrawerとして使用できます
- 任意のコンテンツを配置できます

## Usage
```svelte
<Drawer direction="left" bind:open={isOpen}>
  {@render children?.()}
</Drawer>
```
-->

<script module lang="ts">
  import type { Snippet } from 'svelte';
  import type { ClassValue } from 'svelte/elements';
  import { cva, type VariantProps } from 'class-variance-authority';

  const FLY_DISTANCE = 300;

  export const drawerVariants = cva('fixed z-50 bg-base-surface-default border-base-stroke-default overflow-hidden', {
    variants: {
      /** drawerの方向 */
      direction: {
        left: 'top-0 left-0 w-[40vw] h-[100vh] border-r rounded-r-lg max-md:w-[70vw]',
        right: 'top-0 right-0 w-[40vw] h-[100vh] border-l rounded-l-lg max-md:w-[70vw]',
        top: 'top-0 left-0 w-[100vw] h-[40vh] border-b rounded-bl-lg rounded-br-lg max-md:h-[50vh]',
        bottom: 'bottom-0 left-0 w-[100vw] h-[40vh] border-t rounded-tl-lg rounded-tr-lg max-md:h-[50vh]',
      },
    },
    defaultVariants: {
      direction: 'right',
    },
  });

  export type DrawerVariants = VariantProps<typeof drawerVariants>;

  export type DirectionType = 'left' | 'right' | 'top' | 'bottom';

  export interface DrawerProps extends DrawerVariants {
    /** クラス */
    class?: ClassValue;
    /** 開閉のフラグ */
    open: boolean;
    /** drawerの要素外をクリックしたときに閉じるかどうか */
    dismissible?: boolean;
    /** drawerの方向 */
    direction?: DirectionType;
    children: Snippet<[]>;
  }
</script>

<script lang="ts">
  import { fade, fly } from 'svelte/transition';

  let { class: className, children, direction = 'left', open = $bindable(false), dismissible = true }: DrawerProps = $props();

  let backgroundElement = $state<HTMLElement>();

  let drawerVariantsClass = $derived(drawerVariants({ direction, class: className }));

  $effect(() => {
    if (open) {
      document.body.classList.add('overflow-hidden');
      document.addEventListener('click', onClickOutside);
      document.addEventListener('keydown', onKeyDown);
    }

    return () => {
      document.body.classList.remove('overflow-hidden');
      document.removeEventListener('click', onClickOutside);
      document.removeEventListener('keydown', onKeyDown);
    };
  });

  // flyアニメーションのパラメータを取得
  function getFlyParams(direction) {
    if (!direction) return { x: 0, y: 0, duration: 0 };
    return {
      x: direction === 'left' ? -FLY_DISTANCE : direction === 'right' ? FLY_DISTANCE : 0,
      y: direction === 'top' ? -FLY_DISTANCE : direction === 'bottom' ? FLY_DISTANCE : 0,
      duration: 300,
    };
  }

  // drawer外をクリックしたときにdrawerを閉じる
  function onClickOutside(e: MouseEvent) {
    e.preventDefault();
    e.stopPropagation();
    if (!backgroundElement) return;
    if (!(e.target instanceof HTMLElement)) return;

    if (backgroundElement.contains(e.target) && dismissible) {
      open = false;
    }
  }

  // escキーでdrawerを閉じる
  function onKeyDown(e: KeyboardEvent) {
    if (e.key === 'Escape' && dismissible) {
      open = false;
    }
  }
</script>

{#if open}
  <div class="fixed inset-0 z-40 bg-base-container-default/50" bind:this={backgroundElement} transition:fade={{ duration: 150 }}></div>
  <div class={drawerVariantsClass} transition:fly={getFlyParams(direction)}>
    {@render children()}
  </div>
{/if}

      

使い方


サンプル

Default

特に操作が行われていない、デフォルトの状態です。

Direction

スライドインする方向を選択できます。

With Input,Select

InputSelectなどの要素と組み合わせることもできます。