Skip to content

Commit

Permalink
Merge pull request #14 from leweyse/feat/yoga-v2
Browse files Browse the repository at this point in the history
Feat: Yoga v2
  • Loading branch information
bbohlender authored Mar 6, 2024
2 parents 495d419 + bf11750 commit c3ee870
Show file tree
Hide file tree
Showing 19 changed files with 79 additions and 278 deletions.
7 changes: 0 additions & 7 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,6 @@ jobs:
cp ./packages/fonts/dist/* ./public/fonts
cp ./packages/fonts/LICENSE public/fonts/LICENSE
# Yoga Wasm
- name: Copy wasm files
run: |
mkdir public/yoga
cp packages/uikit/node_modules/yoga-wasm-web/dist/yoga.wasm public/yoga/yoga.wasm
cp ./packages/uikit/THIRD_PARTY_LICENSES public/yoga/THIRD_PARTY_LICENSES
# Examples
- name: Building Examples
run: |
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ TODO Release
- feat: drag/click threshold
- feat: input
- fix: decrease clipping rect when scrollbar present
- feat: upgrade to yoga2.0

Roadmap

Expand Down
3 changes: 1 addition & 2 deletions examples/uikit/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Suspense, useMemo, useState } from 'react'
import { Canvas } from '@react-three/fiber'
import { Gltf, Box, PerspectiveCamera } from '@react-three/drei'
import { Gltf, Box, PerspectiveCamera, RenderTexture } from '@react-three/drei'
import { signal } from '@preact/signals-core'
import {
DefaultProperties,
Expand All @@ -14,7 +14,6 @@ import {
Portal,
SuspendingImage,
} from '@react-three/uikit'
import { RenderTexture } from '@react-three/drei'
import { Texture } from 'three'
import { Skeleton } from '../../../packages/kits/default/skeleton'

Expand Down
28 changes: 1 addition & 27 deletions packages/uikit/THIRD_PARTY_LICENSES
Original file line number Diff line number Diff line change
@@ -1,32 +1,6 @@
yoga-wasm-web:

MIT License

Copyright (c) 2022 Shu Ding

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

yoga-layout-wasm:

MIT License

Copyright (c) 2020 黄祺
Copyright (c) Facebook, Inc. and its affiliates.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
8 changes: 2 additions & 6 deletions packages/uikit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
"scripts": {
"test": "mocha ./tests/allocation.spec.ts",
"build": "tsc",
"inline-wasm": "wasmwrap --include-decode false --input node_modules/yoga-wasm-web/dist/yoga.wasm --output src/flex/wasm.ts",
"fix:inline-wasm": "replace-in-files --string 'const base64 =' --replacement 'const base64: string =' src/flex/wasm.ts",
"generate": "node --loader ts-node/esm scripts/flex-generate-setter.ts",
"check:prettier": "prettier --check src scripts tests",
"check:eslint": "eslint 'src/**/*.{tsx,ts}'",
Expand All @@ -44,12 +42,11 @@
},
"dependencies": {
"@preact/signals-core": "^1.5.1",
"base64-js": "^1.5.1",
"chalk": "^5.3.0",
"commander": "^12.0.0",
"ora": "^8.0.1",
"prompts": "^2.4.2",
"yoga-wasm-web": "^0.3.3",
"yoga-layout": "^2.0.1",
"zod": "^3.22.4"
},
"devDependencies": {
Expand All @@ -63,7 +60,6 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"replace-in-files-cli": "^2.2.0",
"three": "^0.161.0",
"wasmwrap": "^1.0.0"
"three": "^0.161.0"
}
}
52 changes: 20 additions & 32 deletions packages/uikit/scripts/flex-generate-setter.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import { writeFileSync } from 'fs'
import {
EDGE_BOTTOM,
EDGE_LEFT,
EDGE_RIGHT,
EDGE_TOP,
Node,
UNIT_AUTO,
UNIT_PERCENT,
UNIT_POINT,
UNIT_UNDEFINED,
} from 'yoga-wasm-web'
import { GUTTER_ROW, GUTTER_COLUMN } from 'yoga-wasm-web'
import { loadYogaBase64 } from '../src/flex/load-base64.js'
import { loadYoga, Edge, Gutter, Unit, Node } from 'yoga-layout/wasm-async'

async function main() {
const yoga = await loadYogaBase64()
const yoga = await loadYoga()
const node = yoga.Node.create()

const propertiesWithEdge = new Set(['border', 'padding', 'margin', 'position'])
Expand All @@ -34,15 +22,16 @@ async function main() {
}

const edgeMap = {
Top: EDGE_TOP,
Left: EDGE_LEFT,
Right: EDGE_RIGHT,
Bottom: EDGE_BOTTOM,
Top: Edge.Top,
Left: Edge.Left,
Right: Edge.Right,
Bottom: Edge.Bottom,
}
const gutterMap = {
Row: GUTTER_ROW,
Column: GUTTER_COLUMN,
Row: Gutter.Row,
Column: Gutter.Column,
}

const yogaKeys = Object.entries(yoga)

const kebabCaseFromSnakeCase = (str: string) =>
Expand Down Expand Up @@ -119,11 +108,11 @@ async function main() {
}
}
if (propertiesWithEdge.has(propertyName)) {
importedTypesFromYoga.add('Edge')
for (const [edgeKey, edge] of Object.entries(edgeMap)) {
const defaultValue = fromYoga(propertyName, node[`get${functionName}` as 'getBorder'](edge))
const edgePropertyName = `${propertyName}${edgeKey}`
const edgeType = `EDGE_${edgeKey.toUpperCase()}`
importedTypesFromYoga.add(edgeType)
const edgeType = `Edge.${edgeKey}`
setterFunctions.push([
edgePropertyName,
`(node: Node, precision: number, input: ${types.join(' | ')}) =>
Expand All @@ -135,11 +124,11 @@ async function main() {
])
}
} else if (propertiesWithGutter.has(propertyName)) {
importedTypesFromYoga.add('Gutter')
for (const [gutterKey, gutter] of Object.entries(gutterMap)) {
const defaultValue = fromYoga(propertyName, node[`get${functionName}` as 'getGap'](gutter))
const gutterPropertyName = `${propertyName}${gutterKey}`
const gutterType = `GUTTER_${gutterKey.toUpperCase()}`
importedTypesFromYoga.add(gutterType)
const gutterType = `Gutter.${gutterKey}`
setterFunctions.push([
gutterPropertyName,
`(node: Node, precision: number, input: ${types.join(' | ')}) =>
Expand All @@ -166,8 +155,8 @@ async function main() {

writeFileSync(
'src/flex/setter.ts',
`import { Node } from "yoga-wasm-web"
import type { ${Array.from(importedTypesFromYoga).join(', ')} } from "yoga-wasm-web"
`import { Node } from "yoga-layout/wasm-async"
import type { ${Array.from(importedTypesFromYoga).join(', ')} } from "yoga-layout/wasm-async"
function convertEnum<T extends { [Key in string]: number }>(lut: T, input: keyof T | undefined, defaultValue: T[keyof T]): T[keyof T] {
if(input == null) {
return defaultValue
Expand Down Expand Up @@ -199,8 +188,7 @@ function createLookupTable(
return `const ${name} = {
${values
.map(([key, value, type]) => {
importedTypesFromYoga.add(type)
return `"${key}": ${value} as ${type}`
return `"${key}": ${value}`
})
.join(',\n')}
} as const`
Expand All @@ -209,13 +197,13 @@ function createLookupTable(
function fromYoga(name: string, value: any): 'auto' | `${number}%` | number | null {
if (typeof value === 'object') {
switch (value.unit) {
case UNIT_AUTO:
case Unit.Auto:
return 'auto'
case UNIT_PERCENT:
case Unit.Percent:
return `${value.value}%`
case UNIT_POINT:
case Unit.Point:
return value.value ?? null
case UNIT_UNDEFINED:
case Unit.Undefined:
return null
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/uikit/src/clipping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { RefObject, createContext, useContext, useMemo } from 'react'
import { Group, Matrix4, Plane, Vector3 } from 'three'
import type { Vector2Tuple } from 'three'
import { Inset } from './flex/node.js'
import { OVERFLOW_VISIBLE, Overflow } from 'yoga-wasm-web'
import { Overflow } from 'yoga-layout/wasm-async'

const dotLt45deg = Math.cos((45 / 180) * Math.PI)

Expand Down Expand Up @@ -157,7 +157,7 @@ export function useClippingRect(
() =>
computed(() => {
const global = globalMatrix.value
if (global == null || overflow.value === OVERFLOW_VISIBLE) {
if (global == null || overflow.value === Overflow.Visible) {
return parentClippingRect?.value
}
const [width, height] = size.value
Expand Down
2 changes: 0 additions & 2 deletions packages/uikit/src/components/fullscreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import { DEFAULT_PIXEL_SIZE, Root, RootProperties } from './root.js'
import { batch, signal } from '@preact/signals-core'
import { RootState, createPortal, useFrame, useStore, useThree } from '@react-three/fiber'
import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events.js'
import { Yoga } from 'yoga-wasm-web'
import { ScrollListeners } from '../scroll.js'
import { ComponentInternals, LayoutListeners } from './utils.js'
import { Group, PerspectiveCamera } from 'three'

export const Fullscreen = forwardRef<
ComponentInternals,
RootProperties & {
loadYoga?: () => Promise<Yoga>
children?: ReactNode
precision?: number
attachCamera?: boolean
Expand Down
5 changes: 1 addition & 4 deletions packages/uikit/src/components/root.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Yoga } from 'yoga-wasm-web'
import { ReactNode, forwardRef, useEffect, useMemo, useRef } from 'react'
import { FlexNode, YogaProperties } from '../flex/node.js'
import { RootGroupProvider, alignmentXMap, alignmentYMap, useLoadYoga } from '../utils.js'
Expand Down Expand Up @@ -48,7 +47,6 @@ import { WithClasses, useApplyProperties } from '../properties/default.js'
import { InstancedGlyphProvider, useGetInstancedGlyphGroup } from '../text/react.js'
import { PanelProperties } from '../panel/instanced-panel.js'
import { RootSizeProvider, useApplyResponsiveProperties } from '../responsive.js'
import { loadYogaFromGH } from '../flex/load-binary.js'
import { ElementType, OrderInfoProvider, patchRenderOrder, useOrderInfo } from '../order.js'
import { useApplyPreferredColorSchemeProperties } from '../dark.js'
import { useApplyActiveProperties } from '../active.js'
Expand All @@ -73,7 +71,6 @@ const vectorHelper = new Vector3()
export const Root = forwardRef<
ComponentInternals,
RootProperties & {
loadYoga?: () => Promise<Yoga>
children?: ReactNode
precision?: number
anchorX?: keyof typeof alignmentXMap
Expand All @@ -99,7 +96,7 @@ export const Root = forwardRef<
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
)
const yoga = useLoadYoga(properties.loadYoga ?? loadYogaFromGH)
const yoga = useLoadYoga()
const distanceToCameraRef = useMemo(() => ({ current: 0 }), [])
const groupRef = useRef<Group>(null)
const requestLayout = useDeferredRequestLayoutCalculation()
Expand Down
2 changes: 0 additions & 2 deletions packages/uikit/src/flex/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export * from './utils.js'
export * from './setter.js'
export * from './load-base64.js'
export * from './load-binary.js'
export * from './node.js'
export * from './react.js'
7 changes: 0 additions & 7 deletions packages/uikit/src/flex/load-base64.ts

This file was deleted.

6 changes: 0 additions & 6 deletions packages/uikit/src/flex/load-binary.ts

This file was deleted.

34 changes: 12 additions & 22 deletions packages/uikit/src/flex/node.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import { Group, Object3D, Vector2Tuple } from 'three'
import { Signal, batch, computed, effect, signal } from '@preact/signals-core'
import {
EDGE_TOP,
EDGE_LEFT,
EDGE_RIGHT,
EDGE_BOTTOM,
Node,
Yoga,
OVERFLOW_VISIBLE,
Overflow,
OVERFLOW_SCROLL,
} from 'yoga-wasm-web'
import { Edge, Node, Yoga, Overflow } from 'yoga-layout/wasm-async'
import { setter } from './setter.js'
import { setMeasureFunc, yogaNodeEqual } from './utils.js'
import { WithImmediateProperties } from '../properties/immediate.js'
Expand All @@ -28,7 +18,7 @@ export class FlexNode implements WithImmediateProperties {
public readonly relativeCenter = signal<Vector2Tuple>([0, 0])
public readonly borderInset = signal<Inset>([0, 0, 0, 0])
public readonly paddingInset = signal<Inset>([0, 0, 0, 0])
public readonly overflow = signal<Overflow>(OVERFLOW_VISIBLE)
public readonly overflow = signal<Overflow>(Overflow.Visible)
public readonly maxScrollPosition = signal<Partial<Vector2Tuple>>([undefined, undefined])
public readonly scrollable = signal<[boolean, boolean]>([false, false])

Expand Down Expand Up @@ -214,16 +204,16 @@ export class FlexNode implements WithImmediateProperties {
const relativeCenterY = -(y + height * 0.5 - parentHeight * 0.5)
updateVector2Signal(this.relativeCenter, relativeCenterX, relativeCenterY)

const paddingTop = this.yogaNode.getComputedPadding(EDGE_TOP) * this.precision
const paddingLeft = this.yogaNode.getComputedPadding(EDGE_LEFT) * this.precision
const paddingRight = this.yogaNode.getComputedPadding(EDGE_RIGHT) * this.precision
const paddingBottom = this.yogaNode.getComputedPadding(EDGE_BOTTOM) * this.precision
const paddingTop = this.yogaNode.getComputedPadding(Edge.Top) * this.precision
const paddingLeft = this.yogaNode.getComputedPadding(Edge.Left) * this.precision
const paddingRight = this.yogaNode.getComputedPadding(Edge.Right) * this.precision
const paddingBottom = this.yogaNode.getComputedPadding(Edge.Bottom) * this.precision
updateInsetSignal(this.paddingInset, paddingTop, paddingRight, paddingBottom, paddingLeft)

const borderTop = this.yogaNode.getComputedBorder(EDGE_TOP) * this.precision
const borderRight = this.yogaNode.getComputedBorder(EDGE_RIGHT) * this.precision
const borderBottom = this.yogaNode.getComputedBorder(EDGE_BOTTOM) * this.precision
const borderLeft = this.yogaNode.getComputedBorder(EDGE_LEFT) * this.precision
const borderTop = this.yogaNode.getComputedBorder(Edge.Top) * this.precision
const borderRight = this.yogaNode.getComputedBorder(Edge.Right) * this.precision
const borderBottom = this.yogaNode.getComputedBorder(Edge.Bottom) * this.precision
const borderLeft = this.yogaNode.getComputedBorder(Edge.Left) * this.precision
updateInsetSignal(this.borderInset, borderTop, borderRight, borderBottom, borderLeft)

for (const layoutChangeListener of this.layoutChangeListeners) {
Expand All @@ -242,7 +232,7 @@ export class FlexNode implements WithImmediateProperties {
maxContentWidth -= borderLeft
maxContentHeight -= borderTop

if (this.overflow.value === OVERFLOW_SCROLL) {
if (this.overflow.value === Overflow.Scroll) {
maxContentWidth += paddingRight
maxContentHeight += paddingLeft

Expand All @@ -263,7 +253,7 @@ export class FlexNode implements WithImmediateProperties {
updateVector2Signal(this.scrollable, false, false)
}

const overflowVisible = this.overflow.value === OVERFLOW_VISIBLE
const overflowVisible = this.overflow.value === Overflow.Visible

return [
x + Math.max(width, overflowVisible ? maxContentWidth : 0),
Expand Down
2 changes: 1 addition & 1 deletion packages/uikit/src/flex/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MeasureFunction, Node } from 'yoga-wasm-web'
import { Node, MeasureFunction } from 'yoga-layout/wasm-async'

export function yogaNodeEqual(n1: Node, n2: Node): boolean {
return (n1 as any)['L'] === (n2 as any)['L']
Expand Down
1 change: 0 additions & 1 deletion packages/uikit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export {
type PreferredColorScheme,
} from './dark.js'
export { FontFamilyProvider } from './text/react.js'
export { loadYogaBase64 } from './flex/load-base64.js'
export { useRootSize } from './responsive.js'
export type { ComponentInternals } from './components/utils.js'
export type { MaterialClass } from './panel/react.js'
Expand Down
Loading

0 comments on commit c3ee870

Please sign in to comment.