Ai Message

PreviousNext

A ai-message item.

Docs
mui-treasuryitem

Preview

Loading preview…
components/ai-message/ai-message.tsx
"use client";

import Avatar from "@mui/material/Avatar";
import Box from "@mui/material/Box";
import type { UIMessage } from "ai";
import { memo, type ComponentProps } from "react";

export type MessageProps = ComponentProps<typeof Box> & {
  from: UIMessage["role"];
};

export const Message = memo(({ from, sx, ...props }: MessageProps) => (
  <Box
    data-from={from}
    sx={{
      display: "flex",
      width: "100%",
      alignItems: "flex-end",
      gap: 1,
      py: 2,
      '&[data-from="user"]': {
        flexDirection: "row-reverse",
        "&:has(.MuiAvatar-root:last-child)": {
          flexDirection: "row",
          justifyContent: "flex-end",
        },
      },
      '&:not([data-from="user"]):has(.MuiAvatar-root:last-child)': {
        flexDirection: "row-reverse",
        justifyContent: "flex-end",
      },
      ...sx,
    }}
    {...props}
  />
));

Message.displayName = "Message";

export type MessageContentProps = ComponentProps<typeof Box> & {
  variant?: "contained" | "flat";
};

export const MessageContent = memo(
  ({ children, variant = "contained", sx, ...props }: MessageContentProps) => (
    <Box
      sx={{
        display: "flex",
        flexDirection: "column",
        gap: 1,
        overflow: "hidden",
        borderRadius: 2,
        fontSize: "0.875rem",
        lineHeight: 1.6,

        ...(variant === "contained" && {
          maxWidth: "80%",
          px: 2,
          py: 1.5,
          // User message styles
          "[data-from='user'] > &": {
            bgcolor: "primary.main",
            color: "primary.contrastText",
          },
          // Assistant message styles
          "[data-from='assistant'] > &, [data-from='system'] > &": {
            bgcolor: "action.hover",
            color: "text.primary",
          },
        }),

        ...(variant === "flat" && {
          // User message with flat variant
          "[data-from='user'] > &": {
            maxWidth: "80%",
            bgcolor: "action.hover",
            px: 2,
            py: 1.5,
            color: "text.primary",
          },
          // Assistant message with flat variant
          "[data-from='assistant'] > &, [data-from='system'] > &": {
            borderRadius: 0,
            color: "text.primary",
          },
        }),

        ...sx,
      }}
      {...props}
    >
      {children}
    </Box>
  ),
);

MessageContent.displayName = "MessageContent";

export type MessageAvatarProps = ComponentProps<typeof Avatar> & {
  src?: string;
  name?: string;
};

export const MessageAvatar = memo(
  ({ src, name, sx, ...props }: MessageAvatarProps) => (
    <Avatar
      src={src}
      sx={{
        width: 32,
        height: 32,
        border: 1,
        borderColor: "divider",
        fontSize: "0.75rem",
        ...sx,
      }}
      {...props}
    >
      {!src && (name?.slice(0, 2).toUpperCase() || "ME")}
    </Avatar>
  ),
);

MessageAvatar.displayName = "MessageAvatar";

Installation

npx shadcn@latest add @mui-treasury/ai-message

Usage

import { AiMessage } from "@/components/ai-message"
<AiMessage />