import {
ChevronLeft,
ChevronRight,
Download,
Maximize2,
Minus,
Plus,
StretchHorizontal,
} from "lucide-react";
import { useEffect, useId, useState, type ReactNode } from "react";
import type { FitMode } from "../../hooks/use-pdf-pages";
import { MAX_ZOOM, MIN_ZOOM } from "../../lib/pdf";
import { Button } from "../ui/button";
import { Input } from "../ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
export type PdfToolbarProps = {
page: number;
numPages: number;
/** Logical zoom (1 = 100%). */
zoom: number;
fitMode: FitMode;
/** When true, all interactive controls are disabled (empty / zero-page). */
disabled?: boolean;
downloadUrl: string;
onPageChange: (page: number) => void;
onZoomIn: () => void;
onZoomOut: () => void;
/** Commit an exact zoom level (1 = 100%) from the zoom-level combobox. */
onZoomTo: (level: number) => void;
onFitMode: (mode: "width" | "page") => void;
};
/**
* Fixed zoom stops, all inside the viewer's existing MIN_ZOOM (0.25) /
* MAX_ZOOM (4) bounds — no new zoom math and no new bounds. 100% is the
* default level and is marked as such in its accessible name.
*/
export const ZOOM_STOPS = [0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4] as const;
function zoomStopLabel(level: number): string {
return `${Math.round(level * 100)}%`;
}
function clampPage(raw: number, numPages: number): number {
if (!Number.isFinite(raw) || numPages < 1) {
return 1;
}
return Math.min(numPages, Math.max(1, Math.trunc(raw)));
}
/**
* Digits-only finite values (including 0) are numeric and clamp to 1..N.
* Empty / non-numeric → null (caller reverts, no callback).
*/
function parsePageDraft(draft: string, numPages: number): number | null {
const trimmed = draft.trim();
if (!trimmed || !/^\d+$/u.test(trimmed)) {
return null;
}
const n = Number(trimmed);
if (!Number.isFinite(n)) {
return null;
}
return clampPage(n, numPages);
}
function IconButton({
label,
disabled,
onClick,
children,
testId,
pressed,
}: {
label: string;
disabled?: boolean;
onClick?: () => void;
children: ReactNode;
testId?: string;
pressed?: boolean;
}) {
return (