{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bubble",
  "type": "registry:ui",
  "title": "Bubble",
  "description": "Bubble chat primitives for Tile UI.",
  "dependencies": [
    "@radix-ui/react-slot"
  ],
  "devDependencies": [
    "sass"
  ],
  "registryDependencies": [
    "@tile-ui/core",
    "@tile-ui/styles"
  ],
  "files": [
    {
      "path": "packages/react/src/components/bubble/bubble.tsx",
      "type": "registry:ui",
      "target": "components/ui/bubble/bubble.tsx",
      "content": "import React from 'react';\nimport { Slot } from '@radix-ui/react-slot';\nimport { bubbleStyleKeys, getBubbleStyleKeys } from '../lib/core';\nimport type { BubbleBaseProps, BubbleContentBaseProps, BubbleReactionsBaseProps } from '../lib/core';\nimport styles from './bubble.module.scss';\n\nexport interface BubbleGroupProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst BubbleGroup = React.forwardRef<HTMLDivElement, BubbleGroupProps>(({ className = '', children, ...props }, ref) => {\n\treturn (\n\t\t<div ref={ref} data-slot=\"bubble-group\" className={[styles[bubbleStyleKeys.group], className].filter(Boolean).join(' ')} {...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nBubbleGroup.displayName = 'BubbleGroup';\n\nexport interface BubbleProps extends React.HTMLAttributes<HTMLDivElement>, BubbleBaseProps {}\n\nconst Bubble = React.forwardRef<HTMLDivElement, BubbleProps>(({ className = '', variant = 'default', align = 'start', children, ...props }, ref) => {\n\tconst styleKeys = getBubbleStyleKeys(variant);\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tdata-slot=\"bubble\"\n\t\t\tdata-variant={variant}\n\t\t\tdata-align={align}\n\t\t\tclassName={[styles[styleKeys.base], styles[styleKeys.variant], className].filter(Boolean).join(' ')}\n\t\t\t{...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nBubble.displayName = 'Bubble';\n\nexport interface BubbleContentProps extends React.HTMLAttributes<HTMLDivElement>, BubbleContentBaseProps {}\n\nconst BubbleContent = React.forwardRef<HTMLDivElement, BubbleContentProps>(({ className = '', asChild = false, children, ...props }, ref) => {\n\tconst Comp = asChild ? Slot : 'div';\n\n\treturn (\n\t\t<Comp ref={ref} data-slot=\"bubble-content\" className={[styles[bubbleStyleKeys.content], className].filter(Boolean).join(' ')} {...props}>\n\t\t\t{children}\n\t\t</Comp>\n\t);\n});\nBubbleContent.displayName = 'BubbleContent';\n\nexport interface BubbleReactionsProps extends React.HTMLAttributes<HTMLDivElement>, BubbleReactionsBaseProps {}\n\nconst BubbleReactions = React.forwardRef<HTMLDivElement, BubbleReactionsProps>(({ className = '', side = 'bottom', align = 'end', children, ...props }, ref) => {\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tdata-slot=\"bubble-reactions\"\n\t\t\tdata-side={side}\n\t\t\tdata-align={align}\n\t\t\tclassName={[styles[bubbleStyleKeys.reactions], className].filter(Boolean).join(' ')}\n\t\t\t{...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nBubbleReactions.displayName = 'BubbleReactions';\n\nexport { BubbleGroup, Bubble, BubbleContent, BubbleReactions };\nexport default Bubble;\n"
    },
    {
      "path": "packages/styles/scss/components/bubble.module.scss",
      "type": "registry:file",
      "target": "components/ui/bubble/bubble.module.scss",
      "content": "@use '../../../styles/variables/colors' as *;\n\n// 气泡组\n.group {\n\tdisplay: flex;\n\twidth: 100%;\n\tmin-width: 0;\n\tflex-direction: column;\n\tgap: $spacing-2;\n}\n\n// 气泡根容器\n.bubble {\n\tposition: relative;\n\tdisplay: flex;\n\twidth: fit-content;\n\tmax-width: 80%;\n\tmin-width: 0;\n\tflex-direction: column;\n\tgap: $spacing-1;\n\n\t&[data-align='end'] {\n\t\talign-self: flex-end;\n\n\t\t.content {\n\t\t\talign-self: flex-end;\n\t\t}\n\t}\n\n\t&[data-variant='ghost'] {\n\t\tmax-width: 100%;\n\t}\n\n\t&:has(.reactions[data-side='top']) {\n\t\tmargin-top: $spacing-3;\n\t}\n\n\t&:has(.reactions[data-side='bottom']) {\n\t\tmargin-bottom: $spacing-3;\n\t}\n\n\t// 变体\n\t&.variantDefault .content {\n\t\tbackground-color: var(--tile-bubble-background, $primary);\n\t\tcolor: var(--tile-bubble-color, $primary-foreground);\n\t}\n\n\t&.variantSecondary .content {\n\t\tbackground-color: var(--tile-bubble-secondary-background, $secondary);\n\t\tcolor: $secondary-foreground;\n\t}\n\n\t&.variantMuted .content {\n\t\tbackground-color: var(--tile-bubble-muted-background, $muted);\n\t\tcolor: $foreground;\n\t}\n\n\t&.variantTinted .content {\n\t\tbackground-color: var(--tile-bubble-tinted-background, color-mix(in srgb, $primary 15%, $background));\n\t\tcolor: $foreground;\n\t}\n\n\t&.variantOutline .content {\n\t\tborder-color: var(--tile-bubble-border, $border);\n\t\tbackground-color: var(--tile-bubble-outline-background, $background);\n\t\tcolor: $foreground;\n\t}\n\n\t&.variantGhost .content {\n\t\tborder: none;\n\t\tborder-radius: 0;\n\t\tbackground-color: transparent;\n\t\tpadding: 0;\n\t}\n\n\t&.variantDestructive .content {\n\t\tbackground-color: var(--tile-bubble-error-background, color-mix(in srgb, $destructive 10%, transparent));\n\t\tcolor: var(--tile-bubble-error-color, $destructive);\n\t}\n\n\t// 按钮/链接形态的内容悬停效果\n\t&.variantDefault .content:is(button, a):hover {\n\t\tbackground-color: var(--tile-bubble-hover-background, color-mix(in srgb, $primary 80%, transparent));\n\t}\n\n\t&.variantSecondary .content:is(button, a):hover,\n\t&.variantMuted .content:is(button, a):hover,\n\t&.variantGhost .content:is(button, a):hover,\n\t&.variantOutline .content:is(button, a):hover {\n\t\tbackground-color: $muted;\n\t\tcolor: $foreground;\n\t}\n\n\t&.variantDestructive .content:is(button, a):hover {\n\t\tbackground-color: var(--tile-bubble-error-hover-background, color-mix(in srgb, $destructive 20%, transparent));\n\t}\n}\n\n// 气泡内容\n.content {\n\tdisplay: block;\n\twidth: fit-content;\n\tmax-width: 100%;\n\tmin-width: 0;\n\toverflow: hidden;\n\tborder: 1px solid transparent;\n\tborder-radius: var(--tile-bubble-radius, $radius);\n\tpadding: var(--tile-bubble-padding, $spacing-2 $spacing-3);\n\tfont-size: $text-sm;\n\tline-height: $leading-relaxed;\n\toverflow-wrap: anywhere;\n\tword-break: break-word;\n\n\t&:is(button, a) {\n\t\ttext-align: left;\n\t\ttransition:\n\t\t\tbackground-color $transition-fast,\n\t\t\tborder-color $transition-fast,\n\t\t\tbox-shadow $transition-fast;\n\t\toutline: none;\n\t}\n\n\t&:is(button, a):focus-visible {\n\t\tborder-color: $ring;\n\t\tbox-shadow: var(--tile-bubble-focus-shadow, 0 0 0 3px color-mix(in srgb, $ring 50%, transparent));\n\t}\n}\n\n// 气泡反应区 (绝对定位于气泡边缘)\n.reactions {\n\tposition: absolute;\n\tz-index: 10;\n\tdisplay: flex;\n\twidth: fit-content;\n\tflex-shrink: 0;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: $spacing-1;\n\tborder-radius: $radius-full;\n\tbackground-color: var(--tile-bubble-reactions-background, $muted);\n\tpadding: 0.125rem $spacing-1_5;\n\tfont-size: $text-sm;\n\tbox-shadow: 0 0 0 3px $card;\n\n\t&[data-side='top'] {\n\t\ttop: 0;\n\t\ttransform: translateY(-75%);\n\t}\n\n\t&[data-side='bottom'] {\n\t\tbottom: 0;\n\t\ttransform: translateY(75%);\n\t}\n\n\t&[data-align='start'] {\n\t\tleft: $spacing-3;\n\t}\n\n\t&[data-align='end'] {\n\t\tright: $spacing-3;\n\t}\n}\n"
    },
    {
      "path": "packages/react/src/components/bubble/index.ts",
      "type": "registry:ui",
      "target": "components/ui/bubble/index.ts",
      "content": "export { BubbleGroup, Bubble, BubbleContent, BubbleReactions, type BubbleGroupProps, type BubbleProps, type BubbleContentProps, type BubbleReactionsProps } from './bubble';\n"
    }
  ]
}
