SheetContent.vue 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. <script setup lang="ts">
  2. import type { DialogContentEmits, DialogContentProps } from "reka-ui"
  3. import type { HTMLAttributes } from "vue"
  4. import { reactiveOmit } from "@vueuse/core"
  5. import { X } from "lucide-vue-next"
  6. import {
  7. DialogClose,
  8. DialogContent,
  9. DialogPortal,
  10. useForwardPropsEmits,
  11. } from "reka-ui"
  12. import { cn } from '@/Packages/Shadcn/Lib/utils'
  13. import SheetOverlay from "./SheetOverlay.vue"
  14. interface SheetContentProps extends DialogContentProps {
  15. class?: HTMLAttributes["class"]
  16. side?: "top" | "right" | "bottom" | "left"
  17. }
  18. defineOptions({
  19. inheritAttrs: false,
  20. })
  21. const props = withDefaults(defineProps<SheetContentProps>(), {
  22. side: "right",
  23. })
  24. const emits = defineEmits<DialogContentEmits>()
  25. const delegatedProps = reactiveOmit(props, "class", "side")
  26. const forwarded = useForwardPropsEmits(delegatedProps, emits)
  27. </script>
  28. <template>
  29. <DialogPortal>
  30. <SheetOverlay />
  31. <DialogContent
  32. data-slot="sheet-content"
  33. :class="cn(
  34. 'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
  35. side === 'right'
  36. && 'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
  37. side === 'left'
  38. && 'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
  39. side === 'top'
  40. && 'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
  41. side === 'bottom'
  42. && 'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
  43. props.class)"
  44. v-bind="{ ...forwarded, ...$attrs }"
  45. >
  46. <slot />
  47. <DialogClose
  48. class="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none"
  49. >
  50. <X class="size-4" />
  51. <span class="sr-only">Close</span>
  52. </DialogClose>
  53. </DialogContent>
  54. </DialogPortal>
  55. </template>