{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "gummy-card",
  "type": "registry:ui",
  "title": "Gummy Card",
  "description": "Composable passive, link, and button Card roots with a continuous gel-pocket SVG frame, selected state, and responsive content slots.",
  "registryDependencies": [
    "https://gummyui.dev/r/gummy-core-styles.json"
  ],
  "files": [
    {
      "path": "components/ui/GummyCard.tsx",
      "type": "registry:ui",
      "content": "import * as React from \"react\";\n\nexport type GummyCardElevation = \"default\" | \"elevated\";\n\ntype CardVisualProps = {\n  elevation?: GummyCardElevation;\n  selected?: boolean;\n};\n\nexport type GummyCardProps = Omit<\n  React.HTMLAttributes<HTMLElement>,\n  \"onClick\" | \"onKeyDown\" | \"onKeyUp\" | \"tabIndex\" | \"role\"\n> & CardVisualProps;\nexport type GummyCardLinkProps = React.AnchorHTMLAttributes<HTMLAnchorElement> & CardVisualProps;\nexport type GummyCardButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & CardVisualProps;\nexport type GummyCardTitleProps = React.HTMLAttributes<HTMLHeadingElement> & {\n  /** Selects the heading level required by the surrounding document outline. */\n  level?: 2 | 3 | 4 | 5 | 6;\n};\n\nfunction joinClassNames(...values: Array<string | false | null | undefined>) {\n  return values.filter(Boolean).join(\" \");\n}\n\nfunction visualAttributes(elevation: GummyCardElevation, selected: boolean) {\n  return {\n    \"data-elevation\": elevation,\n    \"data-selected\": selected || undefined,\n  };\n}\n\nfunction CardFrame() {\n  const frameId = React.useId().replaceAll(\":\", \"\");\n  const frameRef = React.useRef<SVGSVGElement>(null);\n  const [frameSize, setFrameSize] = React.useState({ width: 540, height: 330 });\n  const shellGradientId = `${frameId}-shell`;\n  const planeGradientId = `${frameId}-plane`;\n  const reservoirGradientId = `${frameId}-reservoir`;\n  const blurId = `${frameId}-blur`;\n\n  React.useEffect(() => {\n    const frame = frameRef.current;\n    if (!frame || typeof ResizeObserver === \"undefined\") return;\n\n    const measure = () => {\n      const bounds = frame.getBoundingClientRect();\n      const next = {\n        width: Math.max(300, Math.round(bounds.width)),\n        height: Math.max(240, Math.round(bounds.height)),\n      };\n\n      setFrameSize((current) => (\n        current.width === next.width && current.height === next.height ? current : next\n      ));\n    };\n\n    measure();\n    const observer = new ResizeObserver(measure);\n    observer.observe(frame);\n    return () => observer.disconnect();\n  }, []);\n\n  const width = frameSize.width;\n  const height = frameSize.height;\n  const outerPath = [\n    \"M72 10C105 15 132 12 168 13\",\n    `H${width - 48}C${width - 20} 13 ${width - 10} 31 ${width - 12} 58`,\n    `L${width - 16} ${height - 74}`,\n    `C${width - 16} ${height - 56} ${width - 4} ${height - 51} ${width - 3} ${height - 33}`,\n    `C${width - 2} ${height - 10} ${width - 18} ${height - 3} ${width - 40} ${height - 4}`,\n    `C${width - 62} ${height - 5} ${width - 71} ${height - 15} ${width - 94} ${height - 12}`,\n    `H50C22 ${height - 12} 12 ${height - 28} 14 ${height - 54}`,\n    \"L9 58C8 29 24 9 51 8C59 8 65 10 72 10Z\",\n  ].join(\"\");\n  const planePath = [\n    \"M120 32C137 25 157 27 178 27\",\n    `H${width - 47}C${width - 28} 27 ${width - 23} 41 ${width - 24} 61`,\n    `L${width - 28} ${height - 84}`,\n    `C${width - 28} ${height - 69} ${width - 36} ${height - 62} ${width - 51} ${height - 57}`,\n    `C${width - 64} ${height - 53} ${width - 72} ${height - 37} ${width - 88} ${height - 32}`,\n    `C${width - 98} ${height - 29} ${width - 111} ${height - 28} ${width - 131} ${height - 27}`,\n    `H47C31 ${height - 27} 27 ${height - 38} 28 ${height - 54}`,\n    \"L25 99C25 84 31 77 39 79C43 105 61 121 84 119C109 118 124 98 121 74C118 56 111 41 120 32Z\",\n  ].join(\"\");\n  const reservoirPath = [\n    `M${width - 105} ${height - 35}`,\n    `C${width - 91} ${height - 55} ${width - 66} ${height - 67} ${width - 43} ${height - 59}`,\n    `C${width - 20} ${height - 51} ${width - 10} ${height - 26} ${width - 27} ${height - 10}`,\n    `C${width - 43} ${height + 1} ${width - 67} ${height - 8} ${width - 96} ${height - 13}`,\n    `C${width - 104} ${height - 19} ${width - 108} ${height - 27} ${width - 105} ${height - 35}Z`,\n  ].join(\"\");\n  const reservoirGlintPath = `M${width - 88} ${height - 43}C${width - 72} ${height - 57} ${width - 50} ${height - 57} ${width - 37} ${height - 46}`;\n\n  return (\n    <svg\n      ref={frameRef}\n      className=\"gummy-card__frame\"\n      viewBox={`0 0 ${width} ${height}`}\n      preserveAspectRatio=\"none\"\n      aria-hidden=\"true\"\n      focusable=\"false\"\n    >\n      <defs>\n        <linearGradient id={shellGradientId} x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"var(--card-frame-light)\" />\n          <stop offset=\"0.42\" stopColor=\"var(--card-frame-core)\" />\n          <stop offset=\"1\" stopColor=\"var(--card-frame-rim)\" />\n        </linearGradient>\n        <linearGradient id={planeGradientId} x1=\"0.12\" y1=\"0\" x2=\"0.9\" y2=\"1\">\n          <stop offset=\"0\" stopColor=\"var(--card-plane-light)\" />\n          <stop offset=\"1\" stopColor=\"var(--card-plane-core)\" />\n        </linearGradient>\n        <radialGradient id={reservoirGradientId} cx=\"0.28\" cy=\"0.2\" r=\"0.9\">\n          <stop offset=\"0\" stopColor=\"var(--card-frame-light)\" />\n          <stop offset=\"0.58\" stopColor=\"var(--card-frame-core)\" />\n          <stop offset=\"1\" stopColor=\"var(--card-frame-depth)\" />\n        </radialGradient>\n        <filter id={blurId} x=\"-20%\" y=\"-30%\" width=\"150%\" height=\"170%\">\n          <feGaussianBlur stdDeviation=\"8\" />\n        </filter>\n      </defs>\n\n      <path\n        className=\"gummy-card__frame-shadow\"\n        d={outerPath}\n        filter={`url(#${blurId})`}\n      />\n      <path\n        className=\"gummy-card__frame-shell\"\n        d={outerPath}\n        fill={`url(#${shellGradientId})`}\n      />\n      <path\n        className=\"gummy-card__frame-plane\"\n        d={planePath}\n        fill={`url(#${planeGradientId})`}\n      />\n      <path\n        className=\"gummy-card__frame-reservoir\"\n        d={reservoirPath}\n        fill={`url(#${reservoirGradientId})`}\n      />\n      <path\n        className=\"gummy-card__frame-meniscus gummy-card__frame-meniscus--outer\"\n        d={outerPath}\n      />\n      <path\n        className=\"gummy-card__frame-meniscus gummy-card__frame-meniscus--inner\"\n        d={planePath}\n      />\n      <path\n        className=\"gummy-card__icon-well\"\n        d=\"M42 68C40 40 57 21 83 21C110 21 126 41 124 69C122 99 106 117 83 118C58 118 43 97 42 68Z\"\n      />\n      <path\n        className=\"gummy-card__frame-glint\"\n        d=\"M28 56C34 28 54 18 82 22C116 27 135 20 172 24\"\n      />\n      <path\n        className=\"gummy-card__reservoir-glint\"\n        d={reservoirGlintPath}\n      />\n    </svg>\n  );\n}\n\nexport const GummyCard = React.forwardRef<HTMLElement, GummyCardProps>(\n  function GummyCard(\n    {\n      elevation = \"default\",\n      selected = false,\n      className,\n      children,\n      ...cardProps\n    },\n    ref,\n  ) {\n    return (\n      <article\n        {...cardProps}\n        {...visualAttributes(elevation, selected)}\n        ref={ref}\n        className={joinClassNames(\"gummy-card\", className)}\n      >\n        <CardFrame />\n        {children}\n      </article>\n    );\n  },\n);\n\nGummyCard.displayName = \"GummyCard\";\n\nexport const GummyCardLink = React.forwardRef<HTMLAnchorElement, GummyCardLinkProps>(\n  function GummyCardLink(\n    {\n      elevation = \"default\",\n      selected = false,\n      className,\n      children,\n      ...linkProps\n    },\n    ref,\n  ) {\n    return (\n      <a\n        {...linkProps}\n        {...visualAttributes(elevation, selected)}\n        ref={ref}\n        className={joinClassNames(\"gummy-card gummy-card--interactive\", className)}\n        data-interactive=\"link\"\n      >\n        <CardFrame />\n        {children}\n      </a>\n    );\n  },\n);\n\nGummyCardLink.displayName = \"GummyCardLink\";\n\nexport const GummyCardButton = React.forwardRef<HTMLButtonElement, GummyCardButtonProps>(\n  function GummyCardButton(\n    {\n      elevation = \"default\",\n      selected = false,\n      type = \"button\",\n      className,\n      children,\n      ...buttonProps\n    },\n    ref,\n  ) {\n    return (\n      <button\n        {...buttonProps}\n        {...visualAttributes(elevation, selected)}\n        ref={ref}\n        type={type}\n        className={joinClassNames(\"gummy-card gummy-card--interactive\", className)}\n        data-interactive=\"button\"\n      >\n        <CardFrame />\n        {children}\n      </button>\n    );\n  },\n);\n\nGummyCardButton.displayName = \"GummyCardButton\";\n\nexport const GummyCardIcon = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(function GummyCardIcon({ className, ...props }, ref) {\n  return <div {...props} ref={ref} className={joinClassNames(\"gummy-card__icon\", className)} />;\n});\n\nGummyCardIcon.displayName = \"GummyCardIcon\";\n\nexport const GummyCardHeader = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(function GummyCardHeader({ className, ...props }, ref) {\n  return <div {...props} ref={ref} className={joinClassNames(\"gummy-card__header\", className)} />;\n});\n\nGummyCardHeader.displayName = \"GummyCardHeader\";\n\nexport const GummyCardTitle = React.forwardRef<\n  HTMLHeadingElement,\n  GummyCardTitleProps\n>(function GummyCardTitle({ className, level = 3, ...props }, ref) {\n  const Heading = `h${level}` as const;\n  return React.createElement(Heading, {\n    ...props,\n    ref,\n    className: joinClassNames(\"gummy-card__title\", className),\n  });\n});\n\nGummyCardTitle.displayName = \"GummyCardTitle\";\n\nexport const GummyCardDescription = React.forwardRef<\n  HTMLParagraphElement,\n  React.HTMLAttributes<HTMLParagraphElement>\n>(function GummyCardDescription({ className, ...props }, ref) {\n  return <p {...props} ref={ref} className={joinClassNames(\"gummy-card__description\", className)} />;\n});\n\nGummyCardDescription.displayName = \"GummyCardDescription\";\n\nexport const GummyCardContent = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(function GummyCardContent({ className, ...props }, ref) {\n  return <div {...props} ref={ref} className={joinClassNames(\"gummy-card__content\", className)} />;\n});\n\nGummyCardContent.displayName = \"GummyCardContent\";\n\nexport const GummyCardFooter = React.forwardRef<\n  HTMLDivElement,\n  React.HTMLAttributes<HTMLDivElement>\n>(function GummyCardFooter({ className, ...props }, ref) {\n  return <div {...props} ref={ref} className={joinClassNames(\"gummy-card__footer\", className)} />;\n});\n\nGummyCardFooter.displayName = \"GummyCardFooter\";\n"
    }
  ]
}
