/** * GraphQL Identifier Popover using Radix Themes * * Displays rich information about GraphQL identifiers on hover/click */ import type { React } from '#dep/react/index' import { Cross2Icon } from '@radix-ui/react-icons' import { Badge, Box, Flex, IconButton, Link, Popover, Text } from '@radix-ui/themes' import type { Documentation } from '../schema-integration.js' import type { Identifier } from '../types.js' export interface GraphQLIdentifierPopoverProps { /** The identifier being shown */ identifier: Identifier /** Documentation from schema */ documentation: Documentation /** Whether this identifier has an error */ hasError?: boolean /** Reference URL for "View docs" link */ referenceUrl: string /** Whether popover is open */ open: boolean /** Whether popover is pinned */ isPinned: boolean /** Callback when open state changes */ onOpenChange: (open: boolean) => void /** Callback to navigate to docs */ onNavigate?: (url: string) => void /** The trigger element */ children: React.ReactNode } /** * Popover content for GraphQL identifiers */ export const GraphQLIdentifierPopover: React.FC = ({ identifier, documentation, hasError = false, referenceUrl, open, isPinned, onOpenChange, onNavigate, children, }) => { // Determine badge color based on identifier kind const getBadgeColor = () => { switch (identifier.kind) { case `Type`: return `blue` case `Field`: return `green` case `Argument`: return `orange` case `Variable`: return `purple` case `Directive`: return `amber` case `Fragment`: return `cyan` default: return `gray` } } return ( {children} { // Prevent closing when clicking inside popover if pinned if (isPinned) { e.preventDefault() } }} > {/* Header with name, kind, and close button */} {identifier.name} {identifier.kind} {isPinned && ( { onOpenChange(false) }} aria-label='Close popover' > )} {/* Type signature */} Type: {documentation.typeInfo} {/* Description */} {documentation.description && ( {documentation.description} )} {/* Default value for arguments */} {documentation.defaultValue && ( Default:{` `} {documentation.defaultValue} )} {/* Deprecation warning */} {documentation.deprecated && ( ⚠️ Deprecated: {documentation.deprecated.reason} {documentation.deprecated.replacement && ( Use {documentation.deprecated.replacement} instead. )} )} {/* Error message */} {hasError && ( ❌ {identifier.kind} not found in schema )} {/* Schema path */} Path: {identifier.schemaPath.join(` → `)} {/* View docs link */} {onNavigate && !hasError && ( { e.preventDefault() onNavigate(referenceUrl) onOpenChange(false) }} > View full documentation → )} ) }