{"version":3,"file":"progressive-enhancement.mjs","sources":["../../../src/lib/ux/progressive-enhancement.tsx"],"sourcesContent":["/**\n * @file Progressive Enhancement System\n * @description PhD-level progressive feature loading with capability detection,\n * graceful degradation, and feature negotiation for optimal user experience.\n *\n * Features:\n * - Capability-based feature loading\n * - Progressive feature availability\n * - Graceful degradation paths\n * - Feature negotiation system\n * - Polyfill coordination\n */\n\nimport React, { useState, useEffect, useCallback, useMemo, type ReactNode } from 'react';\nimport {\n  ProgressiveEnhancementContext,\n  type ProgressiveEnhancementContextValue,\n} from '../contexts/ProgressiveEnhancementContext';\nimport {\n  checkWebPSupport,\n  checkAVIFSupport,\n  detectCapabilities,\n  createFeature as createFeatureUtil,\n  type BrowserCapabilities,\n} from './progressive-enhancement-utils';\nimport {\n  useProgressiveEnhancement,\n  useProgressiveFeature,\n  useCapability,\n  useCapabilities,\n  useCapabilityConditional,\n} from './progressive-enhancement-hooks';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Feature capability levels\n */\nexport type CapabilityLevel = 'full' | 'partial' | 'fallback' | 'none';\n\n// Re-export BrowserCapabilities from utils for convenience\nexport type { BrowserCapabilities } from './progressive-enhancement-utils';\n\n/**\n * Feature definition\n */\nexport interface FeatureDefinition {\n  /** Feature identifier */\n  id: string;\n  /** Human-readable name */\n  name: string;\n  /** Required capabilities */\n  requires: Array<keyof BrowserCapabilities>;\n  /** Optional capabilities for enhanced experience */\n  enhancedBy?: Array<keyof BrowserCapabilities>;\n  /** Loader function */\n  loader: () => Promise<unknown>;\n  /** Fallback loader */\n  fallbackLoader?: () => Promise<unknown>;\n  /** Polyfills to load */\n  polyfills?: Array<() => Promise<void>>;\n  /** Priority (higher = load first) */\n  priority?: number;\n}\n\n/**\n * Feature status\n */\nexport interface FeatureStatus {\n  /** Feature ID */\n  id: string;\n  /** Capability level */\n  level: CapabilityLevel;\n  /** Is loaded */\n  loaded: boolean;\n  /** Is loading */\n  loading: boolean;\n  /** Load error */\n  error: Error | null;\n  /** Loaded module */\n  module: unknown;\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport interface ProgressiveEnhancementProviderProps {\n  children: ReactNode;\n  /** Initial feature definitions */\n  features?: FeatureDefinition[];\n  /** On capability detection complete */\n  onCapabilitiesDetected?: (capabilities: BrowserCapabilities) => void;\n}\n\n/**\n * Progressive enhancement provider\n */\nexport function ProgressiveEnhancementProvider({\n  children,\n  features: initialFeatures = [],\n  onCapabilitiesDetected,\n}: ProgressiveEnhancementProviderProps): React.ReactElement {\n  const [capabilities, setCapabilities] = useState<BrowserCapabilities>(() => {\n    return detectCapabilities();\n  });\n  const [featureDefinitions] = useState<Map<string, FeatureDefinition>>(\n    () => new Map(initialFeatures.map((f) => [f.id, f]))\n  );\n  const [featureStatuses, setFeatureStatuses] = useState<Map<string, FeatureStatus>>(new Map());\n\n  // Async capability detection\n  useEffect(() => {\n    async function detectAsyncCapabilities(): Promise<void> {\n      const [webP, avif] = await Promise.all([checkWebPSupport(), checkAVIFSupport()]);\n\n      setCapabilities((prev: BrowserCapabilities) => {\n        const updated: BrowserCapabilities = { ...prev, webP, avif };\n        onCapabilitiesDetected?.(updated);\n        return updated;\n      });\n    }\n\n    void detectAsyncCapabilities();\n  }, [onCapabilitiesDetected]);\n\n  /**\n   * Check if has capability\n   */\n  const hasCapability = useCallback(\n    (capability: keyof BrowserCapabilities): boolean => {\n      return capabilities[capability];\n    },\n    [capabilities]\n  );\n\n  /**\n   * Get feature capability level\n   */\n  const getFeatureLevel = useCallback(\n    (id: string): CapabilityLevel => {\n      const definition = featureDefinitions.get(id);\n      if (!definition) return 'none';\n\n      const hasRequired = definition.requires.every((cap) => capabilities[cap]);\n      if (!hasRequired) {\n        return definition.fallbackLoader ? 'fallback' : 'none';\n      }\n\n      const hasEnhanced = definition.enhancedBy?.every((cap) => capabilities[cap]) ?? true;\n      return hasEnhanced ? 'full' : 'partial';\n    },\n    [featureDefinitions, capabilities]\n  );\n\n  /**\n   * Load feature\n   */\n  const loadFeature = useCallback(\n    async (id: string): Promise<unknown> => {\n      const definition = featureDefinitions.get(id);\n      if (!definition) {\n        throw new Error(`Feature not found: ${id}`);\n      }\n\n      // Check existing status\n      const existing = featureStatuses.get(id);\n      if (existing?.loaded === true) {\n        return existing.module;\n      }\n\n      // Update loading status\n      setFeatureStatuses((prev) =>\n        new Map(prev).set(id, {\n          id,\n          level: getFeatureLevel(id),\n          loaded: false,\n          loading: true,\n          error: null,\n          module: null,\n        })\n      );\n\n      try {\n        // Load polyfills first\n        if (definition.polyfills) {\n          await Promise.all(definition.polyfills.map(async (p) => p()));\n        }\n\n        // Determine which loader to use\n        const level = getFeatureLevel(id);\n        let module: unknown;\n\n        if (level === 'fallback' && definition.fallbackLoader) {\n          module = await definition.fallbackLoader();\n        } else if (level !== 'none') {\n          module = await definition.loader();\n        } else {\n          throw new Error(`Feature ${id} is not supported`);\n        }\n\n        // Update status\n        setFeatureStatuses((prev) =>\n          new Map(prev).set(id, {\n            id,\n            level,\n            loaded: true,\n            loading: false,\n            error: null,\n            module,\n          })\n        );\n\n        return module;\n      } catch (error) {\n        setFeatureStatuses((prev) =>\n          new Map(prev).set(id, {\n            id,\n            level: 'none',\n            loaded: false,\n            loading: false,\n            error: error instanceof Error ? error : new Error(String(error)),\n            module: null,\n          })\n        );\n        throw error;\n      }\n    },\n    [featureDefinitions, featureStatuses, getFeatureLevel]\n  );\n\n  /**\n   * Register a feature\n   */\n  const registerFeature = useCallback(\n    (definition: FeatureDefinition): void => {\n      featureDefinitions.set(definition.id, definition);\n    },\n    [featureDefinitions]\n  );\n\n  const value = useMemo<ProgressiveEnhancementContextValue>(\n    () => ({\n      capabilities,\n      features: featureStatuses,\n      loadFeature,\n      hasCapability,\n      getFeatureLevel,\n      registerFeature,\n    }),\n    [capabilities, featureStatuses, loadFeature, hasCapability, getFeatureLevel, registerFeature]\n  );\n\n  return (\n    <ProgressiveEnhancementContext.Provider value={value}>\n      {children}\n    </ProgressiveEnhancementContext.Provider>\n  );\n}\n\n// ============================================================================\n// Components\n// ============================================================================\n\ninterface CapabilityGateProps {\n  capability: keyof BrowserCapabilities;\n  children: ReactNode;\n  fallback?: ReactNode;\n}\n\n/**\n * Render children only if capability is supported\n */\nexport function CapabilityGate({\n  capability,\n  children,\n  fallback = null,\n}: CapabilityGateProps): React.ReactElement {\n  const hasCapability = useCapability(capability);\n  return <>{hasCapability ? children : fallback}</>;\n}\n\ninterface FeatureGateProps {\n  featureId: string;\n  children: ReactNode | ((module: unknown) => ReactNode);\n  loading?: ReactNode;\n  fallback?: ReactNode;\n  errorFallback?: ReactNode | ((error: Error) => ReactNode);\n}\n\n/**\n * Render children when feature is loaded\n */\nexport function FeatureGate({\n  featureId,\n  children,\n  loading: loadingFallback = null,\n  fallback = null,\n  errorFallback,\n}: FeatureGateProps): React.ReactElement {\n  const { module, level, loading, error } = useProgressiveFeature(featureId);\n\n  if (loading) return <>{loadingFallback}</>;\n  if (error != null) {\n    if (errorFallback != null) {\n      return <>{typeof errorFallback === 'function' ? errorFallback(error) : errorFallback}</>;\n    }\n    return <>{fallback}</>;\n  }\n  if (level === 'none') return <>{fallback}</>;\n  if (module == null) return <>{fallback}</>;\n\n  return <>{typeof children === 'function' ? children(module) : children}</>;\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport default {\n  ProgressiveEnhancementProvider,\n  useProgressiveEnhancement,\n  useProgressiveFeature,\n  useCapability,\n  useCapabilities,\n  useCapabilityConditional,\n  CapabilityGate,\n  FeatureGate,\n  createFeature: createFeatureUtil,\n  checkWebPSupport,\n  checkAVIFSupport,\n};\n"],"names":["ProgressiveEnhancementProvider","children","initialFeatures","onCapabilitiesDetected","capabilities","setCapabilities","useState","detectCapabilities","featureDefinitions","f","featureStatuses","setFeatureStatuses","useEffect","detectAsyncCapabilities","webP","avif","checkWebPSupport","checkAVIFSupport","prev","updated","hasCapability","useCallback","capability","getFeatureLevel","id","definition","cap","loadFeature","existing","p","level","module","error","registerFeature","value","useMemo","jsx","ProgressiveEnhancementContext","CapabilityGate","fallback","useCapability","Fragment","FeatureGate","featureId","loadingFallback","errorFallback","loading","useProgressiveFeature"],"mappings":"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"}