Skip to content

Commit

Permalink
BREAKING: allow to pass an outer yoga provider
Browse files Browse the repository at this point in the history
This is mainly to allow usage of yoga-layout-wasm. From now on there's 2 entrpoints,
a default one with YogaPrebuiltProvider (which uses yoga-layout-prebuilt)
and outerRuntime that exports YogaProvider that allows to pass an arbitrary runtime
(that conforms with Yoga types)

This is a breaking change because library users will have to place a YogaProvider/YogaPrebuiltProvider in their code

Fixes pmndrs#66
  • Loading branch information
saitonakamura committed Sep 29, 2021
1 parent 4c7e23f commit 08c64fa
Show file tree
Hide file tree
Showing 25 changed files with 980 additions and 34 deletions.
7 changes: 5 additions & 2 deletions .storybook/Setup.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react'
import React, { Suspense } from 'react'
import * as THREE from 'three'
import { Canvas } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import { YogaPrebuiltProvider } from '../src'

export function Setup({
children,
Expand All @@ -19,7 +20,9 @@ export function Setup({
}) {
return (
<Canvas shadows camera={{ position: cameraPosition, fov: cameraFov }} dpr={window.devicePixelRatio} {...restProps}>
{children}
<Suspense fallback={null}>
<YogaPrebuiltProvider>{children}</YogaPrebuiltProvider>
</Suspense>
{lights && (
<>
<ambientLight intensity={0.8} />
Expand Down
9 changes: 5 additions & 4 deletions examples/config-overrides.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
const { override, addWebpackAlias, addWebpackPlugin } = require('customize-cra')
const { override, addWebpackAlias, addWebpackPlugin, } = require('customize-cra')
const { addReactRefresh } = require('customize-cra-react-refresh')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const path = require('path')

module.exports = override(
addReactRefresh(),
addWebpackAlias({
// addReactRefresh(),
// addWebpackAlias({
// three$: path.resolve('./src/utils/three.js'),
// '../../../build/three.module.js': path.resolve('./src/utils/three.js'),
}),
// '@react-three/flex': path.resolve('../'),
// })
//addWebpackPlugin(new BundleAnalyzerPlugin())
)
41 changes: 33 additions & 8 deletions examples/src/state.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
import BH41NVu from './images/BH41NVu.jpg'
import fBoIJLX from './images/fBoIJLX.jpg'
import _04zTfWB from './images/04zTfWB.jpg'
import c4cA8UN from './images/c4cA8UN.jpg'
import ajQ73ol from './images/ajQ73ol.jpg'
import gZOmLNU from './images/gZOmLNU.jpg'
import mbFIW1b from './images/mbFIW1b.jpg'
import mlDUVig from './images/mlDUVig.jpg'
import gwuZrgo from './images/gwuZrgo.jpg'
import cAKwexj from './images/cAKwexj.jpg'

const state = {
top: 0,
pages: 0,
Expand All @@ -7,30 +18,44 @@ const state = {
{
tag: '00',
text: `The Bacchic\nand Dionysiac\nRites`,
images: ['/images/BH41NVu.jpg', '/images/fBoIJLX.jpg', '/images/04zTfWB.jpg'],
images: [BH41NVu, fBoIJLX, _04zTfWB],
},
{ tag: '01', text: `The Elysian\nMysteries`, images: ['/images/c4cA8UN.jpg', '/images/ajQ73ol.jpg', '/images/gZOmLNU.jpg'] },
{ tag: '02', text: `The Hiramic\nLegend`, images: ['/images/mbFIW1b.jpg', '/images/mlDUVig.jpg', '/images/gwuZrgo.jpg'] },
{ tag: '01', text: `The Elysian\nMysteries`, images: [c4cA8UN, ajQ73ol, gZOmLNU] },
{ tag: '02', text: `The Hiramic\nLegend`, images: [mbFIW1b, mlDUVig, gwuZrgo] },
],
depthbox: [
{
depth: 0,
color: '#cccccc',
textColor: '#ffffff',
text: 'In a void,\nno one could say\nwhy a thing\nonce set in motion\nshould stop anywhere.',
image: '/images/cAKwexj.jpg',
image: cAKwexj,
},
{
depth: -5,
textColor: '#272727',
text: 'For why should it stop\nhere rather than here?\nSo that a thing\nwill either be at rest\nor must be moved\nad infinitum.',
image: '/images/04zTfWB.jpg',
image: _04zTfWB,
},
],
lines: [
{ points: [[-20, 0, 0], [-9, 0, 0]], color: "black", lineWidth: 0.5 },
{ points: [[20, 0, 0], [9, 0, 0]], color: "black", lineWidth: 0.5 },
]
{
points: [
[-20, 0, 0],
[-9, 0, 0],
],
color: 'black',
lineWidth: 0.5,
},
{
points: [
[20, 0, 0],
[9, 0, 0],
],
color: 'black',
lineWidth: 0.5,
},
],
}

export default state
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"import": "./dist/index.js"
},
"./package.json": "./package.json",
"./": "./"
"./": "./",
"./outerRuntime": "./dist/outerRuntime.js"
},
"files": [
"dist"
Expand All @@ -58,6 +59,7 @@
"build-storybook": "build-storybook"
},
"dependencies": {
"use-asset": "^1.0.4",
"yoga-layout-prebuilt": "^1.9.6"
},
"devDependencies": {
Expand Down
18 changes: 12 additions & 6 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,33 @@ const getBabelOptions = ({ useESModules }, targets) => ({

export default [
{
input: `./src/index.ts`,
input: `./src/index.tsx`,
output: { file: `dist/index.js`, format: 'esm' },
external,
plugins: [
json(),
babel(getBabelOptions({ useESModules: true }, '>1%, not dead, not ie 11, not op_mini all')),
resolve({ extensions }),
terser(),
filesize()
filesize(),
],
},
{
input: `./src/index.ts`,
output: { file: `dist/index.cjs`, format: 'cjs' },
input: `./src/outerRuntime.ts`,
output: { file: `dist/outerRuntime.js`, format: 'esm' },
external,
plugins: [
json(),
babel(getBabelOptions({ useESModules: false })),
babel(getBabelOptions({ useESModules: true }, '>1%, not dead, not ie 11, not op_mini all')),
resolve({ extensions }),
terser(),
filesize()
filesize(),
],
},
{
input: `./src/index.tsx`,
output: { file: `dist/index.cjs`, format: 'cjs' },
external,
plugins: [json(), babel(getBabelOptions({ useESModules: false })), resolve({ extensions }), terser(), filesize()],
},
]
8 changes: 5 additions & 3 deletions src/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
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'
import { useYoga } from './YogaProvider'

export type BoxProps = {
centerAnchor?: boolean
Expand Down Expand Up @@ -184,15 +184,17 @@ function BoxImpl(
wrap,
])

const Yoga = useYoga()

const { registerBox, unregisterBox, scaleFactor } = useContext(flexContext)
const { node: parent } = useContext(boxContext)
const group = useRef<THREE.Group>()
const node = useMemo(() => Yoga.Node.create(), [])
const reflow = useReflow()

useLayoutEffect(() => {
setYogaProperties(node, flexProps, scaleFactor)
}, [flexProps, node, scaleFactor])
setYogaProperties(Yoga, node, flexProps, scaleFactor)
}, [flexProps, node, scaleFactor, Yoga])

// Make child known to the parents yoga instance *before* it calculates layout
useLayoutEffect(() => {
Expand Down
10 changes: 7 additions & 3 deletions src/Flex.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useLayoutEffect, useMemo, useCallback, PropsWithChildren, useRef } from 'react'
import Yoga, { YogaNode } from 'yoga-layout-prebuilt'
// eslint-disable-next-line import/no-unresolved
import type { YogaNode } from 'yoga-layout'
import * as THREE from 'three'
import { useFrame, useThree, ReactThreeFiber } from '@react-three/fiber'
import mergeRefs from 'react-merge-refs'
Expand All @@ -16,6 +17,7 @@ import {
} from './util'
import { boxContext, flexContext, SharedFlexContext, SharedBoxContext } from './context'
import type { R3FlexProps, FlexYogaDirection, FlexPlane } from './props'
import { useYoga } from './YogaProvider'

export type FlexProps = PropsWithChildren<
Partial<{
Expand Down Expand Up @@ -218,6 +220,8 @@ function FlexImpl(
wrap,
])

const Yoga = useYoga()

const rootGroup = useRef<THREE.Group>()

// Keeps track of the yoga nodes of the children and the related wrapper groups
Expand All @@ -242,8 +246,8 @@ function FlexImpl(
// Reference to the yoga native node
const node = useMemo(() => Yoga.Node.create(), [])
useLayoutEffect(() => {
setYogaProperties(node, flexProps, scaleFactor)
}, [node, flexProps, scaleFactor])
setYogaProperties(Yoga, node, flexProps, scaleFactor)
}, [node, flexProps, scaleFactor, Yoga])

// Mechanism for invalidating and recalculating layout
const { invalidate } = useThree()
Expand Down
25 changes: 25 additions & 0 deletions src/YogaProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { createContext, PropsWithChildren, useCallback, useContext, useMemo } from 'react'
import { useAsset } from 'use-asset'
// eslint-disable-next-line import/no-unresolved
import Yoga from 'yoga-layout'

interface YogaContextData {
initYoga: () => Promise<typeof Yoga>
}

const YogaContext = createContext<YogaContextData>({
initYoga() {
return Promise.reject(new Error("YogaRuntimeProvider hasn't been initialized"))
},
})

export const YogaProvider = ({ initYoga, ...props }: PropsWithChildren<YogaContextData>) => {
const value = useMemo(() => ({ initYoga }), [initYoga])
return <YogaContext.Provider value={value} {...props} />
}

export const useYoga = (): typeof Yoga => {
const { initYoga } = useContext(YogaContext)
const yoga = useAsset(initYoga)
return yoga
}
3 changes: 2 additions & 1 deletion src/context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createContext } from 'react'
import { YogaNode } from 'yoga-layout-prebuilt'
// eslint-disable-next-line import/no-unresolved
import type { YogaNode } from 'yoga-layout'
import { Group } from 'three'
import { R3FlexProps } from './props'

Expand Down
6 changes: 4 additions & 2 deletions src/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useCallback, useContext as useContextImpl, useMemo } from 'react'
import React, { useCallback, useContext as useContextImpl, useMemo } from 'react'
import { Mesh, Vector3 } from 'three'
import { flexContext, boxContext } from './context'
// eslint-disable-next-line import/no-unresolved
import type { YogaNode } from 'yoga-layout'

export function useContext<T extends { notInitialized?: boolean }>(context: React.Context<T>) {
let result = useContextImpl(context)
Expand All @@ -27,7 +29,7 @@ export function useFlexSize() {
return value
}

export function useFlexNode() {
export function useFlexNode(): YogaNode | null {
const { node } = useContext(boxContext)
return node
}
Expand Down
14 changes: 14 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React, { PropsWithChildren, useCallback } from 'react'
import Yoga from 'yoga-layout-prebuilt'
import { YogaProvider } from './YogaProvider'

export * from './Box'
export * from './Flex'
export * from './props'
export * from './hooks'
export type { Axis } from './util'

export const YogaPrebuiltProvider = (props: PropsWithChildren<{}>) => {
const initYoga = useCallback(() => Promise.resolve(Yoga), [])
return <YogaProvider initYoga={initYoga} {...props} />
}
1 change: 1 addition & 0 deletions src/index.ts → src/outerRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from './Box'
export * from './Flex'
export * from './props'
export * from './hooks'
export * from './YogaProvider'
export type { Axis } from './util'
9 changes: 8 additions & 1 deletion src/props.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { YogaFlexDirection, YogaAlign, YogaJustifyContent, YogaFlexWrap, YogaDirection } from 'yoga-layout-prebuilt'
import type {
YogaFlexDirection,
YogaAlign,
YogaJustifyContent,
YogaFlexWrap,
YogaDirection,
// eslint-disable-next-line import/no-unresolved
} from 'yoga-layout'

export type FlexYogaDirection = YogaDirection | 'ltr' | 'rtl'
export type FlexPlane = 'xy' | 'yz' | 'xz'
Expand Down
7 changes: 5 additions & 2 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Box3, Matrix4, Object3D, Vector3 } from 'three'
import Yoga, { YogaNode } from 'yoga-layout-prebuilt'
// eslint-disable-next-line import/no-unresolved
import type { YogaNode } from 'yoga-layout'
import { R3FlexProps, FlexPlane } from './props'

export const capitalize = (s: string) => s[0].toUpperCase() + s.slice(1)

export const jsxPropToYogaProp = (s: string) => s.toUpperCase().replace('-', '_')

export const setYogaProperties = (node: YogaNode, props: R3FlexProps, scaleFactor: number) => {
type YogaStatic = any

export const setYogaProperties = (Yoga: YogaStatic, node: YogaNode, props: R3FlexProps, scaleFactor: number) => {
return Object.keys(props).forEach((name) => {
const value = props[name as keyof R3FlexProps]

Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"removeComments": false,
"baseUrl": ".",
"paths": {
"@react-three/flex": ["./src/index.ts"]
"@react-three/flex": ["src/index.tsx"]
}
},
"include": ["src"]
Expand Down
5 changes: 5 additions & 0 deletions vite-wasm-example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
13 changes: 13 additions & 0 deletions vite-wasm-example/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
23 changes: 23 additions & 0 deletions vite-wasm-example/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "examples2",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"serve": "vite preview"
},
"dependencies": {
"@react-three/fiber": "^7.0.7",
"@react-three/flex": "^0.7.0",
"react": "^17.0.0",
"react-dom": "^17.0.0",
"yoga-layout-wasm": "^1.9.3-alpha.7"
},
"devDependencies": {
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@vitejs/plugin-react": "^1.0.0",
"typescript": "^4.3.2",
"vite": "^2.5.4"
}
}
Loading

0 comments on commit 08c64fa

Please sign in to comment.