main

mattermost/focalboard

Last updated at: 28/12/2023 01:37

hooks.ts

TLDR

This file, located at webapp/src/components/tutorial_tour_tip/hooks.ts, contains a single function called useMeasurePunchouts which calculates the coordinates and dimensions of a series of elements on a webpage.

Methods

useMeasurePunchouts

This method takes in an array of element IDs, an array of additional dependencies, and an optional offset object. It then calculates and returns the coordinates and dimensions of the elements specified by the given IDs. The resulting values are used to create a TutorialTourTipPunchout object that represents an area on the webpage that should be excluded from the tutorial or tour tips.

END

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {useLayoutEffect, useMemo, useState} from 'react'
import throttle from 'lodash/throttle'

import useElementAvailable from './useElementAvailable'

import {TutorialTourTipPunchout} from './tutorial_tour_tip_backdrop'

type PunchoutOffset = {
    x: number
    y: number
    width: number
    height: number
}

export function useMeasurePunchouts(elementIds: string[], additionalDeps: any[], offset?: PunchoutOffset): TutorialTourTipPunchout | null | undefined {
    const elementsAvailable = useElementAvailable(elementIds)
    const [size, setSize] = useState<DOMRect>()
    const updateSize = throttle(() => {
        setSize(document.getElementById('root')?.getBoundingClientRect())
    }, 100)

    useLayoutEffect(() => {
        window.addEventListener('resize', updateSize)
        return () =>
            window.removeEventListener('resize', updateSize)
    }, [])

    const channelPunchout = useMemo(() => {
        let minX = Number.MAX_SAFE_INTEGER
        let minY = Number.MAX_SAFE_INTEGER
        let maxX = Number.MIN_SAFE_INTEGER
        let maxY = Number.MIN_SAFE_INTEGER
        for (let i = 0; i < elementIds.length; i++) {
            const rectangle = document.querySelector(elementIds[i])?.getBoundingClientRect()
            if (!rectangle) {
                return null
            }
            if (rectangle.x < minX) {
                minX = rectangle.x
            }
            if (rectangle.y < minY) {
                minY = rectangle.y
            }
            if (rectangle.x + rectangle.width > maxX) {
                maxX = rectangle.x + rectangle.width
            }
            if (rectangle.y + rectangle.height > maxY) {
                maxY = rectangle.y + rectangle.height
            }
        }

        return {
            x: `${minX + (offset ? offset.x : 0)}px`,
            y: `${minY + (offset ? offset.y : 0)}px`,
            width: `${(maxX - minX) + (offset ? offset.width : 0)}px`,
            height: `${(maxY - minY) + (offset ? offset.height : 0)}px`,
        }
    }, [...elementIds, ...additionalDeps, size, elementsAvailable])
    return channelPunchout
}