arredemo
Version:
Instantly build a static site for your package
118 lines (95 loc) • 2.68 kB
JavaScript
import useScroll from "app/layout/hooks/useScroll.mjs"
import { useCallback, useEffect, useState } from "react"
const MENU_OFFSET = 64
const _getMenuItemYCoordinate = (item) => {
let node
try {
node = document.querySelector(`#${item.id}`)
} catch (_) {}
if (!node) {
return 0
}
//const rect= item.node.getBoundingClientRect()
//const top= item.node.offsetTop
const rect = node.getBoundingClientRect()
const top = node.offsetTop
const height = rect.height
const middle = top + height / 2 // half so it does not get inside view just when padding is shown
//const bottom= rect.bottom
// return {
// //top,
// middle,
// //bottom,
// //height
// }
return middle
}
const _getMenuCoordinates = (menu) => {
const coords = menu.map((e, idx) => {
const y = _getMenuItemYCoordinate(e)
return {
index: idx,
id: e.id, //e.node.id,
y
}
})
return coords
}
const _findActiveOption = (menu) => {
let aOption
if (menu.length > 0) {
const screenTop = window.pageYOffset
const screenHeight =
(window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) -
MENU_OFFSET
const screenBottom = screenTop + screenHeight
// console.log(`scr ${screenTop} -> ${screenBottom} (${screenHeight}) `)
const coords = _getMenuCoordinates(menu)
// console.log(coords.map(c => `${c.id}-${c.top}`).join('\n'))
/*
const inside= coords.filter((e) => {
return (e.bottom>=screenTop && e.top<=screenBottom)
})
*/
const inside = coords.filter((e) => {
return e.y >= screenTop && e.y <= screenBottom
})
//console.log(inside)
if (inside.length > 0) {
const opt = inside.slice(0, 1)[0]
aOption = opt.index
} else {
const previous = coords.filter((e) => {
return e.y < screenTop
})
if (previous.length > 0) {
const opt = previous.slice(-1)[0]
aOption = opt.index
}
}
}
if (aOption === undefined) {
if (menu.length > 0) {
if (window.pageYOffset < MENU_OFFSET) {
aOption = 0
} else {
aOption = menu.length - 1
}
}
}
// console.log('Page: _findActiveOption ' + aOption)
return aOption
}
const useActiveOption = (menu) => {
const [activeOption, setActiveOption] = useState(0)
const updateActiveOption = useCallback(() => {
const nActiveOption = _findActiveOption(menu)
setActiveOption(nActiveOption)
}, [menu])
useEffect(() => {
updateActiveOption()
}, [updateActiveOption])
useScroll(updateActiveOption)
return activeOption
}
export default useActiveOption