{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "perplexity-message",
  "title": "Perplexity Message",
  "description": "User pill and assistant answer turn with search and action slots.",
  "dependencies": [
    "cn"
  ],
  "registryDependencies": [
    "avatar",
    "collapsible"
  ],
  "files": [
    {
      "path": "registry/notra/perplexity/components/perplexity-message.tsx",
      "content": "import { cn } from \"cn\";\n\nimport type { PerplexityMessageProps } from \"../types/perplexity\";\n\nexport const PerplexityMessage = ({\n  actions,\n  children,\n  className,\n  from,\n  search,\n  ...props\n}: PerplexityMessageProps) => {\n  if (from === \"user\") {\n    return (\n      <div\n        className={cn(\n          \"group/message flex items-center justify-end gap-3\",\n          className\n        )}\n        data-from=\"user\"\n        data-slot=\"perplexity-message\"\n        {...props}\n      >\n        {actions ? (\n          <div className=\"opacity-0 transition-opacity duration-150 group-focus-within/message:opacity-100 group-hover/message:opacity-100 motion-reduce:transition-none [@media(hover:none)]:opacity-100\">\n            {actions}\n          </div>\n        ) : null}\n        <div className=\"bg-pplx-bubble font-pplx text-pplx-fg max-w-[min(36rem,82%)] rounded-2xl px-4 py-2.5 text-base leading-6\">\n          {children}\n        </div>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      className={cn(\"flex w-full flex-col items-start gap-3.5\", className)}\n      data-from=\"assistant\"\n      data-slot=\"perplexity-message\"\n      {...props}\n    >\n      {search}\n      {children ? (\n        <div className=\"font-pplx-serif text-pplx-fg max-w-2xl text-base leading-6.5 font-normal\">\n          {children}\n        </div>\n      ) : null}\n      {actions ? (\n        <div className=\"-ms-1.5 w-full max-w-2xl\">{actions}</div>\n      ) : null}\n    </div>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/perplexity/components/perplexity-message.tsx"
    },
    {
      "path": "registry/notra/perplexity/types/perplexity.ts",
      "content": "import type { ComponentProps, ReactNode } from \"react\";\n\nimport type { Avatar } from \"@/components/ui/avatar\";\nimport type { Collapsible } from \"@/components/ui/collapsible\";\n\nexport type PerplexityMessageRole = \"user\" | \"assistant\";\n\nexport type PerplexityModelProvider =\n  | \"perplexity\"\n  | \"openai\"\n  | \"google\"\n  | \"anthropic\"\n  | \"kimi\"\n  | \"zhipu\"\n  | \"xai\"\n  | \"nvidia\";\n\nexport type PerplexityModelBadge = \"max\" | \"new\";\n\nexport interface PerplexityModel {\n  badge?: PerplexityModelBadge;\n  id: string;\n  label: string;\n  locked?: boolean;\n  provider: PerplexityModelProvider;\n}\n\nexport type PerplexityFocusId = \"search\" | \"research\";\n\nexport type PerplexityRewriteModeId = \"deep-research\" | \"learn\" | \"search\";\n\nexport interface PerplexityRewriteMode {\n  id: PerplexityRewriteModeId;\n  label: string;\n  locked?: boolean;\n}\n\nexport interface PerplexityRewriteOptions {\n  mode: PerplexityRewriteModeId;\n  model?: string;\n}\n\nexport interface PerplexityRewritePanelProps extends Omit<\n  ComponentProps<\"div\">,\n  \"onSubmit\"\n> {\n  defaultMode?: PerplexityRewriteModeId;\n  modes?: readonly PerplexityRewriteMode[];\n  models?: readonly PerplexityModel[];\n  onClose?: () => void;\n  onRewrite?: (options: PerplexityRewriteOptions) => void;\n  promoLabel?: ReactNode;\n}\n\nexport interface PerplexityFocusOption {\n  description: string;\n  id: PerplexityFocusId;\n  label: string;\n}\n\nexport interface PerplexitySource {\n  domain: string;\n  title: string;\n  url?: string;\n  verified?: boolean;\n}\n\nexport interface PerplexitySearchLabels {\n  more: (count: number) => string;\n  showLess: string;\n}\n\nexport interface PerplexityMessageProps extends ComponentProps<\"div\"> {\n  actions?: ReactNode;\n  from: PerplexityMessageRole;\n  search?: ReactNode;\n}\n\nexport interface PerplexitySearchProps extends Omit<\n  ComponentProps<typeof Collapsible>,\n  \"title\"\n> {\n  duration?: ReactNode;\n  emptyDescription?: ReactNode;\n  extraCount?: number;\n  label?: ReactNode;\n  labels?: PerplexitySearchLabels;\n  onStepOpenChange?: (open: boolean) => void;\n  previewCount?: number;\n  queries: readonly string[];\n  reducedMotion?: boolean;\n  runningLabel?: ReactNode;\n  sequential?: boolean;\n  sources: readonly PerplexitySource[];\n  stepDefaultOpen?: boolean;\n  stepOpen?: boolean;\n  title?: ReactNode;\n}\n\nexport interface PerplexityCitationSource {\n  description?: string;\n  domain: string;\n  title: string;\n  url?: string;\n}\n\nexport interface PerplexityCitationProps extends ComponentProps<\"span\"> {\n  extra?: number;\n  label: string;\n  sources?: readonly PerplexityCitationSource[];\n}\n\nexport interface PerplexityFaviconProps extends ComponentProps<typeof Avatar> {\n  domain: string;\n}\n\nexport interface PerplexityActionsProps extends Omit<\n  ComponentProps<\"div\">,\n  \"onSubmit\"\n> {\n  models?: readonly PerplexityModel[];\n  onBadResponse?: () => void;\n  onDownload?: () => void;\n  onGoodResponse?: () => void;\n  onMore?: () => void;\n  onRewrite?: (options: PerplexityRewriteOptions) => void;\n  onShare?: () => void;\n  sources?: readonly PerplexitySource[];\n  text: string;\n}\n\nexport interface PerplexityUserActionsProps extends ComponentProps<\"div\"> {\n  onEdit?: () => void;\n  text: string;\n  timestamp?: ReactNode;\n}\n\nexport interface PerplexitySourcesSummaryProps extends ComponentProps<\"div\"> {\n  sources: readonly PerplexitySource[];\n}\n\nexport interface PerplexityComposerProps extends Omit<\n  ComponentProps<\"form\">,\n  \"onSubmit\"\n> {\n  busy?: boolean;\n  defaultModel?: string;\n  focus?: PerplexityFocusId;\n  focusOptions?: readonly PerplexityFocusOption[];\n  model?: string;\n  models?: readonly PerplexityModel[];\n  onModelChange?: (model: string) => void;\n  onSend?: (text: string) => void;\n  onStop?: () => void;\n  placeholder?: string;\n}\n\nexport interface PerplexityModelSelectorProps extends ComponentProps<\"button\"> {\n  label?: ReactNode;\n  model?: string;\n  models?: readonly PerplexityModel[];\n  onModelChange?: (model: string) => void;\n  promoLabel?: ReactNode;\n}\n\nexport interface PerplexityModelIconProps extends ComponentProps<\"span\"> {\n  provider: PerplexityModelProvider;\n}\n\nexport interface PerplexityThinkingProps extends ComponentProps<\"div\"> {\n  label?: ReactNode;\n  reducedMotion?: boolean;\n}\n\nexport interface PerplexityThreadCitation {\n  domain: string;\n  extra?: number;\n  id: string;\n  label: string;\n  sources?: readonly PerplexityCitationSource[];\n}\n\nexport interface PerplexityThreadSearch {\n  duration?: string;\n  extraCount?: number;\n  previewCount?: number;\n  queries: string[];\n  sources: PerplexitySource[];\n  title?: string;\n}\n\nexport interface PerplexityThreadMessage {\n  citations?: readonly PerplexityThreadCitation[];\n  from: PerplexityMessageRole;\n  id: string;\n  search?: PerplexityThreadSearch;\n  text: string;\n}\n\nexport interface PerplexityAnswerProps extends ComponentProps<\"div\"> {\n  citations?: readonly PerplexityThreadCitation[];\n  text: string;\n}\n\nexport type PerplexityPlaybackPhase =\n  | { status: \"idle\" }\n  | { status: \"playing\"; source: \"script\" | \"send\"; thinking: boolean };\n",
      "type": "registry:lib",
      "target": "components/perplexity/types/perplexity.ts"
    }
  ],
  "cssVars": {
    "theme": {
      "color-pplx-bg": "var(--pplx-bg)",
      "color-pplx-fg": "var(--pplx-fg)",
      "color-pplx-icon": "var(--pplx-icon)",
      "color-pplx-secondary": "var(--pplx-secondary)",
      "color-pplx-muted": "var(--pplx-muted)",
      "color-pplx-subtle": "var(--pplx-subtle)",
      "color-pplx-hover": "var(--pplx-hover)",
      "color-pplx-row-hover": "var(--pplx-row-hover)",
      "color-pplx-bubble": "var(--pplx-bubble)",
      "color-pplx-chip": "var(--pplx-chip)",
      "color-pplx-favicon": "var(--pplx-favicon)",
      "color-pplx-surface": "var(--pplx-surface)",
      "color-pplx-popover": "var(--pplx-popover)",
      "color-pplx-border": "var(--pplx-border)",
      "color-pplx-ring": "var(--pplx-ring)",
      "color-pplx-send": "var(--pplx-send)",
      "color-pplx-send-hover": "var(--pplx-send-hover)",
      "color-pplx-send-fg": "var(--pplx-send-fg)",
      "color-pplx-send-disabled": "var(--pplx-send-disabled)",
      "color-pplx-send-disabled-fg": "var(--pplx-send-disabled-fg)",
      "color-pplx-model-chip": "var(--pplx-model-chip)",
      "color-pplx-model-chip-hover": "var(--pplx-model-chip-hover)",
      "color-pplx-badge": "var(--pplx-badge)",
      "color-pplx-badge-fg": "var(--pplx-badge-fg)",
      "color-pplx-badge-new": "var(--pplx-badge-new)",
      "color-pplx-badge-new-fg": "var(--pplx-badge-new-fg)",
      "color-pplx-promo": "var(--pplx-promo)",
      "color-pplx-promo-hover": "var(--pplx-promo-hover)",
      "color-pplx-lock": "var(--pplx-lock)",
      "font-pplx": "Inter, ui-sans-serif, system-ui, sans-serif",
      "font-pplx-serif": "ui-serif, Georgia, Cambria, \"Times New Roman\", Times, serif"
    },
    "light": {
      "pplx-bg": "#fdfbfb",
      "pplx-fg": "#27251e",
      "pplx-icon": "#3d3d3d",
      "pplx-secondary": "#5c5c5c",
      "pplx-muted": "#6b6b6b",
      "pplx-subtle": "#8d8d8d",
      "pplx-hover": "#f3f3f3",
      "pplx-row-hover": "#f5f5f5",
      "pplx-bubble": "#f3f3f3",
      "pplx-chip": "#f0f0f0",
      "pplx-favicon": "#e8e8e8",
      "pplx-surface": "#ffffff",
      "pplx-popover": "#ffffff",
      "pplx-border": "rgb(0 0 0 / 8%)",
      "pplx-ring": "rgb(0 0 0 / 15%)",
      "pplx-send": "#2a2a2a",
      "pplx-send-hover": "#1a1a1a",
      "pplx-send-fg": "#ffffff",
      "pplx-send-disabled": "#d9d9d9",
      "pplx-send-disabled-fg": "#ffffff",
      "pplx-model-chip": "#f2f2f2",
      "pplx-model-chip-hover": "#ebebeb",
      "pplx-badge": "#ececec",
      "pplx-badge-fg": "#6b6b6b",
      "pplx-badge-new": "#e8f1fb",
      "pplx-badge-new-fg": "#3d7ab5",
      "pplx-promo": "#e6f3f1",
      "pplx-promo-hover": "#dceeea",
      "pplx-lock": "#b0b0b0"
    },
    "dark": {
      "pplx-bg": "#171615",
      "pplx-fg": "#d6d5d4",
      "pplx-icon": "#fafafa",
      "pplx-secondary": "#b3b3b3",
      "pplx-muted": "#b3b3b3",
      "pplx-subtle": "#a3a3a3",
      "pplx-hover": "rgb(255 255 255 / 10%)",
      "pplx-row-hover": "rgb(255 255 255 / 8%)",
      "pplx-bubble": "rgb(255 255 255 / 10%)",
      "pplx-chip": "rgb(255 255 255 / 10%)",
      "pplx-favicon": "rgb(255 255 255 / 12%)",
      "pplx-surface": "#1c1c1c",
      "pplx-popover": "#1c1c1c",
      "pplx-border": "rgb(255 255 255 / 10%)",
      "pplx-ring": "rgb(255 255 255 / 20%)",
      "pplx-send": "#ffffff",
      "pplx-send-hover": "rgb(255 255 255 / 90%)",
      "pplx-send-fg": "#1a1a1a",
      "pplx-send-disabled": "rgb(255 255 255 / 20%)",
      "pplx-send-disabled-fg": "rgb(255 255 255 / 70%)",
      "pplx-model-chip": "rgb(255 255 255 / 10%)",
      "pplx-model-chip-hover": "rgb(255 255 255 / 15%)",
      "pplx-badge": "rgb(255 255 255 / 10%)",
      "pplx-badge-fg": "#b3b3b3",
      "pplx-badge-new": "rgb(61 122 181 / 20%)",
      "pplx-badge-new-fg": "#8bb8e0",
      "pplx-promo": "#1c3d38",
      "pplx-promo-hover": "#244843",
      "pplx-lock": "#7a7a7a"
    }
  },
  "type": "registry:component"
}