{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bento-grid-01",
  "type": "registry:block",
  "title": "Interactive Bento Collection",
  "description": "A responsive Bento card collection with hover and keyboard-revealed actions and an inline detail view, adapted from Magic UI.",
  "author": "Magic UI",
  "registryDependencies": [],
  "dependencies": [
    "cn@0.2.6",
    "lucide-react@0.577.0"
  ],
  "files": [
    {
      "path": "content/components/grid-list/bento-grid-01.tsx",
      "type": "registry:component",
      "target": "@components/uiblocks/bento-grid-01/bento-grid-01.tsx",
      "content": "\"use client\";\n\n/**\n * Adapted from Magic UI's BentoGrid / BentoCard.\n * Copyright (c) Magic UI — MIT License.\n * https://github.com/magicuidesign/magicui/blob/efe76fc5755eca1142dd4f74c1d6f0ace2887e3c/apps/www/registry/magicui/bento-grid.tsx\n * Adaptations: portable Lucide icons and anchors/buttons, responsive columns,\n * keyboard/reduced-motion states, typed host content and an explicit local demo.\n */\nimport { ArrowRight, BookOpen, Files, Inbox, Search, X } from \"lucide-react\";\nimport {\n  useId,\n  useState,\n  useRef,\n  type MouseEvent,\n  type ComponentPropsWithoutRef,\n  type ElementType,\n  type ReactNode,\n} from \"react\";\nimport { cn } from \"./shared/lib/utils\";\n\nexport function BentoGrid({\n  children,\n  className,\n  ...props\n}: ComponentPropsWithoutRef<\"div\">) {\n  return (\n    <div\n      className={cn(\n        \"grid w-full auto-rows-[minmax(22rem,auto)] grid-cols-1 gap-4 md:grid-cols-3\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport type BentoCardProps = Omit<\n  ComponentPropsWithoutRef<\"article\">,\n  \"title\"\n> & {\n  name: string;\n  description: string;\n  background?: ReactNode;\n  Icon?: ElementType;\n  href?: string;\n  cta?: string;\n  onAction?: (event: MouseEvent<HTMLButtonElement>) => void;\n  actionControls?: string;\n  actionExpanded?: boolean;\n};\n\nexport function BentoCard({\n  name,\n  description,\n  background,\n  Icon = Files,\n  href,\n  cta = \"View details\",\n  onAction,\n  actionControls,\n  actionExpanded,\n  className,\n  ...props\n}: BentoCardProps) {\n  const actionable = Boolean(href || onAction);\n  const actionClass =\n    \"pointer-events-auto inline-flex min-h-10 items-center gap-2 rounded-md text-sm font-medium text-foreground outline-offset-4 hover:underline focus-visible:outline-2 focus-visible:outline-ring\";\n  const action = href ? (\n    <a aria-label={`${cta}: ${name}`} className={actionClass} href={href}>\n      {cta}\n      <ArrowRight aria-hidden=\"true\" className=\"size-4\" />\n    </a>\n  ) : (\n    <button\n      aria-label={`${cta}: ${name}`}\n      aria-controls={actionControls}\n      aria-expanded={actionExpanded}\n      className={actionClass}\n      onClick={onAction}\n      type=\"button\"\n    >\n      {cta}\n      <ArrowRight aria-hidden=\"true\" className=\"size-4\" />\n    </button>\n  );\n  return (\n    <article\n      className={cn(\n        \"group relative flex min-h-[22rem] min-w-0 flex-col justify-between overflow-hidden rounded-xl bg-background [box-shadow:0_0_0_1px_rgba(0,0,0,.05),0_2px_4px_rgba(0,0,0,.05),0_12px_24px_rgba(0,0,0,.05)] dark:border dark:[box-shadow:0_-20px_80px_-20px_#ffffff0a_inset]\",\n        className\n      )}\n      {...props}\n    >\n      <div className=\"min-h-0 overflow-hidden\">{background}</div>\n      <div className=\"relative z-10 p-5\">\n        <div\n          className={cn(\n            \"pointer-events-none flex min-w-0 flex-col gap-2 transition-transform duration-300 motion-reduce:transform-none motion-reduce:transition-none\",\n            actionable &&\n              \"lg:pt-10 motion-safe:lg:group-hover:-translate-y-10 motion-safe:lg:group-focus-within:-translate-y-10 lg:motion-reduce:pt-0\"\n          )}\n        >\n          <Icon\n            aria-hidden=\"true\"\n            className=\"mb-1 size-9 origin-left text-muted-foreground transition-transform duration-300 motion-safe:group-hover:scale-90 motion-reduce:transition-none\"\n          />\n          <h3 className=\"break-words text-lg font-semibold tracking-tight\">\n            {name}\n          </h3>\n          <p className=\"max-w-lg text-sm leading-6 text-muted-foreground [overflow-wrap:anywhere]\">\n            {description}\n          </p>\n        </div>\n        {actionable && (\n          <div className=\"mt-2 lg:hidden lg:motion-reduce:block\">{action}</div>\n        )}\n      </div>\n      {actionable && (\n        <div className=\"pointer-events-none absolute bottom-0 z-20 hidden w-full translate-y-10 p-5 opacity-0 transition-all duration-300 group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:translate-y-0 motion-reduce:transition-none lg:flex lg:motion-reduce:hidden\">\n          {action}\n        </div>\n      )}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 transition-colors duration-300 group-hover:bg-muted/20 motion-reduce:transition-none\"\n      />\n    </article>\n  );\n}\n\nexport type BentoFeature = {\n  id: string;\n  name: string;\n  description: string;\n  detail?: string;\n  icon?: ElementType;\n  background?: ReactNode;\n  href?: string;\n  actionLabel?: string;\n  wide?: boolean;\n};\nexport type BentoGrid01Props = {\n  mode?: \"controlled\" | \"demo\";\n  title?: string;\n  description?: string;\n  items?: readonly BentoFeature[];\n  onSelect?: (id: string) => void;\n  className?: string;\n};\n\nconst demoItems: readonly BentoFeature[] = [\n  {\n    id: \"search\",\n    name: \"Find the thread.\",\n    description:\n      \"Keep your team's documents, notes, and decisions within reach.\",\n    detail:\n      \"This is an illustrative search feature card. Supply your actual product content and destinations through items.\",\n    icon: Search,\n    wide: true,\n    background: <DemoDocuments />,\n  },\n  {\n    id: \"collections\",\n    name: \"A place for every idea.\",\n    description:\n      \"Bring related work together in a collection your team understands.\",\n    detail:\n      \"Use background to render a real product screenshot or your own preview component.\",\n    icon: Files,\n    background: <DemoCollections />,\n  },\n  {\n    id: \"inbox\",\n    name: \"Less noise. More focus.\",\n    description: \"A clear view of what's waiting for your attention.\",\n    detail:\n      \"This card displays local demo content only. Connect your own links through each item's href.\",\n    icon: Inbox,\n    background: <DemoInbox />,\n  },\n  {\n    id: \"notes\",\n    name: \"Make room for the next step.\",\n    description: \"Turn a useful note into a shared starting point.\",\n    detail:\n      \"The original Magic UI hover pattern also reveals its action when reached by keyboard.\",\n    icon: BookOpen,\n    wide: true,\n    background: <DemoNotes />,\n  },\n];\n\nexport default function BentoGrid01({\n  mode = \"controlled\",\n  title = \"A clearer place for your work.\",\n  description = \"Bring your product's features into one considered grid.\",\n  items,\n  onSelect,\n  className,\n}: BentoGrid01Props) {\n  const [selectedId, setSelectedId] = useState<string | null>(null);\n  const opener = useRef<HTMLButtonElement | null>(null);\n  const detailsId = useId();\n  const cards = items ?? (mode === \"demo\" ? demoItems : []);\n  const selected = cards.find((item) => item.id === selectedId);\n  return (\n    <section\n      className={cn(\n        \"w-full bg-background px-5 py-12 text-foreground sm:px-8\",\n        className\n      )}\n    >\n      <div className=\"mx-auto max-w-6xl\">\n        <div className=\"mb-8 max-w-2xl\">\n          <p className=\"mb-3 text-xs font-medium uppercase tracking-widest text-muted-foreground\">\n            Feature collection\n          </p>\n          <h2 className=\"break-words text-3xl font-semibold tracking-tight sm:text-4xl\">\n            {title}\n          </h2>\n          <p className=\"mt-3 text-sm leading-7 text-muted-foreground [overflow-wrap:anywhere]\">\n            {description}\n          </p>\n        </div>\n        {mode === \"demo\" && (\n          <p className=\"mb-4 text-xs text-muted-foreground\">\n            Demo content · Illustrative workspace features.\n          </p>\n        )}\n        {cards.length ? (\n          <BentoGrid>\n            {cards.map((item) => (\n              <BentoCard\n                key={item.id}\n                name={item.name}\n                description={item.description}\n                background={item.background}\n                Icon={item.icon}\n                href={item.href}\n                cta={item.actionLabel}\n                className={item.wide ? \"md:col-span-2\" : undefined}\n                onAction={\n                  item.href\n                    ? undefined\n                    : (event) => {\n                        opener.current = event.currentTarget;\n                        setSelectedId(item.id);\n                        onSelect?.(item.id);\n                      }\n                }\n                actionControls={!item.href ? detailsId : undefined}\n                actionExpanded={!item.href ? selectedId === item.id : undefined}\n              />\n            ))}\n          </BentoGrid>\n        ) : (\n          <p className=\"rounded-xl border border-dashed p-8 text-sm text-muted-foreground\">\n            No feature cards supplied. Pass your product's items to populate\n            this grid.\n          </p>\n        )}\n        {selected && (\n          <div\n            aria-label=\"Selected feature details\"\n            aria-live=\"polite\"\n            className=\"mt-5 rounded-xl border bg-muted/20 p-5\"\n            id={detailsId}\n            role=\"region\"\n          >\n            <div className=\"flex items-start justify-between gap-4\">\n              <div>\n                <h3 className=\"font-semibold\">{selected.name}</h3>\n                <p className=\"mt-2 text-sm leading-7 text-muted-foreground [overflow-wrap:anywhere]\">\n                  {selected.detail ?? selected.description}\n                </p>\n              </div>\n              <button\n                aria-label=\"Close feature details\"\n                className=\"grid size-9 shrink-0 place-items-center rounded-md border bg-background focus-visible:outline-2 focus-visible:outline-ring\"\n                onClick={() => {\n                  setSelectedId(null);\n                  opener.current?.focus();\n                }}\n                type=\"button\"\n              >\n                <X className=\"size-4\" />\n              </button>\n            </div>\n          </div>\n        )}\n      </div>\n    </section>\n  );\n}\n\nfunction DemoDocuments() {\n  return (\n    <div\n      aria-hidden=\"true\"\n      className=\"mx-5 mt-5 rounded-lg border bg-muted/20 p-3 text-xs\"\n    >\n      <div className=\"mb-3 flex items-center gap-2 rounded-md border bg-background px-3 py-2 text-muted-foreground\">\n        <Search className=\"size-3.5\" />\n        Search your workspace…\n        <span className=\"ml-auto rounded border px-1.5 text-[10px]\">⌘ K</span>\n      </div>\n      {[\"Product direction\", \"Design review notes\", \"Launch checklist\"].map(\n        (name, i) => (\n          <div\n            className=\"flex items-center gap-3 border-t py-3 first:border-0\"\n            key={name}\n          >\n            <Files className=\"size-4 text-violet-500\" />\n            <span>{name}</span>\n            <span className=\"ml-auto text-[10px] text-muted-foreground\">\n              {i + 1}h ago\n            </span>\n          </div>\n        )\n      )}\n    </div>\n  );\n}\nfunction DemoCollections() {\n  return (\n    <div aria-hidden=\"true\" className=\"m-5 grid grid-cols-2 gap-3 text-xs\">\n      {[\"Research\", \"Design\", \"Engineering\", \"Ideas\"].map((name, i) => (\n        <div\n          className={cn(\n            \"rounded-xl border p-4\",\n            i === 0 ? \"bg-violet-50 dark:bg-violet-950/20\" : \"bg-muted/30\"\n          )}\n          key={name}\n        >\n          <Files className=\"mb-4 size-5 text-muted-foreground\" />\n          <p>{name}</p>\n          <p className=\"mt-1 text-[10px] text-muted-foreground\">\n            {[12, 8, 24, 6][i]} documents\n          </p>\n        </div>\n      ))}\n    </div>\n  );\n}\nfunction DemoInbox() {\n  return (\n    <div aria-hidden=\"true\" className=\"m-5 space-y-3 text-xs\">\n      {[\"Ready for a review\", \"A decision to make\", \"A small win to share\"].map(\n        (name, i) => (\n          <div\n            className=\"flex items-center gap-3 rounded-lg border bg-muted/20 p-3\"\n            key={name}\n          >\n            <span\n              className={cn(\n                \"size-2 rounded-full\",\n                i === 0 ? \"bg-violet-500\" : \"bg-muted-foreground/25\"\n              )}\n            />\n            <span>{name}</span>\n          </div>\n        )\n      )}\n    </div>\n  );\n}\nfunction DemoNotes() {\n  return (\n    <div\n      aria-hidden=\"true\"\n      className=\"mx-5 mt-5 rounded-lg border bg-muted/20 p-5 text-xs\"\n    >\n      <p className=\"text-[10px] uppercase tracking-widest text-muted-foreground\">\n        Project notes / Next chapter\n      </p>\n      <p className=\"mt-3 font-medium\">A few good ideas for what's next.</p>\n      <ul className=\"mt-3 space-y-2 text-muted-foreground\">\n        <li>✓ Start with what people need.</li>\n        <li>✓ Make the important part feel simple.</li>\n        <li>○ Leave a clear next step.</li>\n      </ul>\n    </div>\n  );\n}\n"
    },
    {
      "path": "licenses/bento-grid-01/LICENSE.txt",
      "type": "registry:file",
      "target": "@components/uiblocks/bento-grid-01/LICENSE.txt",
      "content": "Includes source from Blocks.so and its bundled primitives.\nSource: https://github.com/ephraimduncan/blocks\nRevision: 3f759d5171c2391253ec4c772e9e5b3db2bc7c7f\nUIBlocks modifications (block v0.1.0):\n- Replaced Radix arrow icons and asChild buttons with Lucide icons and portable native actions.\n- Added responsive columns, keyboard focus reveal and reduced-motion styles.\n- Added typed host items and detail selection, safe empty defaults and an explicitly labeled fictional-workspace demo.\n\nMIT License\n\nCopyright (c) 2025 Ephraim Duncan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n\nThird-party design: Magic UI\nBlock: bento-grid-01 (v0.1.0)\nSource: https://github.com/magicuidesign/magicui\nAuthor: Magic UI\nRevision: efe76fc5755eca1142dd4f74c1d6f0ace2887e3c\nOriginal files:\n- apps/www/registry/magicui/bento-grid.tsx\nUIBlocks modifications:\n- Replaced Radix arrow icons and asChild buttons with Lucide icons and portable native actions.\n- Added responsive columns, keyboard focus reveal and reduced-motion styles.\n- Added typed host items and detail selection, safe empty defaults and an explicitly labeled fictional-workspace demo.\n\nMIT License\n\nCopyright (c) Magic UI\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
    },
    {
      "path": "lib/utils.ts",
      "type": "registry:component",
      "target": "@components/uiblocks/bento-grid-01/shared/lib/utils.ts",
      "content": "export { cn } from \"cn\";\n"
    }
  ],
  "categories": [
    "grid-list",
    "application",
    "clean-saas"
  ],
  "docs": "Import the default component from @components/uiblocks/bento-grid-01/bento-grid-01.tsx. React 19, Tailwind CSS 4, and the standard shadcn CSS theme variables are required. This block is framework-independent React and works in TanStack Start, Vite, and Next.js projects. Connect links or navigation callbacks to your host application. The live preview opts into mode='demo'; the installed component defaults to controlled data and actions. Supply the host's records and callbacks before enabling service actions. Original design: Magic UI by Magic UI, commit efe76fc5755eca1142dd4f74c1d6f0ace2887e3c, source https://github.com/magicuidesign/magicui. Original paths and local adaptations are recorded in meta.source. The complete upstream MIT notice is bundled in LICENSE.txt; retain it when adapting the component. See https://uiblocks.org/grid-list/bento-grid-01 for content guidelines and source attribution.",
  "meta": {
    "kind": "block",
    "previewProps": {
      "mode": "demo"
    },
    "defaultMode": "controlled",
    "demoMode": "explicit",
    "includesBackend": false,
    "version": "0.1.0",
    "source": {
      "name": "Magic UI",
      "url": "https://github.com/magicuidesign/magicui",
      "license": "MIT",
      "author": "Magic UI",
      "revision": "efe76fc5755eca1142dd4f74c1d6f0ace2887e3c",
      "licenseFile": "licenses/third-party/magic-ui-MIT.txt",
      "files": [
        "apps/www/registry/magicui/bento-grid.tsx"
      ],
      "modifications": [
        "Replaced Radix arrow icons and asChild buttons with Lucide icons and portable native actions.",
        "Added responsive columns, keyboard focus reveal and reduced-motion styles.",
        "Added typed host items and detail selection, safe empty defaults and an explicitly labeled fictional-workspace demo."
      ]
    },
    "license": "MIT",
    "style": "clean-saas",
    "pageType": "application",
    "featured": true,
    "tags": [
      "bento",
      "grid",
      "cards",
      "features",
      "collections",
      "hover",
      "keyboard",
      "便当网格",
      "卡片",
      "功能展示",
      "资源集合"
    ],
    "contentGuidelines": [
      "Pass your own items, content backgrounds and host destinations; the default controlled grid is empty.",
      "Keep titles and descriptions concise so each card retains a clear hierarchy.",
      "Use mode='demo' for the sample workspace only, and check action visibility with keyboard navigation and reduced motion."
    ],
    "recommendedWith": [
      "features-02",
      "hero-01",
      "grid-list-01"
    ],
    "entry": "@components/uiblocks/bento-grid-01/bento-grid-01.tsx",
    "exportName": "default",
    "frameworkIndependent": true,
    "frameworkDependencies": [],
    "compatibleHosts": [
      "react",
      "vite",
      "tanstack-start",
      "nextjs"
    ],
    "requirements": {
      "react": ">=19",
      "tailwind": ">=4"
    },
    "previewUrl": "https://uiblocks.org/preview/bento-grid-01"
  }
}
