AI Artifact

PreviousNext

A container component for displaying artifacts with header, actions, and content areas

Docs
mui-treasuryitem

Preview

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

import Box from "@mui/material/Box";
import IconButton from "@mui/material/IconButton";
import Paper from "@mui/material/Paper";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import { XIcon } from "lucide-react";
import { memo, type ComponentProps } from "react";

export type ArtifactProps = ComponentProps<typeof Paper>;

export const Artifact = ({ children, sx, ...props }: ArtifactProps) => (
  <Paper
    elevation={4}
    sx={{
      display: "flex",
      flexDirection: "column",
      overflow: "hidden",
      border: 1,
      borderColor: "divider",
      ...sx,
    }}
    {...props}
  >
    {children}
  </Paper>
);

export type ArtifactHeaderProps = ComponentProps<typeof Box>;

export const ArtifactHeader = ({
  children,
  sx,
  ...props
}: ArtifactHeaderProps) => (
  <Box
    sx={[
      (theme) => ({
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        borderBottom: 1,
        borderColor: "divider",
        bgcolor: (theme.vars || theme).palette.action.hover,
        px: 2,
        py: 1.5,
      }),
      ...(Array.isArray(sx) ? sx : [sx]),
    ]}
    {...props}
  >
    {children}
  </Box>
);

export type ArtifactCloseProps = ComponentProps<typeof IconButton>;

export const ArtifactClose = memo(
  ({ children, size = "small", sx, ...props }: ArtifactCloseProps) => (
    <IconButton
      size={size}
      type="button"
      sx={{
        width: 32,
        height: 32,
        p: 0,
        color: "text.secondary",
        "&:hover": {
          color: "text.primary",
        },
        ...sx,
      }}
      aria-label="Close"
      {...props}
    >
      {children ?? <XIcon className="size-4" />}
    </IconButton>
  ),
);

ArtifactClose.displayName = "ArtifactClose";

export type ArtifactTitleProps = ComponentProps<typeof Typography>;

export const ArtifactTitle = ({ sx, ...props }: ArtifactTitleProps) => (
  <Typography
    variant="body2"
    sx={{
      fontWeight: 500,
      color: "text.primary",
      ...sx,
    }}
    {...props}
  />
);

export type ArtifactDescriptionProps = ComponentProps<typeof Typography>;

export const ArtifactDescription = ({
  sx,
  ...props
}: ArtifactDescriptionProps) => (
  <Typography
    variant="body2"
    sx={{
      color: "text.secondary",
      ...sx,
    }}
    {...props}
  />
);

export type ArtifactActionsProps = ComponentProps<typeof Box>;

export const ArtifactActions = ({
  children,
  sx,
  ...props
}: ArtifactActionsProps) => (
  <Box
    sx={{
      display: "flex",
      alignItems: "center",
      gap: 0.5,
      ...sx,
    }}
    {...props}
  >
    {children}
  </Box>
);

export type ArtifactActionProps = ComponentProps<typeof IconButton> & {
  tooltip?: string;
  label?: string;
  icon?: React.ComponentType<{ className?: string }>;
};

export const ArtifactAction = ({
  tooltip,
  label,
  icon: Icon,
  children,
  size = "small",
  sx,
  ...props
}: ArtifactActionProps) => {
  const button = (
    <IconButton
      size={size}
      type="button"
      sx={{
        width: 32,
        height: 32,
        p: 0,
        color: "text.secondary",
        "&:hover": {
          color: "text.primary",
        },
        ...sx,
      }}
      aria-label={label || tooltip}
      {...props}
    >
      {Icon ? <Icon className="size-4" /> : children}
    </IconButton>
  );

  if (tooltip) {
    return (
      <Tooltip title={tooltip} arrow>
        {button}
      </Tooltip>
    );
  }

  return button;
};

export type ArtifactContentProps = ComponentProps<typeof Box>;

export const ArtifactContent = ({
  children,
  sx,
  ...props
}: ArtifactContentProps) => (
  <Box
    sx={{
      flex: 1,
      overflow: "auto",
      p: 2,
      ...sx,
    }}
    {...props}
  >
    {children}
  </Box>
);

Installation

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

Usage

import { AiArtifact } from "@/components/ai-artifact"
<AiArtifact />