dialog.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. 'use client';
  2. import * as React from 'react';
  3. import { Dialog as DialogPrimitive } from '@base-ui/react/dialog';
  4. import { cn } from '@/lib/utils';
  5. import { Button } from '@/components/ui/button';
  6. import { XIcon } from 'lucide-react';
  7. function Dialog({ ...props }: DialogPrimitive.Root.Props) {
  8. return <DialogPrimitive.Root data-slot="dialog" {...props} />;
  9. }
  10. function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
  11. return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
  12. }
  13. function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
  14. return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
  15. }
  16. function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
  17. return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
  18. }
  19. function DialogOverlay({
  20. className,
  21. ...props
  22. }: DialogPrimitive.Backdrop.Props) {
  23. return (
  24. <DialogPrimitive.Backdrop
  25. data-slot="dialog-overlay"
  26. className={cn(
  27. 'fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0',
  28. className,
  29. )}
  30. {...props}
  31. />
  32. );
  33. }
  34. function DialogContent({
  35. className,
  36. children,
  37. showCloseButton = true,
  38. ...props
  39. }: DialogPrimitive.Popup.Props & {
  40. showCloseButton?: boolean;
  41. }) {
  42. return (
  43. <DialogPortal>
  44. <DialogOverlay />
  45. <DialogPrimitive.Popup
  46. data-slot="dialog-content"
  47. className={cn(
  48. 'fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
  49. className,
  50. )}
  51. {...props}
  52. >
  53. {children}
  54. {showCloseButton && (
  55. <DialogPrimitive.Close
  56. data-slot="dialog-close"
  57. render={
  58. <Button
  59. variant="ghost"
  60. className="absolute top-2 right-2"
  61. size="icon-sm"
  62. />
  63. }
  64. >
  65. <XIcon />
  66. <span className="sr-only">Close</span>
  67. </DialogPrimitive.Close>
  68. )}
  69. </DialogPrimitive.Popup>
  70. </DialogPortal>
  71. );
  72. }
  73. function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
  74. return (
  75. <div
  76. data-slot="dialog-header"
  77. className={cn('flex flex-col gap-2', className)}
  78. {...props}
  79. />
  80. );
  81. }
  82. function DialogFooter({
  83. className,
  84. showCloseButton = false,
  85. children,
  86. ...props
  87. }: React.ComponentProps<'div'> & {
  88. showCloseButton?: boolean;
  89. }) {
  90. return (
  91. <div
  92. data-slot="dialog-footer"
  93. className={cn(
  94. '-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end',
  95. className,
  96. )}
  97. {...props}
  98. >
  99. {children}
  100. {showCloseButton && (
  101. <DialogPrimitive.Close render={<Button variant="outline" />}>
  102. Close
  103. </DialogPrimitive.Close>
  104. )}
  105. </div>
  106. );
  107. }
  108. function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
  109. return (
  110. <DialogPrimitive.Title
  111. data-slot="dialog-title"
  112. className={cn(
  113. 'font-heading text-base leading-none font-medium',
  114. className,
  115. )}
  116. {...props}
  117. />
  118. );
  119. }
  120. function DialogDescription({
  121. className,
  122. ...props
  123. }: DialogPrimitive.Description.Props) {
  124. return (
  125. <DialogPrimitive.Description
  126. data-slot="dialog-description"
  127. className={cn(
  128. 'text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground',
  129. className,
  130. )}
  131. {...props}
  132. />
  133. );
  134. }
  135. export {
  136. Dialog,
  137. DialogClose,
  138. DialogContent,
  139. DialogDescription,
  140. DialogFooter,
  141. DialogHeader,
  142. DialogOverlay,
  143. DialogPortal,
  144. DialogTitle,
  145. DialogTrigger,
  146. };