{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "frame",
  "title": "Frame",
  "description": "A muted frame that holds one or more panels with a header and footer, with nested corners that stay concentric.",
  "dependencies": [
    "class-variance-authority"
  ],
  "files": [
    {
      "path": "registry/tealmac/frame.tsx",
      "content": "/**\n * Frame - adapted for tealmac UI from ReUI \"frame\"\n * (https://github.com/keenthemes/reui), MIT License, Copyright (c) 2025\n * Keenthemes Inc. The full licence text is in THIRD_PARTY_NOTICES.md.\n * Changes: tealmac UI import paths and theme tokens, one self-contained file,\n * lucide icons, a single style, and neutral demo content.\n */\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\n/**\n * Frame sets --frame-panel-bg and --frame-panel-border-color; FramePanel reads\n * them back as bg-(--frame-panel-bg) and border-(--frame-panel-border-color).\n * So variant=\"inverse\" re-points every panel from one place, and a consumer's\n * own bg-* on a panel still wins on source order, with no :not() and no `!`.\n */\nconst frameVariants = cva(\n  [\n    \"relative flex flex-col bg-muted/50 gap-(--frame-gap) px-(--frame-px) py-(--frame-py) rounded-(--frame-radius)\",\n    // Each rung is the radius that style's own shadcn Card resolves through, so\n    // a Frame and a Card side by side agree. lyra/sera are 0px, NOT\n    // var(--radius-none): no such token exists, and it only reached 0 by being\n    // invalid, which also left --frame-radius empty for anything reading it.\n    \"[--frame-radius:var(--radius-xl)]\",\n    \"[--frame-gap:--spacing(0.75)] [--frame-px:--spacing(0.75)] [--frame-py:--spacing(0.75)] [--frame-panel-header-gap:0rem] [--frame-panel-footer-gap:--spacing(1)]\",\n    \"[--frame-panel-px-adjust:0px] [--frame-panel-py-adjust:0px] [--frame-panel-header-px-adjust:0px] [--frame-panel-header-py-adjust:0px] [--frame-panel-footer-px-adjust:0px] [--frame-panel-footer-py-adjust:0px]\",\n    \"[--frame-panel-px:calc(var(--frame-panel-px-base)+var(--frame-panel-px-adjust))] [--frame-panel-py:calc(var(--frame-panel-py-base)+var(--frame-panel-py-adjust))] [--frame-panel-header-px:calc(var(--frame-panel-header-px-base)+var(--frame-panel-header-px-adjust))] [--frame-panel-header-py:calc(var(--frame-panel-header-py-base)+var(--frame-panel-header-py-adjust))] [--frame-panel-footer-px:calc(var(--frame-panel-footer-px-base)+var(--frame-panel-footer-px-adjust))] [--frame-panel-footer-py:calc(var(--frame-panel-footer-py-base)+var(--frame-panel-footer-py-adjust))]\",\n    // Luma alone re-times the frame: wider gap and padding, roomier bars.\n    \"\",\n    \"[--frame-panel-bg:var(--color-card)] [--frame-panel-border-color:var(--color-border)] [--frame-border-color:var(--color-border)]\",\n    // Concentric: the panel nests inside the frame's corner rather than copying\n    // it. It is inset by the 1px border plus --frame-px, so subtracting exactly\n    // that keeps the two arcs parallel. `ghost` drops the border term (no\n    // border), `dense` pins it to the frame radius (panels sit flush).\n    \"[--frame-panel-radius:calc(var(--frame-radius)-var(--frame-px)-1px)]\",\n  ],\n  {\n    variants: {\n      variant: {\n        default: \"border border-[var(--frame-border-color)] bg-clip-padding\",\n        inverse:\n          \"[--frame-panel-bg:color-mix(in_oklch,var(--color-muted)_40%,transparent)] border border-[var(--frame-border-color)] bg-background bg-clip-padding\",\n        ghost:\n          \"[--frame-panel-radius:calc(var(--frame-radius)-var(--frame-px))]\",\n      },\n      // Bars read as chrome, not a second content block: py runs 0.5/1.5/2/2.5\n      // against a body py of 2/3.5/4/5, while px stays level with the body so\n      // header, content and footer left-align. xs floors at 0.5 (2px), below\n      // which it stops reading as padding. No style-*.css overrides these.\n      spacing: {\n        xs: \"[--frame-panel-px-base:--spacing(2)] [--frame-panel-py-base:--spacing(2)] [--frame-panel-header-px-base:--spacing(2)] [--frame-panel-header-py-base:--spacing(0.5)] [--frame-panel-footer-px-base:--spacing(2)] [--frame-panel-footer-py-base:--spacing(0.5)]\",\n        sm: \"[--frame-panel-px-base:--spacing(3)] [--frame-panel-py-base:--spacing(3.5)] [--frame-panel-header-px-base:--spacing(3)] [--frame-panel-header-py-base:--spacing(1.5)] [--frame-panel-footer-px-base:--spacing(3)] [--frame-panel-footer-py-base:--spacing(1.5)]\",\n        default:\n          \"[--frame-panel-px-base:--spacing(4)] [--frame-panel-py-base:--spacing(4)] [--frame-panel-header-px-base:--spacing(4)] [--frame-panel-header-py-base:--spacing(2)] [--frame-panel-footer-px-base:--spacing(4)] [--frame-panel-footer-py-base:--spacing(2)]\",\n        lg: \"[--frame-panel-px-base:--spacing(5)] [--frame-panel-py-base:--spacing(5)] [--frame-panel-header-px-base:--spacing(5)] [--frame-panel-header-py-base:--spacing(2.5)] [--frame-panel-footer-px-base:--spacing(5)] [--frame-panel-footer-py-base:--spacing(2.5)]\",\n      },\n      stacked: {\n        true: [\n          \"gap-0 *:has-[+[data-slot=frame-panel]]:rounded-b-none\",\n          \"*:has-[+[data-slot=frame-panel]]:before:hidden\",\n          \"*:[[data-slot=frame-panel]+[data-slot=frame-panel]]:rounded-t-none\",\n          \"*:[[data-slot=frame-panel]+[data-slot=frame-panel]]:border-t-0\",\n        ],\n        false: [\n          \"data-[spacing=sm]:*:[[data-slot=frame-panel]+[data-slot=frame-panel]]:mt-0.5\",\n          \"data-[spacing=default]:*:[[data-slot=frame-panel]+[data-slot=frame-panel]]:mt-1\",\n          \"data-[spacing=lg]:*:[[data-slot=frame-panel]+[data-slot=frame-panel]]:mt-2\",\n        ],\n      },\n      dense: {\n        // Parent selectors, not CSS vars: these are positional. Panels are\n        // pulled flush (-mx-px), so corners align with the frame's own radius.\n        true: \"p-0 gap-0 border-[var(--frame-border-color)] [--frame-panel-radius:var(--frame-radius)] [&_[data-slot=frame-panel]]:-mx-px [&_[data-slot=frame-panel]]:before:hidden [&_[data-slot=frame-panel]:last-child]:-mb-px [&:not(:has([data-slot=frame-panel-header]))_[data-slot=frame-panel]:is(:first-child)]:-mt-px\",\n        false: \"\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      spacing: \"default\",\n      stacked: false,\n      dense: false,\n    },\n  }\n)\n\nfunction Frame({\n  className,\n  variant,\n  spacing,\n  stacked,\n  dense,\n  ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof frameVariants>) {\n  return (\n    <div\n      className={cn(\n        frameVariants({ variant, spacing, stacked, dense }),\n        className\n      )}\n      data-slot=\"frame\"\n      data-spacing={spacing}\n      {...props}\n    />\n  )\n}\n\nfunction FramePanel({\n  className,\n  fit,\n  ...props\n}: React.ComponentProps<\"div\"> & { fit?: boolean }) {\n  return (\n    <div\n      className={cn(\n        \"relative overflow-hidden rounded-(--frame-panel-radius) border border-(--frame-panel-border-color) bg-(--frame-panel-bg) bg-clip-padding shadow-xs\",\n        /* `fit` sizes the panel to its content; otherwise it grows to fill\n           the frame. */\n        !fit && \"grow\",\n        \"before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--frame-panel-radius)-1px)] before:shadow-black/5\",\n        \"dark:bg-clip-border dark:before:shadow-white/5\",\n        \"px-(--frame-panel-px) py-(--frame-panel-py)\",\n        className\n      )}\n      data-slot=\"frame-panel\"\n      {...props}\n    />\n  )\n}\n\nfunction FrameHeader({ className, ...props }: React.ComponentProps<\"header\">) {\n  return (\n    <header\n      className={cn(\n        \"flex flex-col gap-(--frame-panel-header-gap) px-(--frame-panel-header-px) py-(--frame-panel-header-py)\",\n        className\n      )}\n      data-slot=\"frame-panel-header\"\n      {...props}\n    />\n  )\n}\n\nfunction FrameTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      className={cn(\"text-sm font-semibold\", className)}\n      data-slot=\"frame-panel-title\"\n      {...props}\n    />\n  )\n}\n\nfunction FrameDescription({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      className={cn(\"text-muted-foreground text-sm\", className)}\n      data-slot=\"frame-panel-description\"\n      {...props}\n    />\n  )\n}\n\nfunction FrameFooter({ className, ...props }: React.ComponentProps<\"footer\">) {\n  return (\n    <footer\n      className={cn(\n        \"flex flex-col gap-(--frame-panel-footer-gap) px-(--frame-panel-footer-px) py-(--frame-panel-footer-py)\",\n        className\n      )}\n      data-slot=\"frame-panel-footer\"\n      {...props}\n    />\n  )\n}\n\nexport {\n  Frame,\n  FramePanel,\n  FrameHeader,\n  FrameTitle,\n  FrameDescription,\n  FrameFooter,\n  frameVariants,\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}