"use client";
import { memo, useState } from "react";
import { ChevronDown, X, type LucideIcon } from "lucide-react";
import { useTranslation } from "react-i18next";
/**
* One row in the reference tree: an attachment, a Space reference, a
* persona, etc. All kinds render identically (monochrome icon + kind
* prefix + label) — visual uniformity is the point.
*/
export interface ContextTreeItem {
key: string;
// A lucide icon, or any glyph with the same call signature (brand SVG marks
// are cast to this at the call site).
icon: LucideIcon;
/** Type prefix ("Book", "Notebook", ...), already translated. */
kind: string;
/** Item title; truncates. */
label: string;
/** 16px thumbnail for image attachments — replaces the icon. */
thumbnailUrl?: string;
/** Optional click action (e.g. open attachment preview). */
onClick?: () => void;
/** Optional remove action (composer only). */
onRemove?: () => void;
}
/**
* Connector glyph: a thin rounded elbow line (NOT a bordered box — that
* reads as a todo checkbox). Drawn for the "up" flavor (┌: rises from
* the textarea, turns right); the mirrored/down flavors derive from it
* via CSS transforms.
*/
function ElbowMark({
direction,
mirrored,
}: {
direction: "up" | "down";
mirrored: boolean;
}) {
const flip = [
direction === "down" ? "-scale-y-100" : "",
mirrored ? "-scale-x-100" : "",
]
.join(" ")
.trim();
return (
);
}
/**
* Folded-content mark for the summary toggle: three quiet dots — the
* "…" idiom for collapsed lines. The toggle is a control, not a ref,
* so it gets no elbow; once expanded nothing is hidden anymore and the
* mark yields to a blank spacer that keeps the text column aligned.
*/
function FoldMark({ visible }: { visible: boolean }) {
return (
);
}
/**
* Claude-Code-style attachment tree: an elbow connector + a quiet
* collapsed summary ("N references"), expandable to one row per item.
*
* direction="up" is the composer flavor — the block sits above the
* textarea and the elbows read as the input box extending upward.
* direction="down" + align="right" is the sent-message flavor: ┘
* elbows hug the bubble's right edge and the rows extend leftward.
*/
export default memo(function ContextReferenceTree({
items,
direction,
align = "left",
summaryNoun,
}: {
items: ContextTreeItem[];
direction: "up" | "down";
align?: "left" | "right";
/** Translated noun for the collapsed summary ("attachments" / "references"). */
summaryNoun: string;
}) {
const { t } = useTranslation();
const [expanded, setExpanded] = useState(false);
if (items.length === 0) return null;
// A single item needs no collapse ceremony — show it directly.
const collapsible = items.length > 1;
const showRows = !collapsible || expanded;
const mirrored = align === "right";
const alignClass = mirrored ? "items-end" : "items-start";
// Mirrored rows reverse the flex order so the elbow sits at the right
// edge (hugging the bubble) and content extends leftward.
const rowDirClass = mirrored ? "flex-row-reverse" : "";
const rows = showRows
? items.map((item) => {
const Inner = (
<>
) : (