UNPKG

circuit-bricks

Version:

A modular, Lego-style SVG circuit component system for React (ALPHA - Not for production use)

1 lines 11.6 kB
{"version":3,"file":"ssrUtils-Ca211nnK.mjs","names":["getBrowserValue: () => T","fallbackValue: T | null","key: string","value: string","selector: string","element: Element | Window | Document | null","event: string","handler: EventListener","options?: AddEventListenerOptions","options?: EventListenerOptions","query: string","event: MediaQueryListEvent"],"sources":["../../src/utils/ssrUtils.ts"],"sourcesContent":["/**\n * SSR (Server-Side Rendering) Utilities\n *\n * Utilities for handling server-side rendering compatibility and hydration safety.\n * These utilities help prevent client-server mismatch errors and ensure components\n * work correctly in SSR environments like Next.js, Gatsby, and Remix.\n */\n\nimport { useEffect, useState } from 'react';\n\n/**\n * Check if code is running in a browser environment\n */\nexport const isBrowser = (): boolean => {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n};\n\n/**\n * Check if code is running on the server\n */\nexport const isServer = (): boolean => {\n return !isBrowser();\n};\n\n/**\n * Safe access to window object\n */\nexport const safeWindow = (): Window | null => {\n return isBrowser() ? window : null;\n};\n\n/**\n * Safe access to document object\n */\nexport const safeDocument = (): Document | null => {\n return isBrowser() ? document : null;\n};\n\n/**\n * Hook to detect when component has hydrated on the client\n * This prevents hydration mismatches by ensuring client-only code\n * only runs after hydration is complete.\n */\nexport const useIsClient = (): boolean => {\n const [isClient, setIsClient] = useState(false);\n\n useEffect(() => {\n setIsClient(true);\n }, []);\n\n return isClient;\n};\n\n/**\n * Hook to safely access browser APIs after hydration\n * Returns null during SSR and initial render, then the actual value after hydration\n */\nexport const useSafeBrowserAPI = <T>(\n getBrowserValue: () => T,\n fallbackValue: T | null = null\n): T | null => {\n const isClient = useIsClient();\n const [value, setValue] = useState<T | null>(fallbackValue);\n\n useEffect(() => {\n if (isClient) {\n try {\n setValue(getBrowserValue());\n } catch (error) {\n console.warn('Error accessing browser API:', error);\n setValue(fallbackValue);\n }\n }\n }, [isClient, getBrowserValue, fallbackValue]);\n\n return isClient ? value : fallbackValue;\n};\n\n/**\n * SSR-safe localStorage access\n */\nexport const safeLocalStorage = {\n getItem: (key: string): string | null => {\n if (!isBrowser()) return null;\n try {\n return localStorage.getItem(key);\n } catch (error) {\n console.warn('Error accessing localStorage:', error);\n return null;\n }\n },\n\n setItem: (key: string, value: string): boolean => {\n if (!isBrowser()) return false;\n try {\n localStorage.setItem(key, value);\n return true;\n } catch (error) {\n console.warn('Error setting localStorage:', error);\n return false;\n }\n },\n\n removeItem: (key: string): boolean => {\n if (!isBrowser()) return false;\n try {\n localStorage.removeItem(key);\n return true;\n } catch (error) {\n console.warn('Error removing from localStorage:', error);\n return false;\n }\n }\n};\n\n/**\n * SSR-safe sessionStorage access\n */\nexport const safeSessionStorage = {\n getItem: (key: string): string | null => {\n if (!isBrowser()) return null;\n try {\n return sessionStorage.getItem(key);\n } catch (error) {\n console.warn('Error accessing sessionStorage:', error);\n return null;\n }\n },\n\n setItem: (key: string, value: string): boolean => {\n if (!isBrowser()) return false;\n try {\n sessionStorage.setItem(key, value);\n return true;\n } catch (error) {\n console.warn('Error setting sessionStorage:', error);\n return false;\n }\n },\n\n removeItem: (key: string): boolean => {\n if (!isBrowser()) return false;\n try {\n sessionStorage.removeItem(key);\n return true;\n } catch (error) {\n console.warn('Error removing from sessionStorage:', error);\n return false;\n }\n }\n};\n\n/**\n * SSR-safe DOM query selector\n */\nexport const safeQuerySelector = (selector: string): Element | null => {\n if (!isBrowser()) return null;\n try {\n return document.querySelector(selector);\n } catch (error) {\n console.warn('Error querying DOM:', error);\n return null;\n }\n};\n\n/**\n * SSR-safe DOM query selector all\n */\nexport const safeQuerySelectorAll = (selector: string): NodeListOf<Element> | null => {\n if (!isBrowser()) return null;\n try {\n return document.querySelectorAll(selector);\n } catch (error) {\n console.warn('Error querying DOM:', error);\n return null;\n }\n};\n\n/**\n * SSR-safe event listener management\n */\nexport const safeEventListener = {\n add: (\n element: Element | Window | Document | null,\n event: string,\n handler: EventListener,\n options?: AddEventListenerOptions\n ): boolean => {\n if (!isBrowser() || !element) return false;\n try {\n element.addEventListener(event, handler, options);\n return true;\n } catch (error) {\n console.warn('Error adding event listener:', error);\n return false;\n }\n },\n\n remove: (\n element: Element | Window | Document | null,\n event: string,\n handler: EventListener,\n options?: EventListenerOptions\n ): boolean => {\n if (!isBrowser() || !element) return false;\n try {\n element.removeEventListener(event, handler, options);\n return true;\n } catch (error) {\n console.warn('Error removing event listener:', error);\n return false;\n }\n }\n};\n\n/**\n * SSR-safe viewport dimensions\n */\nexport const useViewportDimensions = () => {\n const [dimensions, setDimensions] = useState({\n width: 1024, // Default fallback values\n height: 768\n });\n\n useEffect(() => {\n if (!isBrowser()) return;\n\n const updateDimensions = () => {\n setDimensions({\n width: window.innerWidth,\n height: window.innerHeight\n });\n };\n\n // Set initial dimensions\n updateDimensions();\n\n // Listen for resize events\n window.addEventListener('resize', updateDimensions);\n\n return () => {\n window.removeEventListener('resize', updateDimensions);\n };\n }, []);\n\n return dimensions;\n};\n\n/**\n * SSR-safe media query hook\n */\nexport const useMediaQuery = (query: string): boolean => {\n const [matches, setMatches] = useState(false);\n\n useEffect(() => {\n if (!isBrowser()) return;\n\n const mediaQuery = window.matchMedia(query);\n setMatches(mediaQuery.matches);\n\n const handler = (event: MediaQueryListEvent) => {\n setMatches(event.matches);\n };\n\n mediaQuery.addEventListener('change', handler);\n\n return () => {\n mediaQuery.removeEventListener('change', handler);\n };\n }, [query]);\n\n return matches;\n};\n\n/**\n * SSR-safe user agent detection\n */\nexport const useUserAgent = () => {\n const [userAgent, setUserAgent] = useState('');\n\n useEffect(() => {\n if (isBrowser()) {\n setUserAgent(navigator.userAgent);\n }\n }, []);\n\n return userAgent;\n};\n\n/**\n * Detect mobile devices\n */\nexport const useIsMobile = (): boolean => {\n const userAgent = useUserAgent();\n const isSmallScreen = useMediaQuery('(max-width: 768px)');\n\n const isMobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);\n\n return isMobileUA || isSmallScreen;\n};\n\n/**\n * Detect touch support\n */\nexport const useHasTouchSupport = (): boolean => {\n const [hasTouch, setHasTouch] = useState(false);\n\n useEffect(() => {\n if (isBrowser()) {\n setHasTouch(\n 'ontouchstart' in window ||\n navigator.maxTouchPoints > 0 ||\n // @ts-ignore - for older browsers\n navigator.msMaxTouchPoints > 0\n );\n }\n }, []);\n\n return hasTouch;\n};\n"],"mappings":"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"}