circuit-bricks
Version:
A modular, Lego-style SVG circuit component system for React (ALPHA - Not for production use)
255 lines (253 loc) • 5.88 kB
JavaScript
"use client";
import { isBrowser } from "./ssrUtils-Ca211nnK.mjs";
import { useEffect, useState } from "react";
//#region src/utils/responsiveUtils.ts
/**
* Breakpoint definitions
*/
const breakpoints = {
xs: 0,
sm: 576,
md: 768,
lg: 992,
xl: 1200,
xxl: 1400
};
/**
* Get current breakpoint based on width
*/
const getBreakpoint = (width) => {
if (width >= breakpoints.xxl) return "xxl";
if (width >= breakpoints.xl) return "xl";
if (width >= breakpoints.lg) return "lg";
if (width >= breakpoints.md) return "md";
if (width >= breakpoints.sm) return "sm";
return "xs";
};
/**
* Get device type based on width and user agent
*/
const getDeviceType = (width, userAgent = "") => {
const isMobileUA = /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
const isTabletUA = /iPad|Android(?!.*Mobile)/i.test(userAgent);
if (isMobileUA || width < breakpoints.md) return "mobile";
if (isTabletUA || width >= breakpoints.md && width < breakpoints.lg) return "tablet";
return "desktop";
};
/**
* Hook for responsive screen information
*/
const useScreenInfo = () => {
const [screenInfo, setScreenInfo] = useState({
width: 1024,
height: 768,
breakpoint: "lg",
deviceType: "desktop",
isPortrait: false,
isLandscape: true,
pixelRatio: 1
});
useEffect(() => {
if (!isBrowser()) return;
const updateScreenInfo = () => {
const width = window.innerWidth;
const height = window.innerHeight;
const breakpoint = getBreakpoint(width);
const deviceType = getDeviceType(width, navigator.userAgent);
const isPortrait = height > width;
const isLandscape = !isPortrait;
const pixelRatio = window.devicePixelRatio || 1;
setScreenInfo({
width,
height,
breakpoint,
deviceType,
isPortrait,
isLandscape,
pixelRatio
});
};
updateScreenInfo();
window.addEventListener("resize", updateScreenInfo);
window.addEventListener("orientationchange", updateScreenInfo);
return () => {
window.removeEventListener("resize", updateScreenInfo);
window.removeEventListener("orientationchange", updateScreenInfo);
};
}, []);
return screenInfo;
};
/**
* Hook for breakpoint-specific values
*/
const useBreakpointValue = (values, fallback) => {
const { breakpoint } = useScreenInfo();
const breakpointOrder = [
"xs",
"sm",
"md",
"lg",
"xl",
"xxl"
];
const currentIndex = breakpointOrder.indexOf(breakpoint);
if (values[breakpoint] !== void 0) return values[breakpoint];
for (let i = currentIndex - 1; i >= 0; i--) {
const bp = breakpointOrder[i];
if (values[bp] !== void 0) return values[bp];
}
for (let i = currentIndex + 1; i < breakpointOrder.length; i++) {
const bp = breakpointOrder[i];
if (values[bp] !== void 0) return values[bp];
}
return fallback;
};
/**
* Get responsive grid configuration based on device type
*/
const useResponsiveGridConfig = () => {
const { deviceType } = useScreenInfo();
return useBreakpointValue({
xs: {
gridSize: 15,
snapThreshold: 12,
minZoom: .25,
maxZoom: 3,
zoomStep: .15,
panSensitivity: 1.2
},
sm: {
gridSize: 18,
snapThreshold: 15,
minZoom: .3,
maxZoom: 4,
zoomStep: .2,
panSensitivity: 1.1
},
md: {
gridSize: 20,
snapThreshold: 18,
minZoom: .4,
maxZoom: 5,
zoomStep: .25,
panSensitivity: 1
},
lg: {
gridSize: 25,
snapThreshold: 20,
minZoom: .5,
maxZoom: 8,
zoomStep: .3,
panSensitivity: .9
},
xl: {
gridSize: 30,
snapThreshold: 25,
minZoom: .1,
maxZoom: 10,
zoomStep: .5,
panSensitivity: .8
}
}, {
gridSize: 20,
snapThreshold: 18,
minZoom: .1,
maxZoom: 10,
zoomStep: .25,
panSensitivity: 1
});
};
/**
* Get responsive component configuration
*/
const useResponsiveComponentConfig = () => {
return useBreakpointValue({
xs: {
minComponentSize: 30,
maxComponentSize: 80,
portSize: 6,
wireStrokeWidth: 2,
fontSize: 10,
iconSize: 16
},
sm: {
minComponentSize: 35,
maxComponentSize: 90,
portSize: 7,
wireStrokeWidth: 2.5,
fontSize: 11,
iconSize: 18
},
md: {
minComponentSize: 40,
maxComponentSize: 100,
portSize: 8,
wireStrokeWidth: 3,
fontSize: 12,
iconSize: 20
},
lg: {
minComponentSize: 50,
maxComponentSize: 120,
portSize: 10,
wireStrokeWidth: 3,
fontSize: 14,
iconSize: 24
},
xl: {
minComponentSize: 60,
maxComponentSize: 150,
portSize: 12,
wireStrokeWidth: 4,
fontSize: 16,
iconSize: 28
}
}, {
minComponentSize: 40,
maxComponentSize: 100,
portSize: 8,
wireStrokeWidth: 3,
fontSize: 12,
iconSize: 20
});
};
/**
* Check if current screen matches a breakpoint
*/
const useMatchesBreakpoint = (targetBreakpoint) => {
const { breakpoint } = useScreenInfo();
const breakpointOrder = [
"xs",
"sm",
"md",
"lg",
"xl",
"xxl"
];
const currentIndex = breakpointOrder.indexOf(breakpoint);
const targetIndex = breakpointOrder.indexOf(targetBreakpoint);
return currentIndex >= targetIndex;
};
/**
* Get optimal canvas dimensions for current screen
*/
const useOptimalCanvasDimensions = (containerWidth, containerHeight) => {
const { width: screenWidth, height: screenHeight, deviceType } = useScreenInfo();
const width = containerWidth || screenWidth;
const height = containerHeight || screenHeight;
if (deviceType === "mobile") return {
width: Math.min(width, screenWidth * .95),
height: Math.min(height, screenHeight * .8)
};
if (deviceType === "tablet") return {
width: Math.min(width, screenWidth * .98),
height: Math.min(height, screenHeight * .9)
};
return {
width,
height
};
};
//#endregion
export { breakpoints, getBreakpoint, getDeviceType, useBreakpointValue, useMatchesBreakpoint, useOptimalCanvasDimensions, useResponsiveComponentConfig, useResponsiveGridConfig, useScreenInfo };
//# sourceMappingURL=responsiveUtils-DZdyCtQl.mjs.map