{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "inline-attachment",
  "type": "registry:component",
  "title": "InlineAttachment",
  "description": "Inline file and media previews for chat turns.",
  "dependencies": [],
  "registryDependencies": [
    "https://control-ui.dev/r/core.json",
    "https://control-ui.dev/r/effects.json"
  ],
  "files": [
    {
      "path": "src/registry/knob-contracts/inline-attachment-knobs.ts",
      "target": "@components/control-ui/knob-contracts/inline-attachment-knobs.ts",
      "type": "registry:component",
      "content": "// Generated from src/registry/sources/control-ui/recipes/inline-attachment.css by scripts/gen-knob-contracts.ts — run `bun run sync:knobs`.\nexport const inlineAttachmentKnobs = [\n  \"--cui-inline-attachment-radius\",\n  \"--cui-inline-attachment-background\",\n  \"--cui-inline-attachment-ring-color\",\n  \"--cui-inline-attachment-shadow\",\n  \"--cui-inline-attachment-hover-shadow\",\n  \"--cui-inline-attachment-content-radius\",\n  \"--cui-inline-attachment-content-background\",\n  \"--cui-inline-attachment-content-foreground\",\n  \"--cui-inline-attachment-content-shadow\",\n] as const;\nexport type InlineAttachmentKnobStyle = Partial<Record<(typeof inlineAttachmentKnobs)[number], string>>;\n"
    },
    {
      "path": "src/registry/sources/control-ui/inline-attachment.tsx",
      "target": "@components/control-ui/inline-attachment.tsx",
      "type": "registry:component",
      "content": "\"use client\";\n\nimport type { ComponentProps, CSSProperties, ReactNode } from \"react\";\nimport { createContext, useContext } from \"react\";\n\nimport type { InlineAttachmentKnobStyle } from \"@/components/control-ui/knob-contracts/inline-attachment-knobs\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\n\nexport type InlineAttachmentState = \"ready\" | \"pending\" | \"error\";\n\ntype InlineAttachmentContextValue = { name: string; state: InlineAttachmentState };\n\ntype InlineAttachmentStyle = CSSProperties & InlineAttachmentKnobStyle;\ntype InlineAttachmentStyleProps<Props, Style> = Omit<Props, \"style\"> & { style?: CSSProperties & Style };\n\nconst InlineAttachmentContext = createContext<InlineAttachmentContextValue | null>(null);\n\nfunction useInlineAttachmentContext() {\n  const context = useContext(InlineAttachmentContext);\n  if (!context) throw new Error(\"InlineAttachment compound components must be rendered inside <InlineAttachment>.\");\n  return context;\n}\n\nfunction defaultLabel(name: string, state: InlineAttachmentState) {\n  if (state === \"pending\") return `Generating ${name}`;\n  if (state === \"error\") return `${name} is unavailable`;\n  return `Open attachment: ${name}`;\n}\n\nexport type InlineAttachmentProps = InlineAttachmentStyleProps<ComponentProps<\"button\">, InlineAttachmentKnobStyle> & {\n  name: string;\n  state?: InlineAttachmentState;\n  /** Width-to-height ratio of the reserved box — generated media knows its ratio before its pixels, so arrival never reflows the turn. */\n  aspect?: number;\n};\n\nexport function InlineAttachment({\n  name,\n  state = \"ready\",\n  aspect = 1.26,\n  disabled,\n  className,\n  children,\n  style,\n  \"aria-label\": ariaLabel,\n  ...props\n}: InlineAttachmentProps) {\n  const attachmentStyle = { aspectRatio: aspect, ...style } satisfies InlineAttachmentStyle;\n\n  return (\n    <InlineAttachmentContext.Provider value={{ name, state }}>\n      <button\n        type=\"button\"\n        aria-label={ariaLabel ?? defaultLabel(name, state)}\n        aria-busy={state === \"pending\" || undefined}\n        disabled={disabled || state === \"pending\"}\n        data-control-ui=\"inline-attachment\"\n        data-control-family=\"inline-attachment\"\n        data-slot=\"root\"\n        data-surface=\"panel\"\n        data-state={state}\n        className={cn(\"group relative w-full max-w-72 cursor-pointer overflow-hidden disabled:cursor-default\", className)}\n        style={attachmentStyle}\n        {...props}\n      >\n        {children}\n      </button>\n    </InlineAttachmentContext.Provider>\n  );\n}\n\nexport type InlineAttachmentMediaProps = ComponentProps<\"div\"> & {\n  src?: string;\n  alt?: string;\n} & { style?: CSSProperties & InlineAttachmentKnobStyle };\n\nfunction GeneratingPlaceholder() {\n  return (\n    <div\n      aria-hidden=\"true\"\n      data-control-ui=\"inline-attachment\"\n      data-control-family=\"inline-attachment\"\n      data-slot=\"placeholder\"\n      className={cn(\"size-full\", \"halftone\")}\n    />\n  );\n}\n\nfunction DocumentPlaceholder() {\n  return (\n    <div data-control-ui=\"inline-attachment\" data-control-family=\"inline-attachment\" data-slot=\"document\" className=\"size-full p-5\">\n      <div data-control-ui=\"inline-attachment\" data-control-family=\"inline-attachment\" data-slot=\"document-sheet\" className=\"h-full p-4\">\n        <div\n          data-control-ui=\"inline-attachment\"\n          data-control-family=\"inline-attachment\"\n          data-slot=\"document-heading\"\n          className=\"h-2 w-20\"\n        />\n        <div className=\"mt-5 grid gap-2\">\n          <div\n            data-control-ui=\"inline-attachment\"\n            data-control-family=\"inline-attachment\"\n            data-slot=\"document-line\"\n            data-width=\"long\"\n            className=\"h-1.5 w-44\"\n          />\n          <div\n            data-control-ui=\"inline-attachment\"\n            data-control-family=\"inline-attachment\"\n            data-slot=\"document-line\"\n            data-width=\"medium\"\n            className=\"h-1.5 w-36\"\n          />\n          <div\n            data-control-ui=\"inline-attachment\"\n            data-control-family=\"inline-attachment\"\n            data-slot=\"document-line\"\n            data-width=\"longest\"\n            className=\"h-1.5 w-48\"\n          />\n          <div\n            data-control-ui=\"inline-attachment\"\n            data-control-family=\"inline-attachment\"\n            data-slot=\"document-line\"\n            data-width=\"short\"\n            className=\"h-1.5 w-28\"\n          />\n        </div>\n        <div\n          data-control-ui=\"inline-attachment\"\n          data-control-family=\"inline-attachment\"\n          data-slot=\"document-stamp\"\n          className=\"mt-5 h-9 w-24\"\n        />\n      </div>\n    </div>\n  );\n}\n\nfunction mediaContent({ state, src, alt, children }: { state: InlineAttachmentState; src?: string; alt: string; children?: ReactNode }) {\n  if (state === \"pending\") return <GeneratingPlaceholder />;\n  if (src) {\n    return (\n      <img\n        src={src}\n        alt={alt}\n        loading=\"lazy\"\n        decoding=\"async\"\n        data-control-ui=\"inline-attachment\"\n        data-control-family=\"inline-attachment\"\n        data-slot=\"media-image\"\n        className=\"size-full object-cover\"\n      />\n    );\n  }\n  return children ?? <DocumentPlaceholder />;\n}\n\nexport function InlineAttachmentMedia({ src, alt, className, children, ...props }: InlineAttachmentMediaProps) {\n  const { name, state } = useInlineAttachmentContext();\n\n  return (\n    <div\n      data-control-ui=\"inline-attachment\"\n      data-control-family=\"inline-attachment\"\n      data-slot=\"image\"\n      className={cn(\"size-full\", className)}\n      {...props}\n    >\n      {mediaContent({ state, src, alt: alt ?? name, children })}\n    </div>\n  );\n}\n\nexport type InlineAttachmentContentProps = InlineAttachmentStyleProps<ComponentProps<\"div\">, InlineAttachmentKnobStyle>;\n\nexport function InlineAttachmentContent({ className, ...props }: InlineAttachmentContentProps) {\n  return (\n    <div\n      data-control-ui=\"inline-attachment\"\n      data-control-family=\"inline-attachment\"\n      data-slot=\"content\"\n      className={cn(\"absolute inset-x-3 bottom-3 px-3 py-1\", className)}\n      {...props}\n    />\n  );\n}\n\nexport type InlineAttachmentTitleProps = ComponentProps<\"div\"> & { style?: CSSProperties & InlineAttachmentKnobStyle };\n\nexport function InlineAttachmentTitle({ children, className, ...props }: InlineAttachmentTitleProps) {\n  const { name } = useInlineAttachmentContext();\n\n  return (\n    <div\n      data-control-ui=\"inline-attachment\"\n      data-control-family=\"inline-attachment\"\n      data-slot=\"title\"\n      className={cn(\"truncate\", className)}\n      {...props}\n    >\n      {children ?? name}\n    </div>\n  );\n}\n\nexport type InlineAttachmentDescriptionProps = InlineAttachmentStyleProps<ComponentProps<\"div\">, InlineAttachmentKnobStyle>;\n\nexport function InlineAttachmentDescription({ className, ...props }: InlineAttachmentDescriptionProps) {\n  return (\n    <div\n      data-control-ui=\"inline-attachment\"\n      data-control-family=\"inline-attachment\"\n      data-slot=\"description\"\n      className={cn(\"truncate\", className)}\n      {...props}\n    />\n  );\n}\n\nexport type InlineAttachmentActionsProps = ComponentProps<\"div\"> & { style?: CSSProperties & InlineAttachmentKnobStyle };\n\nexport function InlineAttachmentActions({ className, ...props }: InlineAttachmentActionsProps) {\n  return (\n    <div\n      data-control-ui=\"inline-attachment\"\n      data-control-family=\"inline-attachment\"\n      data-slot=\"actions\"\n      className={cn(\"mt-1 flex items-center gap-1\", className)}\n      {...props}\n    />\n  );\n}\n\nexport type InlineAttachmentActionProps = InlineAttachmentStyleProps<ComponentProps<\"span\">, InlineAttachmentKnobStyle>;\n\nexport function InlineAttachmentAction({ className, ...props }: InlineAttachmentActionProps) {\n  return (\n    <span\n      data-control-ui=\"inline-attachment\"\n      data-control-family=\"inline-attachment\"\n      data-slot=\"action\"\n      className={cn(\"px-1.5 py-0.5\", className)}\n      {...props}\n    />\n  );\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/inline-attachment.css",
      "target": "@components/control-ui/styles/recipes/inline-attachment.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"root\"]) {\n    --cui-inline-attachment-background: var(--muted);\n    --cui-inline-attachment-hover-shadow: var(--shadow-md);\n    --cui-inline-attachment-radius: var(--radius-scene);\n    --cui-inline-attachment-ring-color: var(--border);\n    --cui-inline-attachment-shadow: var(--shadow-sm);\n    --cui-inline-attachment-content-background: oklch(from var(--background) l c h / 0.85);\n    --cui-inline-attachment-content-foreground: var(--foreground);\n    --cui-inline-attachment-content-radius: var(--radius-control);\n    --cui-inline-attachment-content-shadow: var(--shadow-sm);\n    --_inline-attachment-media-hover-scale: 1.02;\n    border-radius: var(--cui-inline-attachment-radius);\n    background: var(--cui-inline-attachment-background);\n    box-shadow:\n      inset 0 0 0 1px var(--cui-inline-attachment-ring-color),\n      var(--cui-inline-attachment-shadow);\n    transition: box-shadow var(--duration-fast) var(--ease-standard);\n    text-align: left;\n  }\n\n  @media (hover: hover) {\n    :where([data-control-family=\"inline-attachment\"][data-slot=\"root\"]:hover) {\n      box-shadow:\n        inset 0 0 0 1px var(--cui-inline-attachment-ring-color),\n        var(--cui-inline-attachment-hover-shadow);\n    }\n\n    :where([data-control-family=\"inline-attachment\"][data-slot=\"root\"]:disabled:hover) {\n      box-shadow:\n        inset 0 0 0 1px var(--cui-inline-attachment-ring-color),\n        var(--cui-inline-attachment-shadow);\n    }\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"media-image\"]) {\n    transition: scale var(--duration-slow) var(--ease-standard);\n  }\n\n  @media (hover: hover) {\n    :where([data-control-family=\"inline-attachment\"][data-slot=\"root\"]:hover [data-slot=\"media-image\"]) {\n      scale: var(--_inline-attachment-media-hover-scale);\n    }\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"document\"]) {\n    background: linear-gradient(135deg in srgb, var(--color-slate-50) 0%, var(--color-zinc-100) 46%, var(--color-stone-200) 100%);\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"document-sheet\"]) {\n    border-radius: 1rem;\n    background: oklch(from var(--card) l c h / 0.78);\n    box-shadow:\n      inset 0 0 0 1px oklch(from var(--foreground) l c h / 0.1),\n      var(--shadow-sm);\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"document-heading\"]) {\n    border-radius: 9999px;\n    background: oklch(from var(--foreground) l c h / 0.12);\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"document-line\"]) {\n    border-radius: 9999px;\n    background: oklch(from var(--foreground) l c h / 0.12);\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"document-line\"][data-width=\"medium\"]) {\n    background: oklch(from var(--foreground) l c h / 0.12);\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"document-line\"][data-width=\"longest\"]) {\n    background: oklch(from var(--foreground) l c h / 0.14);\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"document-line\"][data-width=\"short\"]) {\n    background: oklch(from var(--foreground) l c h / 0.1);\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"document-stamp\"]) {\n    border: 1px dashed oklch(from var(--foreground) l c h / 0.18);\n    border-radius: 0.75rem;\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"content\"]) {\n    border-radius: var(--cui-inline-attachment-content-radius);\n    background: var(--cui-inline-attachment-content-background);\n    color: var(--cui-inline-attachment-content-foreground);\n    box-shadow: var(--cui-inline-attachment-content-shadow);\n    backdrop-filter: blur(var(--backdrop-blur-popover));\n    font-size: var(--text-caption);\n    font-weight: var(--font-weight-medium);\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"description\"]) {\n    font-size: var(--text-micro);\n    opacity: 0.65;\n  }\n\n  :where([data-control-family=\"inline-attachment\"][data-slot=\"action\"]) {\n    border-radius: var(--radius-control);\n    background: oklch(from var(--foreground) l c h / 0.08);\n    font-size: var(--text-micro);\n  }\n}\n\n@property --cui-inline-attachment-radius {\n  syntax: \"<length>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-inline-attachment-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-inline-attachment-ring-color {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-inline-attachment-shadow {\n  syntax: \"*\";\n  inherits: true;\n}\n\n@property --cui-inline-attachment-hover-shadow {\n  syntax: \"*\";\n  inherits: true;\n}\n\n@property --cui-inline-attachment-content-radius {\n  syntax: \"<length>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-inline-attachment-content-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-inline-attachment-content-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-inline-attachment-content-shadow {\n  syntax: \"*\";\n  inherits: true;\n}\n"
    }
  ],
  "css": {
    "@import \"../components/control-ui/styles/recipes/inline-attachment.css\"": {}
  },
  "meta": {}
}
