Files
tutti/packages/agent/gui/agent-gui/agentGuiNode/AgentComposerDisclosureCard.tsx
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

106 lines
2.9 KiB
TypeScript

import { useId, type ReactNode } from "react";
import { ChevronDown } from "lucide-react";
import { cn } from "../../app/renderer/lib/utils";
import styles from "./AgentGUIChrome.styles";
/**
* Product-neutral composer accessory that expands upward from its persistent
* banner. The disclosure trigger and trailing actions are siblings so actions
* never become nested interactive controls.
*/
export function AgentComposerDisclosureCard({
actions,
bannerClassName,
children,
expanded,
icon,
labels,
onExpandedChange,
panelClassName,
summary,
testId,
title
}: {
actions?: ReactNode;
/** Extra class applied to the persistent banner card only. */
bannerClassName?: string;
children: ReactNode;
expanded: boolean;
icon: ReactNode;
labels: {
collapse: string;
expand: string;
};
onExpandedChange(expanded: boolean): void;
/** Extra class applied to the expanded panel surface only. */
panelClassName?: string;
summary: string;
testId: string;
title: string;
}): React.JSX.Element {
const panelId = useId();
const disclosureLabel = expanded ? labels.collapse : labels.expand;
return (
<div className={styles.sessionChrome}>
<section
className={styles.composerDisclosure}
data-expanded={expanded ? "true" : "false"}
data-testid={testId}
>
{expanded ? (
<div
id={panelId}
className={cn(styles.composerDisclosurePanel, panelClassName)}
data-testid={`${testId}-panel`}
>
{children}
</div>
) : null}
<div
className={cn(
styles.chromeCard,
styles.chromeCardMuted,
styles.composerDisclosureBanner,
bannerClassName
)}
>
<button
type="button"
className={styles.composerDisclosureTrigger}
aria-controls={panelId}
aria-expanded={expanded}
aria-label={disclosureLabel}
title={disclosureLabel}
onClick={() => onExpandedChange(!expanded)}
>
<span className={styles.chromeIcon}>{icon}</span>
<span
className={cn(styles.chromeMessage, styles.chromeNoticeMessage)}
title={`${title} · ${summary}`}
>
<span className={styles.chromeNoticeTitle}>{title}</span>
<span
className={styles.chromeNoticeDescription}
aria-live="polite"
>
{summary}
</span>
</span>
<ChevronDown
aria-hidden
className={cn(
styles.composerDisclosureChevron,
expanded && styles.composerDisclosureChevronExpanded
)}
/>
</button>
{actions ? (
<div className={styles.chromeGoalActions}>{actions}</div>
) : null}
</div>
</section>
</div>
);
}