/** * useBreakpoint Hook * 断点检测 - 检测当前断点 */ import { useMemo, useState, useEffect } from 'react'; import { Dimensions, ScaledSize } from 'react-native'; import { BREAKPOINTS, FINE_BREAKPOINTS } from './types'; import type { BreakpointKey, FineBreakpointKey } from './types'; // ==================== 工具函数 ==================== /** * 获取当前断点 */ export function getBreakpoint(width: number): BreakpointKey { if (width >= BREAKPOINTS.wide) { return 'wide'; } if (width >= BREAKPOINTS.desktop) { return 'desktop'; } if (width >= BREAKPOINTS.tablet) { return 'tablet'; } return 'mobile'; } /** * 获取细粒度断点 */ export function getFineBreakpoint(width: number): FineBreakpointKey { if (width >= FINE_BREAKPOINTS['4xl']) return '4xl'; if (width >= FINE_BREAKPOINTS['3xl']) return '3xl'; if (width >= FINE_BREAKPOINTS['2xl']) return '2xl'; if (width >= FINE_BREAKPOINTS.xl) return 'xl'; if (width >= FINE_BREAKPOINTS.lg) return 'lg'; if (width >= FINE_BREAKPOINTS.md) return 'md'; if (width >= FINE_BREAKPOINTS.sm) return 'sm'; return 'xs'; } /** * 断点比较 - 检查当前断点是否大于等于目标断点 */ export function isBreakpointGTE( current: FineBreakpointKey, target: FineBreakpointKey ): boolean { const order: FineBreakpointKey[] = ['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl']; return order.indexOf(current) >= order.indexOf(target); } /** * 断点比较 - 检查当前断点是否小于目标断点 */ export function isBreakpointLT( current: FineBreakpointKey, target: FineBreakpointKey ): boolean { return !isBreakpointGTE(current, target); } /** * 检查当前是否在指定断点范围内 */ export function isBreakpointBetween( current: FineBreakpointKey, min: FineBreakpointKey, max: FineBreakpointKey ): boolean { return isBreakpointGTE(current, min) && isBreakpointLT(current, max); } // ==================== Hooks ==================== function useWindowDimensionsLocal(): ScaledSize { const [dimensions, setDimensions] = useState(() => Dimensions.get('window')); useEffect(() => { const subscription = Dimensions.addEventListener('change', ({ window }) => { setDimensions(window); }); return () => { subscription.remove(); }; }, []); return dimensions; } /** * 断点检测 Hook * 返回当前的基础断点 * * @returns 当前断点 * * @example * const breakpoint = useBreakpoint(); * // 'mobile' | 'tablet' | 'desktop' | 'wide' */ export function useBreakpoint(): BreakpointKey { const { width } = useWindowDimensionsLocal(); return useMemo(() => { return getBreakpoint(width); }, [width]); } /** * 细粒度断点检测 Hook * 返回当前的细粒度断点 * * @returns 当前细粒度断点 * * @example * const fineBreakpoint = useFineBreakpoint(); * // 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' */ export function useFineBreakpoint(): FineBreakpointKey { const { width } = useWindowDimensionsLocal(); return useMemo(() => { return getFineBreakpoint(width); }, [width]); } /** * 检查当前断点是否大于等于目标断点 * * @param target - 目标断点 * @returns 是否满足条件 * * @example * const isMediumUp = useBreakpointGTE('md'); */ export function useBreakpointGTE(target: FineBreakpointKey): boolean { const { width } = useWindowDimensionsLocal(); return useMemo(() => { const current = getFineBreakpoint(width); return isBreakpointGTE(current, target); }, [width, target]); } /** * 检查当前断点是否小于目标断点 * * @param target - 目标断点 * @returns 是否满足条件 * * @example * const isMobileOnly = useBreakpointLT('lg'); */ export function useBreakpointLT(target: FineBreakpointKey): boolean { const { width } = useWindowDimensionsLocal(); return useMemo(() => { const current = getFineBreakpoint(width); return isBreakpointLT(current, target); }, [width, target]); } /** * 检查当前是否在指定断点范围内 * * @param min - 最小断点(包含) * @param max - 最大断点(不包含) * @returns 是否在范围内 * * @example * const isTabletRange = useBreakpointBetween('md', 'lg'); */ export function useBreakpointBetween( min: FineBreakpointKey, max: FineBreakpointKey ): boolean { const { width } = useWindowDimensionsLocal(); return useMemo(() => { const current = getFineBreakpoint(width); return isBreakpointBetween(current, min, max); }, [width, min, max]); } export default { useBreakpoint, useFineBreakpoint, useBreakpointGTE, useBreakpointLT, useBreakpointBetween, };