diff --git a/src/Box.tsx b/src/Box.tsx
index 51850e3..8ce17a7 100644
--- a/src/Box.tsx
+++ b/src/Box.tsx
@@ -2,82 +2,84 @@ import React, { useLayoutEffect, useRef, useMemo, useState } from 'react'
import * as THREE from 'three'
import Yoga from 'yoga-layout-prebuilt'
import { ReactThreeFiber, useFrame } from '@react-three/fiber'
+import mergeRefs from 'react-merge-refs'
import { setYogaProperties, rmUndefFromObj } from './util'
import { boxContext, flexContext, SharedBoxContext } from './context'
import { R3FlexProps } from './props'
import { useReflow, useContext } from './hooks'
-/**
- * Box container for 3D Objects.
- * For containing Boxes use ``.
- */
-export function Box({
- // Non-flex props
- children,
- centerAnchor,
-
- // flex props
- flexDirection,
- flexDir,
- dir,
-
- alignContent,
- alignItems,
- alignSelf,
- align,
-
- justifyContent,
- justify,
-
- flexBasis,
- basis,
- flexGrow,
- grow,
-
- flexShrink,
- shrink,
-
- flexWrap,
- wrap,
-
- margin,
- m,
- marginBottom,
- marginLeft,
- marginRight,
- marginTop,
- mb,
- ml,
- mr,
- mt,
-
- padding,
- p,
- paddingBottom,
- paddingLeft,
- paddingRight,
- paddingTop,
- pb,
- pl,
- pr,
- pt,
-
- height,
- width,
-
- maxHeight,
- maxWidth,
- minHeight,
- minWidth,
-
- // other
- ...props
-}: {
+export type BoxProps = {
centerAnchor?: boolean
children: React.ReactNode | ((width: number, height: number, centerAnchor?: boolean) => React.ReactNode)
} & R3FlexProps &
- Omit, 'children'>) {
+ Omit, 'children'>
+
+function BoxImpl(
+ {
+ // Non-flex props
+ children,
+ centerAnchor,
+
+ // flex props
+ flexDirection,
+ flexDir,
+ dir,
+
+ alignContent,
+ alignItems,
+ alignSelf,
+ align,
+
+ justifyContent,
+ justify,
+
+ flexBasis,
+ basis,
+ flexGrow,
+ grow,
+
+ flexShrink,
+ shrink,
+
+ flexWrap,
+ wrap,
+
+ margin,
+ m,
+ marginBottom,
+ marginLeft,
+ marginRight,
+ marginTop,
+ mb,
+ ml,
+ mr,
+ mt,
+
+ padding,
+ p,
+ paddingBottom,
+ paddingLeft,
+ paddingRight,
+ paddingTop,
+ pb,
+ pl,
+ pr,
+ pt,
+
+ height,
+ width,
+
+ maxHeight,
+ maxWidth,
+ minHeight,
+ minWidth,
+
+ // other
+ ...props
+ }: BoxProps,
+ ref: React.Ref
+) {
// must memoize or the object literal will cause every dependent of flexProps to rerender everytime
const flexProps: R3FlexProps = useMemo(() => {
const _flexProps = {
@@ -228,10 +230,18 @@ export function Box({
const sharedBoxContext = useMemo(() => ({ node, size, centerAnchor }), [node, size, centerAnchor])
return (
-
+
{typeof children === 'function' ? children(size[0], size[1], centerAnchor) : children}
)
}
+
+/**
+ * Box container for 3D Objects.
+ * For containing Boxes use ``.
+ */
+export const Box = React.forwardRef(BoxImpl)
+
+Box.displayName = 'Box'
diff --git a/src/Flex.tsx b/src/Flex.tsx
index b7626c8..44d30b4 100644
--- a/src/Flex.tsx
+++ b/src/Flex.tsx
@@ -1,7 +1,8 @@
import React, { useLayoutEffect, useMemo, useCallback, PropsWithChildren, useRef } from 'react'
import Yoga, { YogaNode } from 'yoga-layout-prebuilt'
-import { Vector3, Group, Box3, Object3D } from 'three'
+import * as THREE from 'three'
import { useFrame, useThree, ReactThreeFiber } from '@react-three/fiber'
+import mergeRefs from 'react-merge-refs'
import {
setYogaProperties,
@@ -33,86 +34,86 @@ export type FlexProps = PropsWithChildren<
centerAnchor?: boolean
}> &
R3FlexProps &
- Omit, 'children'>
+ Omit, 'children'>
>
interface BoxesItem {
node: YogaNode
- group: Group
+ group: THREE.Group
flexProps: R3FlexProps
centerAnchor: boolean
}
-/**
- * Flex container. Can contain Boxes
- */
-export function Flex({
- // Non flex props
- size = [1, 1, 1],
- yogaDirection = 'ltr',
- plane = 'xy',
- children,
- scaleFactor = 100,
- onReflow,
- disableSizeRecalc,
- centerAnchor: rootCenterAnchor,
-
- // flex props
-
- flexDirection,
- flexDir,
- dir,
-
- alignContent,
- alignItems,
- alignSelf,
- align,
-
- justifyContent,
- justify,
-
- flexBasis,
- basis,
- flexGrow,
- grow,
- flexShrink,
- shrink,
-
- flexWrap,
- wrap,
-
- margin,
- m,
- marginBottom,
- marginLeft,
- marginRight,
- marginTop,
- mb,
- ml,
- mr,
- mt,
-
- padding,
- p,
- paddingBottom,
- paddingLeft,
- paddingRight,
- paddingTop,
- pb,
- pl,
- pr,
- pt,
-
- height,
- width,
-
- maxHeight,
- maxWidth,
- minHeight,
- minWidth,
-
- // other
- ...props
-}: FlexProps) {
+function FlexImpl(
+ {
+ // Non flex props
+ size = [1, 1, 1],
+ yogaDirection = 'ltr',
+ plane = 'xy',
+ children,
+ scaleFactor = 100,
+ onReflow,
+ disableSizeRecalc,
+ centerAnchor: rootCenterAnchor,
+
+ // flex props
+
+ flexDirection,
+ flexDir,
+ dir,
+
+ alignContent,
+ alignItems,
+ alignSelf,
+ align,
+
+ justifyContent,
+ justify,
+
+ flexBasis,
+ basis,
+ flexGrow,
+ grow,
+ flexShrink,
+ shrink,
+
+ flexWrap,
+ wrap,
+
+ margin,
+ m,
+ marginBottom,
+ marginLeft,
+ marginRight,
+ marginTop,
+ mb,
+ ml,
+ mr,
+ mt,
+
+ padding,
+ p,
+ paddingBottom,
+ paddingLeft,
+ paddingRight,
+ paddingTop,
+ pb,
+ pl,
+ pr,
+ pt,
+
+ height,
+ width,
+
+ maxHeight,
+ maxWidth,
+ minHeight,
+ minWidth,
+
+ // other
+ ...props
+ }: FlexProps,
+ ref: React.Ref
+) {
// must memoize or the object literal will cause every dependent of flexProps to rerender everytime
const flexProps: R3FlexProps = useMemo(() => {
const _flexProps = {
@@ -217,12 +218,12 @@ export function Flex({
wrap,
])
- const rootGroup = useRef()
+ const rootGroup = useRef()
// Keeps track of the yoga nodes of the children and the related wrapper groups
const boxesRef = useRef([])
const registerBox = useCallback(
- (node: YogaNode, group: Group, flexProps: R3FlexProps, centerAnchor: boolean = false) => {
+ (node: YogaNode, group: THREE.Group, flexProps: R3FlexProps, centerAnchor: boolean = false) => {
const i = boxesRef.current.findIndex((b) => b.node === node)
if (i !== -1) {
boxesRef.current.splice(i, 1)
@@ -258,8 +259,8 @@ export function Flex({
}, [children, flexProps, requestReflow])
// Common variables for reflow
- const boundingBox = useMemo(() => new Box3(), [])
- const vec = useMemo(() => new Vector3(), [])
+ const boundingBox = useMemo(() => new THREE.Box3(), [])
+ const vec = useMemo(() => new THREE.Vector3(), [])
const mainAxis = plane[0] as Axis
const crossAxis = plane[1] as Axis
const depthAxis = getDepthAxis(plane)
@@ -356,10 +357,17 @@ export function Flex({
})
return (
-
+
{children}
)
}
+
+/**
+ * Flex container. Can contain Boxes
+ */
+export const Flex = React.forwardRef(FlexImpl)
+
+Flex.displayName = 'Flex'