Source

tools/hooks/useWidthCheck.ts

import React, {useContext} from "react"
import {ResponsiveLayoutContext} from "../../components";

/**
 * @typedef
 */
type WidthCheckReturn = {
    /**
     * Whether the screen width is below {@link NARROW_UPPER_BOUND} (exclusive)
     */
    wide: boolean
    /**
     * Whether the screen width is above {@link NARROW_UPPER_BOUND} (inclusive) and below {@link MEDIUM_UPPER_BOUND} (exclusive)
     */
    medium: boolean
    /**
     * Whether the screen width is above {@link MEDIUM_UPPER_BOUND} (inclusive)
     */
    narrow: boolean
}

/**
 * Width (in pixels) that represents the upper boundary (exclusive) of the `narrow` value.
 * Since this is an _exclusive_ boundary, this is the first width that is NOT considered narrow.
 *
 * Until doc auto renders, value is set to `575`
 *
 * @constant
 * @type {number}
 * @default
 */
export const NARROW_UPPER_BOUND = 575
/**
 * Width (in pixels) that represents the upper boundary (exclusive) of the `medium` value
 * Since this is an _exclusive_ boundary, this is the first width that is NOT considered medium.
 *
 * Until doc auto renders, value is set to `1000`
 *
 * @constant
 * @type {number}
 * @default
 */
export const MEDIUM_UPPER_BOUND = 1000

/**
 * Custom hook for classifying the current width of the app's
 * viewport into `narrow`, `medium`, and `wide` categories.
 *
 * The hook doesn't take any parameters and returns a boolean
 * for each category.
 *
 * - `narrow`: will be `true` if the screen width is below {@link NARROW_UPPER_BOUND} (exclusive)
 * - `medium`: will be `true` if the screen width is above {@link NARROW_UPPER_BOUND} (inclusive) and below {@link MEDIUM_UPPER_BOUND} (exclusive)
 * - `wide`: will be `true` if the screen width is above {@link MEDIUM_UPPER_BOUND} (inclusive)
 *
 * Note that using this hook will re-render your component when
 * the viewport width changes; that means your layout can adapt
 * as the user resizes their browser or rotates their phone.
 *
 * ### Hook Usage
 *
 * #### Checking the current width
 * ```
 * const {narrow, medium, wide} = useWidthCheck()
 *
 * ...
 *
 * if (narrow) { return 'Your browser window is narrow like a phone' }
 * else if (medium) { return 'Your browser window is medium like a tablet (or you resized it)' }
 * else if (wide) { return 'Your browser window is on a nice wide screen' }
 * ```
 *
 * It's quick and easy to determine what the current screen
 * width is and display accordingly.
 *
 * Because they are all booleans, you can also use logic
 * operations like:
 * ```
 * const {narrow, medium} = useWidthCheck()
 *
 * if (narrow || medium) { return 'not wide' }
 * ```
 *
 * ```
 * const {narrow} = useWidthCheck()
 *
 * if (!narrow) { return 'probably not a phone' }
 * ```
 *
 * @category Hooks
 * @return {WidthCheckReturn}
 */
export function useWidthCheck() : WidthCheckReturn {
    // Load responsive layout context and read current screen width
    const responsiveLayout = useContext(ResponsiveLayoutContext)
    const width = responsiveLayout.width

    let narrow = false
    let medium = false
    let wide = false

    // Check the width vs defined breakpoints
    if (width < NARROW_UPPER_BOUND) {
        narrow = true
    } else if (width < MEDIUM_UPPER_BOUND && width >= NARROW_UPPER_BOUND) {
        medium = true
    } else if (width >= MEDIUM_UPPER_BOUND) {
        wide = true
    }


    return {wide, medium, narrow}
}