Z ZPI 文档 v0.3.8
介绍页

源码

packages/desktop/src/renderer/TaskMenu.tsx

tsx74 行查看原文
import * as Menu from "@radix-ui/react-dropdown-menu";
import { ActionHint } from "@zpi-dev/ui";
import { MoreHorizontal } from "lucide-react";
import { useCallback, useEffect, useRef } from "react";
import type { SessionRecord } from "../shared/bridge.ts";
import { formatShortcut } from "../shared/shortcuts.ts";
import { useStore } from "./store.ts";
import { TaskMenuItems } from "./TaskMenuItems.tsx";
import { useOverlayShortcut } from "./use-overlay-shortcut.ts";

export function TaskMenu({
  record,
  open,
  onOpenChange,
  onRename,
}: {
  record: SessionRecord;
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onRename: () => void;
}) {
  const shortcuts = useStore((state) => state.settings?.shortcuts);
  const opener = useRef<Element | null>(null);
  const menu = useRef<HTMLDivElement>(null);
  const attachMenu = useCallback((element: HTMLDivElement | null) => {
    if (element && menu.current !== element) opener.current = document.activeElement;
    menu.current = element;
  }, []);
  useEffect(() => {
    if (!open) return;
    const frame = requestAnimationFrame(() =>
      menu.current?.querySelector<HTMLElement>('[role="menuitem"]:not([aria-disabled="true"])')?.focus(),
    );
    return () => cancelAnimationFrame(frame);
  }, [open]);
  useOverlayShortcut("task-menu", open, () => onOpenChange(false));
  return (
    <Menu.Root open={open} onOpenChange={onOpenChange}>
      <ActionHint
        label="任务菜单"
        appearance="control"
        open={open ? false : undefined}
        shortcut={
          shortcuts?.enabled && shortcuts.bindings["task-menu"]
            ? formatShortcut(shortcuts.bindings["task-menu"], window.zpi.platform)
            : undefined
        }
      >
        <Menu.Trigger className="task-more" aria-label="任务菜单">
          <MoreHorizontal size={16} />
        </Menu.Trigger>
      </ActionHint>
      <Menu.Portal>
        <Menu.Content
          ref={attachMenu}
          className="selection-menu task-menu"
          align="start"
          sideOffset={2}
          data-shortcut-owner="task-menu"
          loop
          onCloseAutoFocus={(event) => {
            if (opener.current instanceof HTMLElement && opener.current.isConnected) {
              event.preventDefault();
              opener.current.focus();
            }
          }}
        >
          <TaskMenuItems record={record} onRename={onRename} />
        </Menu.Content>
      </Menu.Portal>
    </Menu.Root>
  );
}