{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "message",
  "title": "Message",
  "description": "A chat message row with an avatar, name, bubbles and status, where new messages rise in from the sender's side.",
  "dependencies": [
    "@base-ui/react@^1.8.0",
    "cn"
  ],
  "registryDependencies": [
    "https://hextaui.com/r/theme.json",
    "https://hextaui.com/r/bubble.json",
    "https://hextaui.com/r/avatar.json"
  ],
  "files": [
    {
      "path": "components/ui/message.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { cn } from \"cn\"\n\nimport { BubbleAlignContext } from \"@/components/ui/bubble\"\n\ntype MessageAlign = \"start\" | \"end\"\n\nconst MessageGroupContext = React.createContext<{ ready: boolean } | null>(null)\n\nfunction dataAttributes(slot: string, extra?: Record<string, string>) {\n  return { \"data-slot\": slot, ...extra } as Record<string, string>\n}\n\nfunction MessageGroup({\n  className,\n  render,\n  ...props\n}: useRender.ComponentProps<\"div\">) {\n  const [ready, setReady] = React.useState(false)\n\n  React.useEffect(() => {\n    setReady(true)\n  }, [])\n\n  const context = React.useMemo(() => ({ ready }), [ready])\n\n  const element = useRender({\n    defaultTagName: \"div\",\n    render,\n    props: mergeProps<\"div\">(\n      { className: cn(\"flex min-w-0 flex-col gap-4\", className) },\n      props,\n      dataAttributes(\"message-group\")\n    ),\n  })\n\n  return (\n    <MessageGroupContext.Provider value={context}>\n      {element}\n    </MessageGroupContext.Provider>\n  )\n}\n\ntype MessageProps = useRender.ComponentProps<\"div\"> & {\n  align?: MessageAlign\n  animated?: boolean\n}\n\nfunction Message({\n  className,\n  align = \"start\",\n  animated = true,\n  render,\n  children,\n  ...props\n}: MessageProps) {\n  const group = React.useContext(MessageGroupContext)\n  const [entering] = React.useState(() => Boolean(animated && group?.ready))\n\n  const element = useRender({\n    defaultTagName: \"div\",\n    render,\n    props: mergeProps<\"div\">(\n      {\n        className: cn(\n          \"group/message relative flex w-full min-w-0 items-end gap-2 text-sm data-entering:origin-bottom-left data-[align=end]:flex-row-reverse data-[align=end]:data-entering:origin-bottom-right data-entering:motion-safe:animate-message-in motion-reduce:data-entering:animate-in motion-reduce:data-entering:fade-in-0 rtl:data-entering:origin-bottom-right rtl:data-[align=end]:data-entering:origin-bottom-left\",\n          className\n        ),\n        children: (\n          <BubbleAlignContext.Provider value={align}>\n            {children}\n          </BubbleAlignContext.Provider>\n        ),\n      },\n      props,\n      dataAttributes(\"message\", {\n        \"data-align\": align,\n        ...(entering ? { \"data-entering\": \"\" } : {}),\n      })\n    ),\n  })\n\n  return element\n}\n\nfunction MessageAvatar({\n  className,\n  render,\n  ...props\n}: useRender.ComponentProps<\"div\">) {\n  return useRender({\n    defaultTagName: \"div\",\n    render,\n    props: mergeProps<\"div\">(\n      {\n        className: cn(\n          \"flex w-fit min-w-8 shrink-0 items-center justify-center self-end overflow-hidden rounded-full group-has-[[data-slot=message-footer]]/message:mb-[calc(var(--spacing)*4+var(--spacing)*1.5)] [&>img]:size-8 [&>img]:object-cover [&>svg]:size-8 [&>svg]:rounded-full [&>svg]:bg-muted [&>svg]:p-2 [&>svg]:text-foreground\",\n          className\n        ),\n      },\n      props,\n      dataAttributes(\"message-avatar\")\n    ),\n  })\n}\n\nfunction MessageContent({\n  className,\n  render,\n  ...props\n}: useRender.ComponentProps<\"div\">) {\n  return useRender({\n    defaultTagName: \"div\",\n    render,\n    props: mergeProps<\"div\">(\n      {\n        className: cn(\n          \"flex w-full min-w-0 flex-col gap-1.5 wrap-break-word\",\n          className\n        ),\n      },\n      props,\n      dataAttributes(\"message-content\")\n    ),\n  })\n}\n\nconst metaClassName =\n  \"flex max-w-full min-w-0 items-center gap-1.5 px-3 text-xs font-medium text-muted-foreground group-has-[[data-variant=ghost]]/message:px-0 group-data-[align=start]/message:group-has-[[data-shape=tail]]/message:ps-[calc(var(--spacing)*4.5)] group-data-[align=end]/message:group-has-[[data-shape=tail]]/message:pe-[calc(var(--spacing)*4.5)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5\"\n\nfunction MessageHeader({\n  className,\n  render,\n  ...props\n}: useRender.ComponentProps<\"div\">) {\n  return useRender({\n    defaultTagName: \"div\",\n    render,\n    props: mergeProps<\"div\">(\n      {\n        className: cn(\n          metaClassName,\n          \"min-h-4 group-data-[align=end]/message:justify-end\",\n          className\n        ),\n      },\n      props,\n      dataAttributes(\"message-header\")\n    ),\n  })\n}\n\nfunction MessageFooter({\n  className,\n  render,\n  ...props\n}: useRender.ComponentProps<\"div\">) {\n  return useRender({\n    defaultTagName: \"div\",\n    render,\n    props: mergeProps<\"div\">(\n      {\n        className: cn(\n          metaClassName,\n          \"h-4 overflow-hidden whitespace-nowrap group-data-[align=end]/message:justify-end\",\n          className\n        ),\n      },\n      props,\n      dataAttributes(\"message-footer\")\n    ),\n  })\n}\n\nexport {\n  Message,\n  MessageAvatar,\n  MessageContent,\n  MessageFooter,\n  MessageGroup,\n  MessageHeader,\n}\nexport type { MessageAlign, MessageProps }\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "chat"
  ],
  "type": "registry:ui"
}