{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"bubble","title":"Bubble","description":"A chat message bubble for conversation UIs, with sender alignment, tonal variants, grouped messages, and emoji reactions.","dependencies":["cn","@base-ui/react","class-variance-authority"],"files":[{"path":"components/ui/bubble.tsx","content":"import * as React from \"react\"\nimport { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"cn\"\n\nfunction BubbleGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"bubble-group\"\n      className={cn(\"flex min-w-0 flex-col gap-2\", className)}\n      {...props}\n    />\n  )\n}\n\nconst bubbleVariants = cva(\n  \"group/bubble relative flex w-fit max-w-[min(80%,--spacing(80))] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"*:data-[slot=bubble-content]:bg-card *:data-[slot=bubble-content]:bg-linear-to-b *:data-[slot=bubble-content]:from-white/5 *:data-[slot=bubble-content]:to-transparent *:data-[slot=bubble-content]:text-card-foreground *:data-[slot=bubble-content]:shadow-(--shadow-secondary-control) *:data-[slot=bubble-content]:inset-ring-1 *:data-[slot=bubble-content]:inset-ring-border [&>[data-slot=bubble-content]:is(button,a):hover]:bg-control-hover\",\n        secondary:\n          \"*:data-[slot=bubble-content]:bg-fill-1 *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-fill-2\",\n        muted:\n          \"*:data-[slot=bubble-content]:bg-fill-2 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-fill-3\",\n        tinted:\n          \"*:data-[slot=bubble-content]:bg-primary/20 *:data-[slot=bubble-content]:text-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/25\",\n        outline:\n          \"*:data-[slot=bubble-content]:border *:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background *:data-[slot=bubble-content]:px-2.75 *:data-[slot=bubble-content]:py-1.75 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-fill-2 [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground\",\n        ghost:\n          \"border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:border-0 *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-fill-2 [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground\",\n        destructive:\n          \"*:data-[slot=bubble-content]:bg-card *:data-[slot=bubble-content]:bg-linear-to-b *:data-[slot=bubble-content]:from-white/5 *:data-[slot=bubble-content]:to-transparent *:data-[slot=bubble-content]:text-destructive-foreground *:data-[slot=bubble-content]:shadow-(--shadow-secondary-control) *:data-[slot=bubble-content]:inset-ring-1 *:data-[slot=bubble-content]:inset-ring-destructive/30 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-control-hover\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n)\n\nfunction Bubble({\n  variant = \"default\",\n  align = \"start\",\n  className,\n  ...props\n}: React.ComponentProps<\"div\"> &\n  VariantProps<typeof bubbleVariants> & {\n    align?: \"start\" | \"end\"\n  }) {\n  return (\n    <div\n      data-slot=\"bubble\"\n      data-variant={variant}\n      data-align={align}\n      className={cn(bubbleVariants({ variant }), className)}\n      {...props}\n    />\n  )\n}\n\nfunction BubbleContent({\n  className,\n  render,\n  ...props\n}: useRender.ComponentProps<\"div\">) {\n  return useRender({\n    defaultTagName: \"div\",\n    props: mergeProps<\"div\">(\n      {\n        className: cn(\n          \"w-fit max-w-full min-w-0 overflow-hidden rounded-xl px-3 py-2 text-sm leading-5.5 wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/30\",\n          className\n        ),\n      },\n      props\n    ),\n    render,\n    state: {\n      slot: \"bubble-content\",\n    },\n  })\n}\n\nconst bubbleReactionsVariants = cva(\n  \"absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-2xl bg-muted bg-linear-to-b from-white/10 to-transparent px-[6.5px] py-[0.5px] text-sm shadow-[0_0_0_2px_var(--background),0_0_1px_oklch(0_0_0/3%),0_1px_2px_oklch(0_0_0/5%)] outline-[0.5px] -outline-offset-[0.5px] outline-border outline-solid has-[button]:p-0\",\n  {\n    variants: {\n      side: {\n        top: \"bottom-full translate-y-1.5\",\n        bottom: \"top-full -translate-y-1.5\",\n      },\n      align: {\n        start: \"left-2.5\",\n        end: \"right-2.5\",\n      },\n    },\n    defaultVariants: {\n      side: \"bottom\",\n      align: \"end\",\n    },\n  }\n)\n\nfunction BubbleReactions({\n  side = \"bottom\",\n  align = \"end\",\n  className,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  align?: \"start\" | \"end\"\n  side?: \"top\" | \"bottom\"\n}) {\n  return (\n    <div\n      data-slot=\"bubble-reactions\"\n      data-align={align}\n      data-side={side}\n      className={cn(bubbleReactionsVariants({ side, align }), className)}\n      {...props}\n    />\n  )\n}\n\nexport { BubbleGroup, Bubble, BubbleContent, BubbleReactions }\n","type":"registry:ui"}],"cssVars":{"theme":{"color-destructive-foreground":"var(--destructive-foreground)","color-fill-1":"var(--fill-1)","color-fill-2":"var(--fill-2)","color-fill-3":"var(--fill-3)","color-control-hover":"var(--control-hover)","text-sm--letter-spacing":"-0.005em","shadow-secondary-control":"inset 0 -1px 0 oklch(0 0 0 / 8%), 0 1px 2px -1px oklch(0 0 0 / 4%), 0 2px 3px -1px oklch(0 0 0 / 3%)"},"light":{"destructive-foreground":"oklch(0.505 0.213 27.518)","fill-1":"oklch(0.556 0 0 / 5%)","fill-2":"oklch(0.556 0 0 / 8%)","fill-3":"oklch(0.556 0 0 / 12%)","control-hover":"oklch(0.9925 0 0)"},"dark":{"destructive-foreground":"oklch(0.704 0.191 22.216)","fill-1":"oklch(1 0 0 / 5%)","fill-2":"oklch(1 0 0 / 10%)","fill-3":"oklch(1 0 0 / 14%)","control-hover":"oklch(0.269 0 0)"}},"categories":["chat"],"type":"registry:ui"}