Ai Task

PreviousNext

A ai-task item.

Docs
mui-treasuryitem

Preview

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

import Box from "@mui/material/Box";
import Collapse from "@mui/material/Collapse";
import Typography from "@mui/material/Typography";
import type { SxProps, Theme } from "@mui/material/styles";
import { ChevronDownIcon, SearchIcon } from "lucide-react";
import React, { memo, useState, type ReactNode } from "react";

export type TaskItemFileProps = {
  children?: ReactNode;
  sx?: SxProps<Theme>;
};

export const TaskItemFile = ({ children, sx }: TaskItemFileProps) => (
  <Box
    sx={{
      display: "inline-flex",
      alignItems: "center",
      gap: 0.5,
      borderRadius: 1,
      border: 1,
      borderColor: "divider",
      bgcolor: "action.hover",
      px: 0.75,
      py: 0,
      color: "text.primary",
      fontSize: "0.75rem",
      ...sx,
    }}
  >
    {children}
  </Box>
);

export type TaskItemProps = {
  children?: ReactNode;
  sx?: SxProps<Theme>;
};

export const TaskItem = ({ children, sx }: TaskItemProps) => (
  <Box
    sx={{
      color: "text.secondary",
      fontSize: "0.875rem",
      ...sx,
    }}
  >
    {children}
  </Box>
);

export type TaskProps = {
  defaultOpen?: boolean;
  children?: ReactNode;
  sx?: SxProps<Theme>;
};

export const Task = memo(({ defaultOpen = true, children, sx }: TaskProps) => {
  const [isOpen, setIsOpen] = useState(defaultOpen);

  return (
    <Box sx={sx}>
      {React.Children.map(children, (child) =>
        React.isValidElement(child)
          ? React.cloneElement(child as React.ReactElement<any>, {
              isOpen,
              onToggle: () => setIsOpen(!isOpen),
            })
          : child,
      )}
    </Box>
  );
});

Task.displayName = "Task";

export type TaskTriggerProps = {
  title: string;
  children?: ReactNode;
  sx?: SxProps<Theme>;
  isOpen?: boolean;
  onToggle?: () => void;
};

export const TaskTrigger = ({
  children,
  title,
  sx,
  isOpen = false,
  onToggle,
}: TaskTriggerProps) => (
  <Box
    component="button"
    onClick={onToggle}
    sx={{
      display: "flex",
      width: "100%",
      alignItems: "center",
      gap: 1,
      color: "text.secondary",
      fontSize: "0.875rem",
      transition: "color 0.2s",
      border: "none",
      background: "transparent",
      cursor: "pointer",
      p: 0,
      "&:hover": {
        color: "text.primary",
      },
      ...sx,
    }}
  >
    {children ?? (
      <>
        <SearchIcon size={16} />
        <Typography component="span" sx={{ fontSize: "0.875rem" }}>
          {title}
        </Typography>
        <Box
          component={ChevronDownIcon}
          size={16}
          sx={{
            transition: "transform 0.2s",
            transform: isOpen ? "rotate(180deg)" : "rotate(0deg)",
          }}
        />
      </>
    )}
  </Box>
);

export type TaskContentProps = {
  children?: ReactNode;
  sx?: SxProps<Theme>;
  isOpen?: boolean;
};

export const TaskContent = memo(
  ({ children, sx, isOpen = false }: TaskContentProps) => (
    <Collapse in={isOpen}>
      <Box
        sx={{
          mt: 2,
          pl: 2,
          borderLeft: 2,
          borderColor: "divider",
          "& > *:not(:last-child)": {
            mb: 1,
          },
          ...sx,
        }}
      >
        {children}
      </Box>
    </Collapse>
  ),
);

TaskContent.displayName = "TaskContent";

Installation

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

Usage

import { AiTask } from "@/components/ai-task"
<AiTask />