primitives

Dialog

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

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

src/ui/dialog/Dialog.vue

<script setup lang="ts">
/**
 * Порт базового радикс-слоя (registry/bases/radix/ui/dialog.tsx, MIT).
 * Radix DialogPrimitive -> reka-ui Dialog*, один в один.
 */
import { DialogRoot } from "reka-ui"
</script>

<template>
  <DialogRoot data-slot="dialog">
    <slot />
  </DialogRoot>
</template>

src/ui/dialog/DialogClose.vue

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

<template>
  <DialogClose data-slot="dialog-close">
    <slot />
  </DialogClose>
</template>

src/ui/dialog/DialogContent.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { DialogClose, DialogContent } from "reka-ui"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import DialogOverlay from "./DialogOverlay.vue"
import DialogPortal from "./DialogPortal.vue"

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes["class"]
    showCloseButton?: boolean
  }>(),
  {
    showCloseButton: true,
  }
)
</script>

<template>
  <DialogPortal>
    <DialogOverlay />
    <DialogContent
      data-slot="dialog-content"
      :class="
        cn(
          'cn-dialog-content fixed top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2 outline-none',
          props.class
        )
      "
    >
      <slot />
      <DialogClose v-if="props.showCloseButton" data-slot="dialog-close" as-child>
        <Button variant="ghost" class="cn-dialog-close" size="icon-sm">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
          >
            <path d="M18 6 6 18" />
            <path d="m6 6 12 12" />
          </svg>
          <span class="sr-only">Close</span>
        </Button>
      </DialogClose>
    </DialogContent>
  </DialogPortal>
</template>

src/ui/dialog/DialogDescription.vue

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

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

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

src/ui/dialog/DialogFooter.vue

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

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes["class"]
    showCloseButton?: boolean
  }>(),
  {
    showCloseButton: false,
  }
)
</script>

<template>
  <div
    data-slot="dialog-footer"
    :class="
      cn(
        'cn-dialog-footer flex flex-col-reverse gap-2 sm:flex-row sm:justify-end',
        props.class
      )
    "
  >
    <slot />
    <DialogClose v-if="props.showCloseButton" as-child>
      <Button variant="outline">Close</Button>
    </DialogClose>
  </div>
</template>

src/ui/dialog/DialogHeader.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="dialog-header" :class="cn('cn-dialog-header flex flex-col', props.class)">
    <slot />
  </div>
</template>

src/ui/dialog/DialogOverlay.vue

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

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

<template>
  <DialogOverlay
    data-slot="dialog-overlay"
    :class="cn('cn-dialog-overlay fixed inset-0 isolate z-50', props.class)"
  />
</template>

src/ui/dialog/DialogPortal.vue

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

<template>
  <DialogPortal data-slot="dialog-portal">
    <slot />
  </DialogPortal>
</template>

src/ui/dialog/DialogTitle.vue

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

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

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

src/ui/dialog/DialogTrigger.vue

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

<template>
  <DialogTrigger data-slot="dialog-trigger">
    <slot />
  </DialogTrigger>
</template>

src/ui/dialog/index.ts

export { default as Dialog } from "./Dialog.vue"
export { default as DialogClose } from "./DialogClose.vue"
export { default as DialogContent } from "./DialogContent.vue"
export { default as DialogDescription } from "./DialogDescription.vue"
export { default as DialogFooter } from "./DialogFooter.vue"
export { default as DialogHeader } from "./DialogHeader.vue"
export { default as DialogOverlay } from "./DialogOverlay.vue"
export { default as DialogPortal } from "./DialogPortal.vue"
export { default as DialogTitle } from "./DialogTitle.vue"
export { default as DialogTrigger } from "./DialogTrigger.vue"

Установка

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

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

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

  • reka-ui

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