Unify the Agent history extension with the header acrylic surface, preserve the full conversation body, and consolidate shared control and status styling. Restore map flow and SCADA controller behavior, remove obsolete rendering paths, and extend regression coverage. Button press coverage now releases outside the target so state assertions cannot accidentally toggle the control.
134 lines
4.4 KiB
TypeScript
134 lines
4.4 KiB
TypeScript
import type { LucideIcon } from "lucide-react";
|
|
import { cn } from "@/shared/ui/cn";
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
TooltipTrigger
|
|
} from "@/shared/ui/tooltip";
|
|
import {
|
|
MAP_COMPACT_RADIUS_CLASS_NAME,
|
|
MAP_CONTROL_SURFACE_CLASS_NAME,
|
|
MAP_ICON_CELL_RADIUS_CLASS_NAME,
|
|
MAP_READABLE_SURFACE_CLASS_NAME
|
|
} from "./map-control-styles";
|
|
|
|
export type MapDrawTool = {
|
|
id: string;
|
|
label: string;
|
|
icon: LucideIcon;
|
|
active?: boolean;
|
|
disabled?: boolean;
|
|
tone?: "default" | "danger";
|
|
onClick?: () => void;
|
|
};
|
|
|
|
export type MapDrawToolbarProps = {
|
|
items: MapDrawTool[];
|
|
label?: string;
|
|
className?: string;
|
|
variant?: "compact" | "panel";
|
|
};
|
|
|
|
export function MapDrawToolbar({ items, label = "绘制工具", className = "", variant = "compact" }: MapDrawToolbarProps) {
|
|
if (variant === "panel") {
|
|
return (
|
|
<div
|
|
role="toolbar"
|
|
aria-label={label}
|
|
className={cn("pointer-events-auto grid grid-cols-2 gap-1.5", className)}
|
|
>
|
|
{items.map((item) => {
|
|
const Icon = item.icon;
|
|
const isDanger = item.tone === "danger";
|
|
|
|
return (
|
|
<button
|
|
key={item.id}
|
|
type="button"
|
|
aria-pressed={item.active}
|
|
disabled={item.disabled}
|
|
onClick={item.onClick}
|
|
className={cn(
|
|
"flex min-h-10 items-center gap-2 border px-2.5 py-2 text-left text-xs font-semibold transition duration-150",
|
|
MAP_COMPACT_RADIUS_CLASS_NAME,
|
|
item.active
|
|
? "border-blue-600 bg-blue-600 text-white shadow-[var(--action-shadow-primary)]"
|
|
: "text-slate-700 hover:border-blue-100 hover:bg-white hover:text-blue-700",
|
|
!item.active && MAP_READABLE_SURFACE_CLASS_NAME,
|
|
isDanger && "hover:border-red-100 hover:text-red-700",
|
|
item.disabled &&
|
|
"cursor-not-allowed opacity-55 hover:border-white/70 hover:bg-white/95 hover:text-slate-700"
|
|
)}
|
|
>
|
|
<span
|
|
className={cn(
|
|
"grid h-7 w-7 shrink-0 place-items-center",
|
|
MAP_ICON_CELL_RADIUS_CLASS_NAME,
|
|
item.active ? "bg-white/16 text-white" : "bg-slate-100 text-slate-500",
|
|
isDanger && "bg-red-50 text-red-600"
|
|
)}
|
|
>
|
|
<Icon size={15} aria-hidden="true" />
|
|
</span>
|
|
<span className="min-w-0 truncate">{item.label}</span>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<TooltipProvider delayDuration={180}>
|
|
<div
|
|
role="toolbar"
|
|
aria-label={label}
|
|
className={cn(
|
|
"pointer-events-auto inline-flex gap-1 p-1",
|
|
MAP_COMPACT_RADIUS_CLASS_NAME,
|
|
MAP_CONTROL_SURFACE_CLASS_NAME,
|
|
className
|
|
)}
|
|
>
|
|
{items.map((item) => {
|
|
const Icon = item.icon;
|
|
const isDanger = item.tone === "danger";
|
|
|
|
return (
|
|
<Tooltip key={item.id}>
|
|
<TooltipTrigger asChild>
|
|
<button
|
|
type="button"
|
|
aria-label={item.label}
|
|
aria-pressed={item.active}
|
|
disabled={item.disabled}
|
|
onClick={item.onClick}
|
|
className={cn(
|
|
"grid h-10 w-10 shrink-0 place-items-center border border-transparent text-slate-600",
|
|
MAP_ICON_CELL_RADIUS_CLASS_NAME,
|
|
item.active
|
|
? "border-blue-600 bg-blue-600 text-white shadow-[var(--action-shadow-primary)]"
|
|
: "hover:bg-blue-50 hover:text-blue-700",
|
|
isDanger && "hover:bg-red-50 hover:text-red-700",
|
|
item.disabled && "opacity-45 hover:bg-transparent hover:text-slate-600"
|
|
)}
|
|
>
|
|
<Icon size={16} aria-hidden="true" />
|
|
</button>
|
|
</TooltipTrigger>
|
|
<TooltipContent
|
|
side="top"
|
|
sideOffset={7}
|
|
className="border border-slate-200 bg-white px-2.5 py-1.5 text-xs font-medium text-slate-800 shadow-lg"
|
|
>
|
|
{item.label}
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
);
|
|
})}
|
|
</div>
|
|
</TooltipProvider>
|
|
);
|
|
}
|