{"version":3,"file":"useModuleBoundary.mjs","sources":["../../../../src/lib/vdom/hooks/useModuleBoundary.ts"],"sourcesContent":["/**\n * @file useModuleBoundary Hook\n * @module vdom/hooks/useModuleBoundary\n * @description Hook for accessing module boundary information including\n * slots, dimensions, visibility, and parent boundary context.\n *\n * @author Agent 5 - PhD Virtual DOM Expert\n * @version 1.0.0\n */\n\nimport type React from 'react';\nimport { useRef, useState, useCallback, useMemo, useEffect } from 'react';\nimport { type ReactNode } from 'react';\nimport { type UseModuleBoundaryReturn, type ModuleSlotDefinition } from '../types';\nimport { useModuleContext, useOptionalModuleContext } from '../ModuleBoundary';\nimport { useModuleHierarchy } from '../ModuleProviderExports';\n\n/**\n * Hook for accessing module boundary information and slot management.\n * Provides boundary element reference, slot operations, and visibility tracking.\n *\n * @returns Module boundary information and utilities\n * @throws Error if used outside a ModuleBoundary\n *\n * @example\n * ```tsx\n * function ModuleContent() {\n *   const {\n *     boundaryRef,\n *     slots,\n *     getSlot,\n *     fillSlot,\n *     dimensions,\n *     isVisible,\n *   } = useModuleBoundary();\n *\n *   useEffect(() => {\n *     // Fill a slot programmatically\n *     fillSlot('actions', <ActionButtons />);\n *\n *     return () => clearSlot('actions');\n *   }, [fillSlot, clearSlot]);\n *\n *   return (\n *     <div>\n *       <p>Module is {isVisible ? 'visible' : 'hidden'}</p>\n *       {dimensions && (\n *         <p>Size: {dimensions.width}x{dimensions.height}</p>\n *       )}\n *     </div>\n *   );\n * }\n * ```\n */\nexport function useModuleBoundary(): UseModuleBoundaryReturn {\n  const context = useModuleContext();\n\n  // Boundary element ref\n  const boundaryRef = useRef<HTMLElement>(null);\n\n  // Dimensions state\n  const [dimensions, setDimensions] = useState<DOMRect | null>(null);\n\n  // Visibility state (tracked separately for responsiveness)\n  const [isVisible, setIsVisible] = useState(context.state.isVisible);\n\n  // Get slots from config\n  const slots = useMemo<ReadonlyArray<ModuleSlotDefinition>>(\n    () => context.config.slots ?? [],\n    [context.config.slots]\n  );\n\n  // Slot getter\n  const getSlot = useCallback(\n    (name: string): ReactNode | null => {\n      return context.getSlot(name);\n    },\n    [context]\n  );\n\n  // Slot filler\n  const fillSlot = useCallback(\n    (name: string, content: ReactNode): void => {\n      context.setSlot(name, content);\n    },\n    [context]\n  );\n\n  // Slot clearer\n  const clearSlot = useCallback(\n    (name: string): void => {\n      context.setSlot(name, null);\n    },\n    [context]\n  );\n\n  // Get parent boundary info\n  const parentBoundary = useMemo<UseModuleBoundaryReturn | null>(() => {\n    if (!context.parent) {\n      return null;\n    }\n\n    // Create a simplified parent boundary interface\n    return {\n      boundaryRef: { current: null } as React.RefObject<HTMLElement | null>,\n      slots: context.parent.config.slots ?? [],\n      getSlot: context.parent.getSlot,\n      fillSlot: context.parent.setSlot,\n      clearSlot: (name: string): void => {\n        if (context.parent) {\n          context.parent.setSlot(name, null);\n        }\n      },\n      dimensions: null,\n      isVisible: context.parent.state.isVisible,\n      parentBoundary: null, // Don't recurse infinitely\n    };\n  }, [context.parent]);\n\n  // Track dimensions with ResizeObserver\n  useEffect(() => {\n    const element = boundaryRef.current;\n    if (!element) {\n      return;\n    }\n\n    const updateDimensions = (): void => {\n      setDimensions(element.getBoundingClientRect());\n    };\n\n    // Initial measurement\n    updateDimensions();\n\n    // Set up resize observer\n    const resizeObserver = new ResizeObserver(() => {\n      updateDimensions();\n    });\n\n    resizeObserver.observe(element);\n\n    // Also update on window resize/scroll\n    const handleViewportChange = (): void => {\n      updateDimensions();\n    };\n\n    window.addEventListener('resize', handleViewportChange);\n    window.addEventListener('scroll', handleViewportChange, { passive: true });\n\n    return () => {\n      resizeObserver.disconnect();\n      window.removeEventListener('resize', handleViewportChange);\n      window.removeEventListener('scroll', handleViewportChange);\n    };\n  }, []);\n\n  // Track visibility with IntersectionObserver\n  useEffect(() => {\n    const element = boundaryRef.current;\n    if (!element) {\n      return;\n    }\n\n    const observer = new IntersectionObserver(\n      (entries) => {\n        for (const entry of entries) {\n          setIsVisible(entry.isIntersecting);\n        }\n      },\n      {\n        rootMargin: '50px',\n        threshold: 0.1,\n      }\n    );\n\n    observer.observe(element);\n\n    return () => {\n      observer.disconnect();\n    };\n  }, []);\n\n  // Sync visibility with context\n  useEffect(() => {\n    context.dispatch({ type: 'SET_VISIBILITY', isVisible });\n  }, [context, isVisible]);\n\n  // Return memoized object\n  return useMemo<UseModuleBoundaryReturn>(\n    () => ({\n      boundaryRef,\n      slots,\n      getSlot,\n      fillSlot,\n      clearSlot,\n      dimensions,\n      isVisible,\n      parentBoundary,\n    }),\n    [slots, getSlot, fillSlot, clearSlot, dimensions, isVisible, parentBoundary]\n  );\n}\n\n/**\n * Hook to get the boundary element dimensions.\n * @returns Current dimensions or null if not measured\n *\n * @example\n * ```tsx\n * const dimensions = useBoundaryDimensions();\n *\n * if (dimensions && dimensions.width < 600) {\n *   return <MobileLayout />;\n * }\n * return <DesktopLayout />;\n * ```\n */\nexport function useBoundaryDimensions(): DOMRect | null {\n  const { dimensions } = useModuleBoundary();\n  return dimensions;\n}\n\n/**\n * Hook to check if the module boundary is visible in viewport.\n * @returns Whether boundary is visible\n */\nexport function useBoundaryVisibility(): boolean {\n  const { isVisible } = useModuleBoundary();\n  return isVisible;\n}\n\n/**\n * Hook to get the module hierarchy depth.\n * @returns Nesting depth (0 for root modules)\n */\nexport function useModuleDepth(): number {\n  const hierarchy = useModuleHierarchy();\n  return hierarchy.depth;\n}\n\n/**\n * Hook to get the full module path from root.\n * @returns Array of module IDs from root to current\n */\nexport function useModulePath(): string[] {\n  const hierarchy = useModuleHierarchy();\n  return [...hierarchy.path];\n}\n\n/**\n * Hook to check if current module is nested within another.\n * @returns Whether module has a parent\n */\nexport function useIsNestedModule(): boolean {\n  const hierarchy = useModuleHierarchy();\n  return hierarchy.depth > 1;\n}\n\n/**\n * Hook to get the parent module ID.\n * @returns Parent module ID or null if root\n */\nexport function useParentModuleId(): string | null {\n  const context = useOptionalModuleContext();\n  return context?.parent?.moduleId ?? null;\n}\n\n/**\n * Hook for slot-specific operations.\n * @param slotName - Name of the slot\n * @returns Slot content and operations\n *\n * @example\n * ```tsx\n * const { content, fill, clear, isFilled } = useSlot('sidebar');\n *\n * if (!isFilled) {\n *   return <DefaultSidebar />;\n * }\n * return content;\n * ```\n */\nexport function useSlot(slotName: string): {\n  content: ReactNode | null;\n  fill: (content: ReactNode) => void;\n  clear: () => void;\n  isFilled: boolean;\n} {\n  const { getSlot, fillSlot, clearSlot } = useModuleBoundary();\n\n  const content = getSlot(slotName);\n  const isFilled = content !== null && content !== undefined;\n\n  const fill = useCallback(\n    (newContent: ReactNode) => {\n      fillSlot(slotName, newContent);\n    },\n    [fillSlot, slotName]\n  );\n\n  const clear = useCallback(() => {\n    clearSlot(slotName);\n  }, [clearSlot, slotName]);\n\n  return useMemo(\n    () => ({\n      content,\n      fill,\n      clear,\n      isFilled,\n    }),\n    [content, fill, clear, isFilled]\n  );\n}\n\n/**\n * Hook to manage multiple slots at once.\n * @param slotNames - Array of slot names\n * @returns Map of slot operations by name\n */\nexport function useSlots(slotNames: string[]): Map<\n  string,\n  {\n    content: ReactNode | null;\n    fill: (content: ReactNode) => void;\n    clear: () => void;\n    isFilled: boolean;\n  }\n> {\n  const { getSlot, fillSlot, clearSlot } = useModuleBoundary();\n\n  return useMemo(() => {\n    const map = new Map<\n      string,\n      {\n        content: ReactNode | null;\n        fill: (content: ReactNode) => void;\n        clear: () => void;\n        isFilled: boolean;\n      }\n    >();\n\n    for (const name of slotNames) {\n      const content = getSlot(name);\n      map.set(name, {\n        content,\n        fill: (newContent: ReactNode) => fillSlot(name, newContent),\n        clear: () => clearSlot(name),\n        isFilled: content !== null && content !== undefined,\n      });\n    }\n\n    return map;\n  }, [slotNames, getSlot, fillSlot, clearSlot]);\n}\n"],"names":["useModuleBoundary","context","useModuleContext","boundaryRef","useRef","dimensions","setDimensions","useState","isVisible","setIsVisible","slots","useMemo","getSlot","useCallback","name","fillSlot","content","clearSlot","parentBoundary","useEffect","element","updateDimensions","resizeObserver","handleViewportChange","observer","entries","entry","useBoundaryDimensions","useBoundaryVisibility","useModuleDepth","useModuleHierarchy","useModulePath","useIsNestedModule","useParentModuleId","useOptionalModuleContext","useSlot","slotName","isFilled","fill","newContent","clear","useSlots","slotNames","map"],"mappings":"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"}