87 lines · 3.1 KB · TypeScript
RawDownload
import { ProviderInteractionMode, RuntimeMode } from "@t3tools/contracts";import { memo, type ReactNode } from "react";import { EllipsisIcon } from "lucide-react";import {  Menu,  MenuPopup,  MenuRadioGroup,  MenuRadioItem,  MenuSeparator as MenuDivider,  MenuTrigger,} from "../ui/menu";import { ComposerControl, ComposerControlIcon } from "./ComposerControl";import { composerFloatingLayerProps } from "./composerEventScope";import { useComposerMenuState } from "./useComposerMenuState"; export const CompactComposerControlsMenu = memo(function CompactComposerControlsMenu(props: {  interactionMode: ProviderInteractionMode;  runtimeMode: RuntimeMode;  showInteractionModeToggle: boolean;  traitsMenuContent?: ReactNode;  size?: "sm" | "xs";  /**   * The resting strip keeps this menu mounted out of flow while every block   * fits inline. Its portaled popup would outlive that transition, so an   * open menu closes when its trigger hides.   */  hidden?: boolean;  onToggleInteractionMode: () => void;  onRuntimeModeChange: (mode: RuntimeMode) => void;}) {  const size = props.size ?? "sm";  const [open, setOpen] = useComposerMenuState(props.hidden);   return (    <Menu open={open} onOpenChange={setOpen}>      <MenuTrigger        render={          <ComposerControl            size={size}            variant="ghost"            className={size === "xs" ? "shrink-0" : "shrink-0 px-2"}            aria-label="More composer controls"          />        }      >        <ComposerControlIcon icon={EllipsisIcon} size={size} />      </MenuTrigger>      <MenuPopup align="start" {...composerFloatingLayerProps}>        {props.traitsMenuContent ? (          <>            {props.traitsMenuContent}            <MenuDivider />          </>        ) : null}        {props.showInteractionModeToggle ? (          <>            <div className="px-2 py-1.5 font-medium text-muted-foreground text-xs">Mode</div>            <MenuRadioGroup              value={props.interactionMode}              onValueChange={(value) => {                if (!value || value === props.interactionMode) return;                props.onToggleInteractionMode();              }}            >              <MenuRadioItem value="default">Chat</MenuRadioItem>              <MenuRadioItem value="plan">Plan</MenuRadioItem>            </MenuRadioGroup>            <MenuDivider />          </>        ) : null}        <div className="px-2 py-1.5 font-medium text-muted-foreground text-xs">Access</div>        <MenuRadioGroup          value={props.runtimeMode}          onValueChange={(value) => {            if (!value || value === props.runtimeMode) return;            props.onRuntimeModeChange(value as RuntimeMode);          }}        >          <MenuRadioItem value="approval-required">Supervised</MenuRadioItem>          <MenuRadioItem value="auto-accept-edits">Auto-accept edits</MenuRadioItem>          <MenuRadioItem value="auto">Auto</MenuRadioItem>          <MenuRadioItem value="full-access">Full access</MenuRadioItem>        </MenuRadioGroup>      </MenuPopup>    </Menu>  );});