primitives

Drawer

Drawer — базовый примитив RevueUI (Reka UI + shadcn-совместимый API).

Загрузка превью…

src/ui/drawer/Drawer.vue

<script setup lang="ts">
/**
 * Порт базового радикс-слоя (registry/bases/radix/ui/drawer.tsx, MIT).
 * Оригинал построен на npm-пакете `vaul` (React). Vue-порт `vaul-vue`
 * не используется: пакет помечен на npm лицензией "Proprietary"
 * (в package.json нет поля license), а его README прямо помечает
 * пакет как unmaintained и рекомендует переходить на встроенный
 * Drawer из reka-ui (MIT, уже зависимость воркспейса) — что и сделано
 * здесь. API отличается от vaul (нет проп `direction`, вместо
 * `data-vaul-drawer-direction` — свои атрибуты), см. docs/PORTING.md.
 */
import { DrawerRoot } from "reka-ui"
</script>

<template>
  <DrawerRoot data-slot="drawer">
    <slot />
  </DrawerRoot>
</template>

src/ui/drawer/DrawerClose.vue

<script setup lang="ts">
import { DrawerClose } from "reka-ui"
</script>

<template>
  <DrawerClose data-slot="drawer-close">
    <slot />
  </DrawerClose>
</template>

src/ui/drawer/DrawerContent.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { DrawerContent } from "reka-ui"
import { cn } from "@/lib/utils"
import DrawerOverlay from "./DrawerOverlay.vue"
import DrawerPortal from "./DrawerPortal.vue"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <DrawerPortal data-slot="drawer-portal">
    <DrawerOverlay />
    <DrawerContent
      data-slot="drawer-content"
      :class="
        cn(
          'cn-drawer-content group/drawer-content fixed z-50 data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm',
          props.class
        )
      "
    >
      <div
        class="cn-drawer-handle mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block"
      />
      <slot />
    </DrawerContent>
  </DrawerPortal>
</template>

src/ui/drawer/DrawerDescription.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { DrawerDescription } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <DrawerDescription
    data-slot="drawer-description"
    :class="cn('cn-drawer-description', props.class)"
  >
    <slot />
  </DrawerDescription>
</template>

src/ui/drawer/DrawerFooter.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div
    data-slot="drawer-footer"
    :class="cn('cn-drawer-footer mt-auto flex flex-col', props.class)"
  >
    <slot />
  </div>
</template>

src/ui/drawer/DrawerHeader.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div
    data-slot="drawer-header"
    :class="
      cn(
        'cn-drawer-header flex flex-col group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center',
        props.class
      )
    "
  >
    <slot />
  </div>
</template>

src/ui/drawer/DrawerOverlay.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { DrawerOverlay } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <DrawerOverlay
    data-slot="drawer-overlay"
    :class="
      cn(
        'cn-drawer-overlay fixed inset-0 z-50 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0',
        props.class
      )
    "
  />
</template>

src/ui/drawer/DrawerPortal.vue

<script setup lang="ts">
import { DrawerPortal } from "reka-ui"
</script>

<template>
  <DrawerPortal data-slot="drawer-portal">
    <slot />
  </DrawerPortal>
</template>

src/ui/drawer/DrawerTitle.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { DrawerTitle } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <DrawerTitle
    data-slot="drawer-title"
    :class="cn('cn-drawer-title cn-font-heading', props.class)"
  >
    <slot />
  </DrawerTitle>
</template>

src/ui/drawer/DrawerTrigger.vue

<script setup lang="ts">
import { DrawerTrigger } from "reka-ui"
</script>

<template>
  <DrawerTrigger data-slot="drawer-trigger">
    <slot />
  </DrawerTrigger>
</template>

src/ui/drawer/index.ts

export { default as Drawer } from "./Drawer.vue"
export { default as DrawerTrigger } from "./DrawerTrigger.vue"
export { default as DrawerPortal } from "./DrawerPortal.vue"
export { default as DrawerClose } from "./DrawerClose.vue"
export { default as DrawerOverlay } from "./DrawerOverlay.vue"
export { default as DrawerContent } from "./DrawerContent.vue"
export { default as DrawerHeader } from "./DrawerHeader.vue"
export { default as DrawerFooter } from "./DrawerFooter.vue"
export { default as DrawerTitle } from "./DrawerTitle.vue"
export { default as DrawerDescription } from "./DrawerDescription.vue"

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/drawer.json

Зависимости реестра

npm-зависимости

  • reka-ui

Источник: порт из ReUI (Keenthemes, MIT)