{"version":3,"file":"responsiveUtils-BOo77N0U.mjs","names":["width: number","userAgent: string","values: Partial<Record<Breakpoint, T>>","fallback: T","breakpointOrder: Breakpoint[]","targetBreakpoint: Breakpoint","containerWidth?: number","containerHeight?: number"],"sources":["../../src/utils/responsiveUtils.ts"],"sourcesContent":["/**\n * Responsive Design Utilities\n *\n * Utilities for handling responsive design and adaptive layouts\n * in Circuit-Bricks across different screen sizes and devices.\n */\n\nimport { useState, useEffect } from 'react';\nimport { isBrowser } from './ssrUtils';\n\n/**\n * Breakpoint definitions\n */\nexport const breakpoints = {\n  xs: 0,\n  sm: 576,\n  md: 768,\n  lg: 992,\n  xl: 1200,\n  xxl: 1400\n} as const;\n\nexport type Breakpoint = keyof typeof breakpoints;\n\n/**\n * Device type detection\n */\nexport type DeviceType = 'mobile' | 'tablet' | 'desktop';\n\n/**\n * Screen size information\n */\nexport interface ScreenInfo {\n  width: number;\n  height: number;\n  breakpoint: Breakpoint;\n  deviceType: DeviceType;\n  isPortrait: boolean;\n  isLandscape: boolean;\n  pixelRatio: number;\n}\n\n/**\n * Get current breakpoint based on width\n */\nexport const getBreakpoint = (width: number): Breakpoint => {\n  if (width >= breakpoints.xxl) return 'xxl';\n  if (width >= breakpoints.xl) return 'xl';\n  if (width >= breakpoints.lg) return 'lg';\n  if (width >= breakpoints.md) return 'md';\n  if (width >= breakpoints.sm) return 'sm';\n  return 'xs';\n};\n\n/**\n * Get device type based on width and user agent\n */\nexport const getDeviceType = (width: number, userAgent: string = ''): DeviceType => {\n  // Check user agent for mobile/tablet indicators\n  const isMobileUA = /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);\n  const isTabletUA = /iPad|Android(?!.*Mobile)/i.test(userAgent);\n\n  if (isMobileUA || width < breakpoints.md) return 'mobile';\n  if (isTabletUA || (width >= breakpoints.md && width < breakpoints.lg)) return 'tablet';\n  return 'desktop';\n};\n\n/**\n * Hook for responsive screen information\n */\nexport const useScreenInfo = (): ScreenInfo => {\n  const [screenInfo, setScreenInfo] = useState<ScreenInfo>({\n    width: 1024,\n    height: 768,\n    breakpoint: 'lg',\n    deviceType: 'desktop',\n    isPortrait: false,\n    isLandscape: true,\n    pixelRatio: 1\n  });\n\n  useEffect(() => {\n    if (!isBrowser()) return;\n\n    const updateScreenInfo = () => {\n      const width = window.innerWidth;\n      const height = window.innerHeight;\n      const breakpoint = getBreakpoint(width);\n      const deviceType = getDeviceType(width, navigator.userAgent);\n      const isPortrait = height > width;\n      const isLandscape = !isPortrait;\n      const pixelRatio = window.devicePixelRatio || 1;\n\n      setScreenInfo({\n        width,\n        height,\n        breakpoint,\n        deviceType,\n        isPortrait,\n        isLandscape,\n        pixelRatio\n      });\n    };\n\n    updateScreenInfo();\n\n    window.addEventListener('resize', updateScreenInfo);\n    window.addEventListener('orientationchange', updateScreenInfo);\n\n    return () => {\n      window.removeEventListener('resize', updateScreenInfo);\n      window.removeEventListener('orientationchange', updateScreenInfo);\n    };\n  }, []);\n\n  return screenInfo;\n};\n\n/**\n * Hook for breakpoint-specific values\n */\nexport const useBreakpointValue = <T>(values: Partial<Record<Breakpoint, T>>, fallback: T): T => {\n  const { breakpoint } = useScreenInfo();\n\n  // Find the best matching value for current breakpoint\n  const breakpointOrder: Breakpoint[] = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];\n  const currentIndex = breakpointOrder.indexOf(breakpoint);\n\n  // Look for exact match first\n  if (values[breakpoint] !== undefined) {\n    return values[breakpoint]!;\n  }\n\n  // Look for smaller breakpoints (mobile-first approach)\n  for (let i = currentIndex - 1; i >= 0; i--) {\n    const bp = breakpointOrder[i];\n    if (values[bp] !== undefined) {\n      return values[bp]!;\n    }\n  }\n\n  // Look for larger breakpoints only if no smaller ones found\n  for (let i = currentIndex + 1; i < breakpointOrder.length; i++) {\n    const bp = breakpointOrder[i];\n    if (values[bp] !== undefined) {\n      return values[bp]!;\n    }\n  }\n\n  return fallback;\n};\n\n/**\n * Responsive grid configuration\n */\nexport interface ResponsiveGridConfig {\n  gridSize: number;\n  snapThreshold: number;\n  minZoom: number;\n  maxZoom: number;\n  zoomStep: number;\n  panSensitivity: number;\n}\n\n/**\n * Get responsive grid configuration based on device type\n */\nexport const useResponsiveGridConfig = (): ResponsiveGridConfig => {\n  const { deviceType } = useScreenInfo();\n\n  return useBreakpointValue<ResponsiveGridConfig>({\n    xs: {\n      gridSize: 15,\n      snapThreshold: 12,\n      minZoom: 0.25,\n      maxZoom: 3,\n      zoomStep: 0.15,\n      panSensitivity: 1.2\n    },\n    sm: {\n      gridSize: 18,\n      snapThreshold: 15,\n      minZoom: 0.3,\n      maxZoom: 4,\n      zoomStep: 0.2,\n      panSensitivity: 1.1\n    },\n    md: {\n      gridSize: 20,\n      snapThreshold: 18,\n      minZoom: 0.4,\n      maxZoom: 5,\n      zoomStep: 0.25,\n      panSensitivity: 1.0\n    },\n    lg: {\n      gridSize: 25,\n      snapThreshold: 20,\n      minZoom: 0.5,\n      maxZoom: 8,\n      zoomStep: 0.3,\n      panSensitivity: 0.9\n    },\n    xl: {\n      gridSize: 30,\n      snapThreshold: 25,\n      minZoom: 0.1,\n      maxZoom: 10,\n      zoomStep: 0.5,\n      panSensitivity: 0.8\n    }\n  }, {\n    gridSize: 20,\n    snapThreshold: 18,\n    minZoom: 0.1,\n    maxZoom: 10,\n    zoomStep: 0.25,\n    panSensitivity: 1.0\n  });\n};\n\n/**\n * Responsive component sizing\n */\nexport interface ResponsiveComponentConfig {\n  minComponentSize: number;\n  maxComponentSize: number;\n  portSize: number;\n  wireStrokeWidth: number;\n  fontSize: number;\n  iconSize: number;\n}\n\n/**\n * Get responsive component configuration\n */\nexport const useResponsiveComponentConfig = (): ResponsiveComponentConfig => {\n  return useBreakpointValue<ResponsiveComponentConfig>({\n    xs: {\n      minComponentSize: 30,\n      maxComponentSize: 80,\n      portSize: 6,\n      wireStrokeWidth: 2,\n      fontSize: 10,\n      iconSize: 16\n    },\n    sm: {\n      minComponentSize: 35,\n      maxComponentSize: 90,\n      portSize: 7,\n      wireStrokeWidth: 2.5,\n      fontSize: 11,\n      iconSize: 18\n    },\n    md: {\n      minComponentSize: 40,\n      maxComponentSize: 100,\n      portSize: 8,\n      wireStrokeWidth: 3,\n      fontSize: 12,\n      iconSize: 20\n    },\n    lg: {\n      minComponentSize: 50,\n      maxComponentSize: 120,\n      portSize: 10,\n      wireStrokeWidth: 3,\n      fontSize: 14,\n      iconSize: 24\n    },\n    xl: {\n      minComponentSize: 60,\n      maxComponentSize: 150,\n      portSize: 12,\n      wireStrokeWidth: 4,\n      fontSize: 16,\n      iconSize: 28\n    }\n  }, {\n    minComponentSize: 40,\n    maxComponentSize: 100,\n    portSize: 8,\n    wireStrokeWidth: 3,\n    fontSize: 12,\n    iconSize: 20\n  });\n};\n\n/**\n * Check if current screen matches a breakpoint\n */\nexport const useMatchesBreakpoint = (targetBreakpoint: Breakpoint): boolean => {\n  const { breakpoint } = useScreenInfo();\n  const breakpointOrder: Breakpoint[] = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];\n  const currentIndex = breakpointOrder.indexOf(breakpoint);\n  const targetIndex = breakpointOrder.indexOf(targetBreakpoint);\n\n  return currentIndex >= targetIndex;\n};\n\n/**\n * Get optimal canvas dimensions for current screen\n */\nexport const useOptimalCanvasDimensions = (\n  containerWidth?: number,\n  containerHeight?: number\n): { width: number; height: number } => {\n  const { width: screenWidth, height: screenHeight, deviceType } = useScreenInfo();\n\n  const width = containerWidth || screenWidth;\n  const height = containerHeight || screenHeight;\n\n  // Adjust for mobile devices to account for virtual keyboards and UI\n  if (deviceType === 'mobile') {\n    return {\n      width: Math.min(width, screenWidth * 0.95),\n      height: Math.min(height, screenHeight * 0.8)\n    };\n  }\n\n  if (deviceType === 'tablet') {\n    return {\n      width: Math.min(width, screenWidth * 0.98),\n      height: Math.min(height, screenHeight * 0.9)\n    };\n  }\n\n  return { width, height };\n};\n"],"mappings":"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"}