kopia lustrzana https://github.com/Tldraw/Tldraw
88 wiersze
2.5 KiB
TypeScript
88 wiersze
2.5 KiB
TypeScript
import throttle from 'lodash.throttle'
|
|
import { useLayoutEffect } from 'react'
|
|
import { Box } from '../primitives/Box'
|
|
import { useEditor } from './useEditor'
|
|
|
|
export function useScreenBounds(ref: React.RefObject<HTMLElement>) {
|
|
const editor = useEditor()
|
|
|
|
useLayoutEffect(() => {
|
|
function updateScreenBounds() {
|
|
const container = ref.current
|
|
if (!container) return null
|
|
|
|
const rect = container.getBoundingClientRect()
|
|
|
|
editor.updateViewportScreenBounds(
|
|
new Box(
|
|
rect.left || rect.x,
|
|
rect.top || rect.y,
|
|
Math.max(rect.width, 1),
|
|
Math.max(rect.height, 1)
|
|
)
|
|
)
|
|
}
|
|
|
|
// Set the initial bounds
|
|
updateScreenBounds()
|
|
|
|
// Everything else uses a debounced update...
|
|
const updateBounds = throttle(updateScreenBounds, 200, {
|
|
trailing: true,
|
|
})
|
|
|
|
// Rather than running getClientRects on every frame, we'll
|
|
// run it once a second or when the window resizes.
|
|
const interval = setInterval(updateBounds, 1000)
|
|
window.addEventListener('resize', updateBounds)
|
|
|
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
if (!entries[0].contentRect) return
|
|
updateBounds()
|
|
})
|
|
|
|
const container = ref.current
|
|
let scrollingParent: HTMLElement | Document | null = null
|
|
|
|
if (container) {
|
|
// When the container's size changes, update the bounds
|
|
resizeObserver.observe(container)
|
|
|
|
// When the container's nearest scrollable parent scrolls, update the bounds
|
|
scrollingParent = getNearestScrollableContainer(container)
|
|
scrollingParent.addEventListener('scroll', updateBounds)
|
|
}
|
|
|
|
return () => {
|
|
clearInterval(interval)
|
|
window.removeEventListener('resize', updateBounds)
|
|
resizeObserver.disconnect()
|
|
scrollingParent?.removeEventListener('scroll', updateBounds)
|
|
}
|
|
}, [editor, ref])
|
|
}
|
|
|
|
/*!
|
|
* Author: excalidraw
|
|
* MIT License: https://github.com/excalidraw/excalidraw/blob/master/LICENSE
|
|
* https://github.com/excalidraw/excalidraw/blob/48c3465b19f10ec755b3eb84e21a01a468e96e43/packages/excalidraw/utils.ts#L600
|
|
*/
|
|
const getNearestScrollableContainer = (element: HTMLElement): HTMLElement | Document => {
|
|
let parent = element.parentElement
|
|
while (parent) {
|
|
if (parent === document.body) {
|
|
return document
|
|
}
|
|
const { overflowY } = window.getComputedStyle(parent)
|
|
const hasScrollableContent = parent.scrollHeight > parent.clientHeight
|
|
if (
|
|
hasScrollableContent &&
|
|
(overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay')
|
|
) {
|
|
return parent
|
|
}
|
|
parent = parent.parentElement
|
|
}
|
|
return document
|
|
}
|