"use client"; import pillStyles from "@prototype/components/prototypes/prototype-floating-pill.module.scss"; import { PrototypeComponent } from "@prototype/components/prototypes/prototype-target"; import { Tabs, TabsList, TabsTrigger } from "@prototype/components/ui/tabs"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@prototype/components/ui/tooltip"; import { cn } from "@prototype/lib/utils"; import { getAdjacentDesignExplorationVariant, type DesignExplorationVariantOption, } from "@prototype/lib/prototypes/design-exploration-types"; import { useTrackEvent } from "@prototype/lib/prototypes/telemetry/prototype-telemetry-context"; import { useCallback, useEffect, useState } from "react"; type PrototypeVariantTabsProps = { idPrefix: string; options: DesignExplorationVariantOption[]; value: TVariant; onValueChange: (value: TVariant) => void; /** When true, ArrowLeft/ArrowRight cycle variants (unless a lightbox is open). */ keyboardScopeActive?: boolean; className?: string; /** Disambiguates comment targets when multiple tab strips could mount. */ surface?: "inline" | "modal"; variantTabAriaLabel?: string; /** Shown with a marker when this option is not the active tab. */ defaultVariantValue?: TVariant; /** Dark styling for the review chrome floating popover. */ appearance?: "light" | "dark"; /** Tab trigger content — footer chrome uses labels; modals default to index numbers. */ tabDisplay?: "index" | "label"; }; function getVariantTabsId(idPrefix: string, surface: "inline" | "modal", segment: string) { return surface === "modal" ? `${idPrefix}.modal.${segment}` : `${idPrefix}.${segment}`; } function isTypingTarget(target: EventTarget | null) { if (!(target instanceof HTMLElement)) return false; const tag = target.tagName; return tag === "INPUT" || tag === "TEXTAREA" || target.isContentEditable; } export function PrototypeVariantTabs({ idPrefix, options, value, onValueChange, keyboardScopeActive = true, className, surface = "inline", variantTabAriaLabel = "variant", defaultVariantValue, appearance = "dark", tabDisplay = "index", }: PrototypeVariantTabsProps) { const [keyboardNavEngaged, setKeyboardNavEngaged] = useState(false); const track = useTrackEvent(); const goPrev = useCallback(() => { onValueChange(getAdjacentDesignExplorationVariant(options, value, "prev")); }, [onValueChange, options, value]); const goNext = useCallback(() => { onValueChange(getAdjacentDesignExplorationVariant(options, value, "next")); }, [onValueChange, options, value]); const engageKeyboardNav = useCallback(() => { setKeyboardNavEngaged(true); }, []); const handleArrowNavigation = useCallback( (direction: "prev" | "next") => { if (direction === "prev") { goPrev(); } else { goNext(); } }, [goNext, goPrev], ); useEffect(() => { if (!keyboardScopeActive) { setKeyboardNavEngaged(false); } }, [keyboardScopeActive]); useEffect(() => { if (!keyboardScopeActive || !keyboardNavEngaged) return; function handleKeyDown(event: globalThis.KeyboardEvent) { if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return; if (isTypingTarget(event.target)) return; if (document.querySelector("[data-mobbin-lightbox-open]")) return; event.preventDefault(); handleArrowNavigation(event.key === "ArrowLeft" ? "prev" : "next"); } document.addEventListener("keydown", handleKeyDown, true); return () => document.removeEventListener("keydown", handleKeyDown, true); }, [handleArrowNavigation, keyboardNavEngaged, keyboardScopeActive]); const activeIndex = options.findIndex((option) => option.value === value); const rootId = surface === "modal" ? `${idPrefix}.modal` : idPrefix; const isDark = appearance === "dark"; const showLabel = tabDisplay === "label"; function getTabTriggerContent( option: DesignExplorationVariantOption, index: number, ) { return showLabel ? option.label : index + 1; } return ( { engageKeyboardNav(); onValueChange(nextValue as TVariant); track("variant.selected", { variant: nextValue, idPrefix }); }} className="min-w-0" > {options.map((option, index) => { const isDefaultOption = defaultVariantValue !== undefined && option.value === defaultVariantValue; const isDefaultWhenUnselected = isDefaultOption && option.value !== value; const tabClassName = cn( "shrink-0", !showLabel && "min-w-8 tabular-nums", showLabel && "max-w-[10rem] truncate px-2.5", !isDark && !showLabel && "px-2", isDefaultWhenUnselected && (isDark ? pillStyles.variantsDefaultTab : "bg-muted text-foreground"), isDark && pillStyles.variantsTab, ); const tabId = `${idPrefix}-tab-${surface}-${option.value}`; const defaultTabAriaLabel = `${variantTabAriaLabel} ${index + 1}: ${option.label}, selected`; if (!isDefaultOption) { return ( {getTabTriggerContent(option, index)} ); } return ( {getTabTriggerContent(option, index)} Selected ); })} {`${activeIndex + 1} of ${options.length}: ${options[activeIndex]?.label ?? ""}`} ); }