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
}