import { Box3, Vector3, Sphere, Group, Object3D } from 'three'
import * as React from 'react'
import { useThree } from '@react-three/fiber'
import { ForwardRefComponent } from '../helpers/ts-utils'
export type OnCenterCallbackProps = {
/** The next parent above
*/
parent: Object3D
/** The outmost container group of the component */
container: Object3D
width: number
height: number
depth: number
boundingBox: Box3
boundingSphere: Sphere
center: Vector3
verticalAlignment: number
horizontalAlignment: number
depthAlignment: number
}
export type CenterProps = {
top?: boolean
right?: boolean
bottom?: boolean
left?: boolean
front?: boolean
back?: boolean
/** Disable all axes */
disable?: boolean
/** Disable x-axis centering */
disableX?: boolean
/** Disable y-axis centering */
disableY?: boolean
/** Disable z-axis centering */
disableZ?: boolean
/** See https://threejs.org/docs/index.html?q=box3#api/en/math/Box3.setFromObject */
precise?: boolean
/** Callback, fires in the useLayoutEffect phase, after measurement */
onCentered?: (props: OnCenterCallbackProps) => void
/** Optional cacheKey to keep the component from recalculating on every render */
cacheKey?: any
}
export const Center: ForwardRefComponent =
/* @__PURE__ */ React.forwardRef(function Center(
{
children,
disable,
disableX,
disableY,
disableZ,
left,
right,
top,
bottom,
front,
back,
onCentered,
precise = true,
cacheKey = 0,
...props
},
fRef
) {
const ref = React.useRef(null!)
const outer = React.useRef(null!)
const inner = React.useRef(null!)
React.useLayoutEffect(() => {
outer.current.matrixWorld.identity()
const box3 = new Box3().setFromObject(inner.current, precise)
const center = new Vector3()
const sphere = new Sphere()
const width = box3.max.x - box3.min.x
const height = box3.max.y - box3.min.y
const depth = box3.max.z - box3.min.z
box3.getCenter(center)
box3.getBoundingSphere(sphere)
const vAlign = top ? height / 2 : bottom ? -height / 2 : 0
const hAlign = left ? -width / 2 : right ? width / 2 : 0
const dAlign = front ? depth / 2 : back ? -depth / 2 : 0
outer.current.position.set(
disable || disableX ? 0 : -center.x + hAlign,
disable || disableY ? 0 : -center.y + vAlign,
disable || disableZ ? 0 : -center.z + dAlign
)
// Only fire onCentered if the bounding box has changed
if (typeof onCentered !== 'undefined') {
onCentered({
parent: ref.current.parent!,
container: ref.current,
width,
height,
depth,
boundingBox: box3,
boundingSphere: sphere,
center: center,
verticalAlignment: vAlign,
horizontalAlignment: hAlign,
depthAlignment: dAlign,
})
}
}, [cacheKey, onCentered, top, left, front, disable, disableX, disableY, disableZ, precise, right, bottom, back])
React.useImperativeHandle(fRef, () => ref.current, [])
return (
{children}
)
})