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"