{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"breadcrumbs","type":"registry:ui","title":"Breadcrumbs","description":"Breadcrumbs from react-fancy","package":"react-fancy","dependencies":["lucide-react"],"registryDependencies":[],"files":[{"path":"components\/fancy\/breadcrumbs\/Breadcrumbs.tsx","content":"import { Children, Fragment, useState, type ReactElement } from \"react\";\r\nimport { ChevronRight } from \"lucide-react\";\r\nimport { cn } from \"..\/..\/utils\/cn\";\r\nimport { BreadcrumbsItem } from \".\/BreadcrumbsItem\";\r\nimport { BreadcrumbsDropdown } from \".\/BreadcrumbsDropdown\";\r\nimport type { BreadcrumbsProps, BreadcrumbsItemProps } from \".\/Breadcrumbs.types\";\r\n\r\nfunction BreadcrumbsRoot({\r\n  children,\r\n  separator,\r\n  shrink,\r\n  className,\r\n}: BreadcrumbsProps) {\r\n  const items = Children.toArray(children);\r\n  const [expanded, setExpanded] = useState(false);\r\n\r\n  const sep = separator ?? (\r\n    <ChevronRight size={12} className=\"text-zinc-400\" \/>\r\n  );\r\n\r\n  const lastItem = items[items.length - 1];\r\n\r\n  \/\/ Extract info from children for mobile dropdown\r\n  const dropdownItems = items.map((child) => {\r\n    const el = child as ReactElement<BreadcrumbsItemProps>;\r\n    return {\r\n      label: el.props?.children,\r\n      href: el.props?.href,\r\n      active: el.props?.active,\r\n    };\r\n  });\r\n\r\n  const activeLabel = dropdownItems[dropdownItems.length - 1]?.label ?? \"Menu\";\r\n\r\n  const showShrunk = shrink && !expanded && items.length > 1;\r\n\r\n  return (\r\n    <>\r\n      {\/* Desktop trail *\/}\r\n      <nav\r\n        data-react-fancy-breadcrumbs=\"\"\r\n        aria-label=\"Breadcrumb\"\r\n        className={cn(\"hidden items-center gap-2 md:flex\", className)}\r\n        onMouseLeave={() => shrink && setExpanded(false)}\r\n      >\r\n        {showShrunk ? (\r\n          <>\r\n            <button\r\n              type=\"button\"\r\n              onClick={() => setExpanded(true)}\r\n              onMouseEnter={() => setExpanded(true)}\r\n              className=\"text-sm text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300\"\r\n            >\r\n              ...\r\n            <\/button>\r\n            <span aria-hidden=\"true\">{sep}<\/span>\r\n            {lastItem}\r\n          <\/>\r\n        ) : (\r\n          items.map((child, i) => (\r\n            <Fragment key={i}>\r\n              {i > 0 && <span aria-hidden=\"true\">{sep}<\/span>}\r\n              {child}\r\n            <\/Fragment>\r\n          ))\r\n        )}\r\n      <\/nav>\r\n\r\n      {\/* Mobile dropdown *\/}\r\n      <BreadcrumbsDropdown items={dropdownItems} activeLabel={activeLabel} \/>\r\n    <\/>\r\n  );\r\n}\r\n\r\nexport const Breadcrumbs = Object.assign(BreadcrumbsRoot, {\r\n  Item: BreadcrumbsItem,\r\n});\r\n","type":"registry:ui","target":"components\/fancy\/breadcrumbs\/Breadcrumbs.tsx"},{"path":"components\/fancy\/breadcrumbs\/Breadcrumbs.types.ts","content":"import type { ReactNode } from \"react\";\r\n\r\nexport interface BreadcrumbsProps {\r\n  children: ReactNode;\r\n  separator?: ReactNode;\r\n  shrink?: boolean;\r\n  className?: string;\r\n}\r\n\r\nexport interface BreadcrumbsItemProps {\r\n  children: ReactNode;\r\n  href?: string;\r\n  active?: boolean;\r\n  className?: string;\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/breadcrumbs\/Breadcrumbs.types.ts"},{"path":"components\/fancy\/breadcrumbs\/BreadcrumbsDropdown.tsx","content":"import { useState, useRef, type ReactNode } from \"react\";\r\nimport { ChevronDown } from \"lucide-react\";\r\nimport { cn } from \"..\/..\/utils\/cn\";\r\nimport { useOutsideClick } from \"..\/..\/hooks\/use-outside-click\";\r\nimport { useEscapeKey } from \"..\/..\/hooks\/use-escape-key\";\r\n\r\ninterface BreadcrumbsDropdownItem {\r\n  label: ReactNode;\r\n  href?: string;\r\n  active?: boolean;\r\n}\r\n\r\ninterface BreadcrumbsDropdownProps {\r\n  items: BreadcrumbsDropdownItem[];\r\n  activeLabel: ReactNode;\r\n}\r\n\r\nexport function BreadcrumbsDropdown({ items, activeLabel }: BreadcrumbsDropdownProps) {\r\n  const [open, setOpen] = useState(false);\r\n  const ref = useRef<HTMLDivElement>(null);\r\n\r\n  useOutsideClick(ref, () => setOpen(false), open);\r\n  useEscapeKey(() => setOpen(false), open);\r\n\r\n  return (\r\n    <div ref={ref} data-react-fancy-breadcrumbs-dropdown=\"\" className=\"relative flex md:hidden\">\r\n      <button\r\n        type=\"button\"\r\n        onClick={() => setOpen((v) => !v)}\r\n        className=\"flex items-center gap-1 rounded-lg px-2 py-1 text-sm font-medium text-zinc-900 hover:bg-zinc-100 dark:text-white dark:hover:bg-zinc-800\"\r\n      >\r\n        {activeLabel}\r\n        <ChevronDown size={14} className={cn(\"transition-transform\", open && \"rotate-180\")} \/>\r\n      <\/button>\r\n      {open && (\r\n        <div className=\"absolute top-full left-0 z-50 mt-1 min-w-[180px] rounded-lg border border-zinc-200 bg-white py-1 shadow-lg dark:border-zinc-700 dark:bg-zinc-900\">\r\n          {items.map((item, i) => {\r\n            const cls = cn(\r\n              \"block w-full px-3 py-1.5 text-left text-sm\",\r\n              item.active\r\n                ? \"font-medium text-zinc-900 dark:text-white\"\r\n                : \"text-zinc-500 hover:bg-zinc-50 hover:text-zinc-700 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-300\",\r\n            );\r\n\r\n            if (item.href && !item.active) {\r\n              return (\r\n                <a key={i} href={item.href} className={cls} onClick={() => setOpen(false)}>\r\n                  {item.label}\r\n                <\/a>\r\n              );\r\n            }\r\n\r\n            return (\r\n              <span key={i} className={cls}>\r\n                {item.label}\r\n              <\/span>\r\n            );\r\n          })}\r\n        <\/div>\r\n      )}\r\n    <\/div>\r\n  );\r\n}\r\n\r\nBreadcrumbsDropdown.displayName = \"BreadcrumbsDropdown\";\r\n","type":"registry:ui","target":"components\/fancy\/breadcrumbs\/BreadcrumbsDropdown.tsx"},{"path":"components\/fancy\/breadcrumbs\/BreadcrumbsItem.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport type { BreadcrumbsItemProps } from \".\/Breadcrumbs.types\";\r\n\r\nexport function BreadcrumbsItem({\r\n  children,\r\n  href,\r\n  active = false,\r\n  className,\r\n}: BreadcrumbsItemProps) {\r\n  const baseClass = cn(\r\n    \"text-sm\",\r\n    active\r\n      ? \"font-medium text-zinc-900 dark:text-white\"\r\n      : \"text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-300\",\r\n    className,\r\n  );\r\n\r\n  if (href && !active) {\r\n    return (\r\n      <a data-react-fancy-breadcrumbs-item=\"\" href={href} className={baseClass}>\r\n        {children}\r\n      <\/a>\r\n    );\r\n  }\r\n\r\n  return (\r\n    <span data-react-fancy-breadcrumbs-item=\"\" className={baseClass} aria-current={active ? \"page\" : undefined}>\r\n      {children}\r\n    <\/span>\r\n  );\r\n}\r\n\r\nBreadcrumbsItem.displayName = \"BreadcrumbsItem\";\r\n","type":"registry:ui","target":"components\/fancy\/breadcrumbs\/BreadcrumbsItem.tsx"},{"path":"components\/fancy\/breadcrumbs\/index.ts","content":"export { Breadcrumbs } from \".\/Breadcrumbs\";\r\nexport type { BreadcrumbsProps, BreadcrumbsItemProps } from \".\/Breadcrumbs.types\";\r\n","type":"registry:ui","target":"components\/fancy\/breadcrumbs\/index.ts"}]}