Files
next-tjwater-drainage-frontend/src/features/map/core/components/zoom.tsx
T

135 lines
3.4 KiB
TypeScript

"use client";
import type { Map as MapLibreMap } from "maplibre-gl";
import { Home, Minus, Plus, type LucideIcon } from "lucide-react";
import { type RefObject, useCallback } from "react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger
} from "@/shared/ui/tooltip";
import { cn } from "@/lib/utils";
import {
MAP_CONTROL_HOVER_CLASS_NAME,
MAP_CONTROL_RADIUS_CLASS_NAME,
MAP_ICON_CELL_RADIUS_CLASS_NAME,
MAP_CONTROL_SURFACE_CLASS_NAME
} from "./map-control-styles";
type MapZoomProps = {
mapRef: RefObject<MapLibreMap | null>;
mapReady: boolean;
onHome: () => void;
className?: string;
};
export function MapZoom({ mapRef, mapReady, onHome, className = "" }: MapZoomProps) {
const handleZoomIn = useCallback(() => {
mapRef.current?.zoomIn({ duration: 260 });
}, [mapRef]);
const handleZoomOut = useCallback(() => {
mapRef.current?.zoomOut({ duration: 260 });
}, [mapRef]);
return (
<TooltipProvider delayDuration={180}>
<div
role="group"
aria-label="地图缩放"
className={cn(
"pointer-events-auto flex w-[46px] flex-col gap-2",
className
)}
>
<div
className={cn(
"flex flex-col p-[3px]",
MAP_CONTROL_RADIUS_CLASS_NAME,
MAP_CONTROL_SURFACE_CLASS_NAME
)}
>
<ControlButton
icon={Plus}
label="放大"
disabled={!mapReady}
onClick={handleZoomIn}
/>
<Divider />
<ControlButton
icon={Minus}
label="缩小"
disabled={!mapReady}
onClick={handleZoomOut}
/>
</div>
<div
className={cn(
"p-[3px]",
MAP_CONTROL_RADIUS_CLASS_NAME,
MAP_CONTROL_SURFACE_CLASS_NAME
)}
>
<ControlButton
icon={Home}
label="缩放到全局"
disabled={!mapReady}
onClick={onHome}
/>
</div>
</div>
</TooltipProvider>
);
}
type ControlButtonProps = {
icon: LucideIcon;
label: string;
disabled: boolean;
onClick: () => void;
};
function ControlButton({ icon: Icon, label, disabled, onClick }: ControlButtonProps) {
return (
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
aria-label={label}
disabled={disabled}
onClick={onClick}
className={cn(
"grid h-[38px] w-[38px] place-items-center transition duration-150",
MAP_ICON_CELL_RADIUS_CLASS_NAME,
"focus-visible:outline focus-visible:outline-2 focus-visible:outline-slate-900 focus-visible:outline-offset-2",
"bg-transparent text-slate-700",
MAP_CONTROL_HOVER_CLASS_NAME,
disabled &&
"cursor-not-allowed text-slate-400 opacity-55 hover:bg-transparent hover:text-slate-400 active:bg-transparent"
)}
>
<Icon size={18} strokeWidth={2.2} aria-hidden="true" />
</button>
</TooltipTrigger>
<TooltipContent
side="left"
sideOffset={8}
className="border border-slate-200 bg-white px-2.5 py-1.5 text-xs font-medium text-slate-800 shadow-lg"
>
{label}
</TooltipContent>
</Tooltip>
);
}
function Divider() {
return (
<div
className="my-0.5 h-px w-3.5 self-center bg-slate-300/70"
aria-hidden="true"
/>
);
}