breadcrumb.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import * as React from "react"
  2. import { Slot } from "@radix-ui/react-slot"
  3. import { ChevronRight, MoreHorizontal } from "lucide-react"
  4. import { cn } from "@/lib/utils"
  5. const Breadcrumb = React.forwardRef<
  6. HTMLElement,
  7. React.ComponentPropsWithoutRef<"nav"> & {
  8. separator?: React.ReactNode
  9. }
  10. >(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />)
  11. Breadcrumb.displayName = "Breadcrumb"
  12. const BreadcrumbList = React.forwardRef<
  13. HTMLOListElement,
  14. React.ComponentPropsWithoutRef<"ol">
  15. >(({ className, ...props }, ref) => (
  16. <ol
  17. ref={ref}
  18. className={cn(
  19. "flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
  20. className
  21. )}
  22. {...props}
  23. />
  24. ))
  25. BreadcrumbList.displayName = "BreadcrumbList"
  26. const BreadcrumbItem = React.forwardRef<
  27. HTMLLIElement,
  28. React.ComponentPropsWithoutRef<"li">
  29. >(({ className, ...props }, ref) => (
  30. <li
  31. ref={ref}
  32. className={cn("inline-flex items-center gap-1.5", className)}
  33. {...props}
  34. />
  35. ))
  36. BreadcrumbItem.displayName = "BreadcrumbItem"
  37. const BreadcrumbLink = React.forwardRef<
  38. HTMLAnchorElement,
  39. React.ComponentPropsWithoutRef<"a"> & {
  40. asChild?: boolean
  41. }
  42. >(({ asChild, className, ...props }, ref) => {
  43. const Comp = asChild ? Slot : "a"
  44. return (
  45. <Comp
  46. ref={ref}
  47. className={cn("transition-colors hover:text-foreground", className)}
  48. {...props}
  49. />
  50. )
  51. })
  52. BreadcrumbLink.displayName = "BreadcrumbLink"
  53. const BreadcrumbPage = React.forwardRef<
  54. HTMLSpanElement,
  55. React.ComponentPropsWithoutRef<"span">
  56. >(({ className, ...props }, ref) => (
  57. <span
  58. ref={ref}
  59. role="link"
  60. aria-disabled="true"
  61. aria-current="page"
  62. className={cn("font-normal text-foreground", className)}
  63. {...props}
  64. />
  65. ))
  66. BreadcrumbPage.displayName = "BreadcrumbPage"
  67. const BreadcrumbSeparator = ({
  68. children,
  69. className,
  70. ...props
  71. }: React.ComponentProps<"li">) => (
  72. <li
  73. role="presentation"
  74. aria-hidden="true"
  75. className={cn("[&>svg]:w-3.5 [&>svg]:h-3.5", className)}
  76. {...props}
  77. >
  78. {children ?? <ChevronRight />}
  79. </li>
  80. )
  81. BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
  82. const BreadcrumbEllipsis = ({
  83. className,
  84. ...props
  85. }: React.ComponentProps<"span">) => (
  86. <span
  87. role="presentation"
  88. aria-hidden="true"
  89. className={cn("flex h-9 w-9 items-center justify-center", className)}
  90. {...props}
  91. >
  92. <MoreHorizontal className="h-4 w-4" />
  93. <span className="sr-only">More</span>
  94. </span>
  95. )
  96. BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
  97. export {
  98. Breadcrumb,
  99. BreadcrumbList,
  100. BreadcrumbItem,
  101. BreadcrumbLink,
  102. BreadcrumbPage,
  103. BreadcrumbSeparator,
  104. BreadcrumbEllipsis,
  105. }