circuit-bricks
Version:
A modular, Lego-style SVG circuit component system for React (ALPHA - Not for production use)
1 lines • 11.7 kB
Source Map (JSON)
{"version":3,"file":"responsiveUtils-CCZQdbIB.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":";;;;;;;AAaA,MAAa,cAAc;CACzB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,KAAK;AACN;;;;AAyBD,MAAa,gBAAgB,CAACA,UAA8B;AAC1D,KAAI,SAAS,YAAY,IAAK,QAAO;AACrC,KAAI,SAAS,YAAY,GAAI,QAAO;AACpC,KAAI,SAAS,YAAY,GAAI,QAAO;AACpC,KAAI,SAAS,YAAY,GAAI,QAAO;AACpC,KAAI,SAAS,YAAY,GAAI,QAAO;AACpC,QAAO;AACR;;;;AAKD,MAAa,gBAAgB,CAACA,OAAeC,YAAoB,OAAmB;CAElF,MAAM,aAAa,4DAA4D,KAAK,UAAU;CAC9F,MAAM,aAAa,4BAA4B,KAAK,UAAU;AAE9D,KAAI,cAAc,QAAQ,YAAY,GAAI,QAAO;AACjD,KAAI,cAAe,SAAS,YAAY,MAAM,QAAQ,YAAY,GAAK,QAAO;AAC9E,QAAO;AACR;;;;AAKD,MAAa,gBAAgB,MAAkB;CAC7C,MAAM,CAAC,YAAY,cAAc,GAAG,SAAqB;EACvD,OAAO;EACP,QAAQ;EACR,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,aAAa;EACb,YAAY;CACb,EAAC;AAEF,WAAU,MAAM;AACd,OAAK,WAAW,CAAE;EAElB,MAAM,mBAAmB,MAAM;GAC7B,MAAM,QAAQ,OAAO;GACrB,MAAM,SAAS,OAAO;GACtB,MAAM,aAAa,cAAc,MAAM;GACvC,MAAM,aAAa,cAAc,OAAO,UAAU,UAAU;GAC5D,MAAM,aAAa,SAAS;GAC5B,MAAM,eAAe;GACrB,MAAM,aAAa,OAAO,oBAAoB;AAE9C,iBAAc;IACZ;IACA;IACA;IACA;IACA;IACA;IACA;GACD,EAAC;EACH;AAED,oBAAkB;AAElB,SAAO,iBAAiB,UAAU,iBAAiB;AACnD,SAAO,iBAAiB,qBAAqB,iBAAiB;AAE9D,SAAO,MAAM;AACX,UAAO,oBAAoB,UAAU,iBAAiB;AACtD,UAAO,oBAAoB,qBAAqB,iBAAiB;EAClE;CACF,GAAE,CAAE,EAAC;AAEN,QAAO;AACR;;;;AAKD,MAAa,qBAAqB,CAAIC,QAAwCC,aAAmB;CAC/F,MAAM,EAAE,YAAY,GAAG,eAAe;CAGtC,MAAMC,kBAAgC;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;CAAM;CAC3E,MAAM,eAAe,gBAAgB,QAAQ,WAAW;AAGxD,KAAI,OAAO,uBACT,QAAO,OAAO;AAIhB,MAAK,IAAI,IAAI,eAAe,GAAG,KAAK,GAAG,KAAK;EAC1C,MAAM,KAAK,gBAAgB;AAC3B,MAAI,OAAO,eACT,QAAO,OAAO;CAEjB;AAGD,MAAK,IAAI,IAAI,eAAe,GAAG,IAAI,gBAAgB,QAAQ,KAAK;EAC9D,MAAM,KAAK,gBAAgB;AAC3B,MAAI,OAAO,eACT,QAAO,OAAO;CAEjB;AAED,QAAO;AACR;;;;AAiBD,MAAa,0BAA0B,MAA4B;CACjE,MAAM,EAAE,YAAY,GAAG,eAAe;AAEtC,QAAO,mBAAyC;EAC9C,IAAI;GACF,UAAU;GACV,eAAe;GACf,SAAS;GACT,SAAS;GACT,UAAU;GACV,gBAAgB;EACjB;EACD,IAAI;GACF,UAAU;GACV,eAAe;GACf,SAAS;GACT,SAAS;GACT,UAAU;GACV,gBAAgB;EACjB;EACD,IAAI;GACF,UAAU;GACV,eAAe;GACf,SAAS;GACT,SAAS;GACT,UAAU;GACV,gBAAgB;EACjB;EACD,IAAI;GACF,UAAU;GACV,eAAe;GACf,SAAS;GACT,SAAS;GACT,UAAU;GACV,gBAAgB;EACjB;EACD,IAAI;GACF,UAAU;GACV,eAAe;GACf,SAAS;GACT,SAAS;GACT,UAAU;GACV,gBAAgB;EACjB;CACF,GAAE;EACD,UAAU;EACV,eAAe;EACf,SAAS;EACT,SAAS;EACT,UAAU;EACV,gBAAgB;CACjB,EAAC;AACH;;;;AAiBD,MAAa,+BAA+B,MAAiC;AAC3E,QAAO,mBAA8C;EACnD,IAAI;GACF,kBAAkB;GAClB,kBAAkB;GAClB,UAAU;GACV,iBAAiB;GACjB,UAAU;GACV,UAAU;EACX;EACD,IAAI;GACF,kBAAkB;GAClB,kBAAkB;GAClB,UAAU;GACV,iBAAiB;GACjB,UAAU;GACV,UAAU;EACX;EACD,IAAI;GACF,kBAAkB;GAClB,kBAAkB;GAClB,UAAU;GACV,iBAAiB;GACjB,UAAU;GACV,UAAU;EACX;EACD,IAAI;GACF,kBAAkB;GAClB,kBAAkB;GAClB,UAAU;GACV,iBAAiB;GACjB,UAAU;GACV,UAAU;EACX;EACD,IAAI;GACF,kBAAkB;GAClB,kBAAkB;GAClB,UAAU;GACV,iBAAiB;GACjB,UAAU;GACV,UAAU;EACX;CACF,GAAE;EACD,kBAAkB;EAClB,kBAAkB;EAClB,UAAU;EACV,iBAAiB;EACjB,UAAU;EACV,UAAU;CACX,EAAC;AACH;;;;AAKD,MAAa,uBAAuB,CAACC,qBAA0C;CAC7E,MAAM,EAAE,YAAY,GAAG,eAAe;CACtC,MAAMD,kBAAgC;EAAC;EAAM;EAAM;EAAM;EAAM;EAAM;CAAM;CAC3E,MAAM,eAAe,gBAAgB,QAAQ,WAAW;CACxD,MAAM,cAAc,gBAAgB,QAAQ,iBAAiB;AAE7D,QAAO,gBAAgB;AACxB;;;;AAKD,MAAa,6BAA6B,CACxCE,gBACAC,oBACsC;CACtC,MAAM,EAAE,OAAO,aAAa,QAAQ,cAAc,YAAY,GAAG,eAAe;CAEhF,MAAM,QAAQ,kBAAkB;CAChC,MAAM,SAAS,mBAAmB;AAGlC,KAAI,eAAe,SACjB,QAAO;EACL,OAAO,KAAK,IAAI,OAAO,cAAc,IAAK;EAC1C,QAAQ,KAAK,IAAI,QAAQ,eAAe,GAAI;CAC7C;AAGH,KAAI,eAAe,SACjB,QAAO;EACL,OAAO,KAAK,IAAI,OAAO,cAAc,IAAK;EAC1C,QAAQ,KAAK,IAAI,QAAQ,eAAe,GAAI;CAC7C;AAGH,QAAO;EAAE;EAAO;CAAQ;AACzB"}