58 lines
1.8 KiB
TypeScript
58 lines
1.8 KiB
TypeScript
import { useCallback } from 'react'
|
|
import { useDominoStore, useDominoStoreInstance } from './domino-hooks'
|
|
import type { Padding, ScrollIntoViewOptions } from './domino'
|
|
import { useDominoContainer } from './use-domino-container'
|
|
import { calculateScrollIntoViewTransform } from './math'
|
|
|
|
/**
|
|
* Hook to scroll an element into view within the Domino canvas.
|
|
* (Internal hook, prefer using useDominoInstance)
|
|
*/
|
|
export function useDominoScrollIntoView(
|
|
explicitContainerRef?: React.RefObject<HTMLElement | null>,
|
|
) {
|
|
const store = useDominoStoreInstance()
|
|
const setViewport = useDominoStore(state => state.setViewport)
|
|
const containerRef = useDominoContainer(explicitContainerRef)
|
|
|
|
const scrollIntoView = useCallback(
|
|
(elementId: string, options?: ScrollIntoViewOptions) => {
|
|
const container = containerRef?.current
|
|
if (!container) return false
|
|
|
|
const { elements, viewport, padding: globalPadding } = store.getState()
|
|
const element = elements[elementId]
|
|
if (!element) return false
|
|
|
|
const finalPadding = {
|
|
top: options?.padding?.top ?? globalPadding.top ?? 0,
|
|
right: options?.padding?.right ?? globalPadding.right ?? 0,
|
|
bottom: options?.padding?.bottom ?? globalPadding.bottom ?? 0,
|
|
left: options?.padding?.left ?? globalPadding.left ?? 0,
|
|
} as Required<Padding>
|
|
|
|
const nextViewport = calculateScrollIntoViewTransform(
|
|
element,
|
|
viewport,
|
|
container.getBoundingClientRect(),
|
|
finalPadding,
|
|
{
|
|
force: options?.force,
|
|
block: options?.block,
|
|
inline: options?.inline,
|
|
targetScale: options?.scale,
|
|
},
|
|
)
|
|
|
|
if (nextViewport) {
|
|
setViewport(nextViewport)
|
|
return true
|
|
}
|
|
return false
|
|
},
|
|
[setViewport, containerRef, store],
|
|
)
|
|
|
|
return scrollIntoView
|
|
}
|