Compare commits

..

8 Commits

Author SHA1 Message Date
Nick Gerleman
af57b2164d Fix JS build on Windows (#1648)
Summary:
Pull Request resolved: https://github.com/facebook/yoga/pull/1648

Node made a breaking change in a security release for 18/20 where `spawn()` no longer loads `.bat` files by default. 69ffc6d50d. Execute command in shell.

Reviewed By: javache

Differential Revision: D56230965

fbshipit-source-id: 52e9bd8a76664bd07ea25b6355ac54fcb24cbb9a
2024-04-19 12:14:03 -07:00
Nick Gerleman
1b9b878b9a Set version to 3.0.4 2024-04-17 00:02:16 -07:00
Nick Gerleman
866f503bde Don't run test validation off main branch (#1644)
Summary:
Pull Request resolved: https://github.com/facebook/yoga/pull/1644

Because Chrome behaviors can change

Reviewed By: cortinico

Differential Revision: D56088135

fbshipit-source-id: 7f760786dde061df9af034368e2184117e6e6846
2024-04-17 00:01:02 -07:00
Nick Gerleman
29f016c1ea Isolate Distributed JavaScript (#1645)
Summary:
Pull Request resolved: https://github.com/facebook/yoga/pull/1645

Right now we publish Yoga by transforming in-place, and rewriting the entrypoint to point to the generated vanilla JavaScript.

It is nice to include the original source, e.g. so that users can use sourcemaps when debugging, but putting these files on top of each other has been causing problems, like https://github.com/facebook/yoga/issues/1637#issuecomment-2049099690

This changes the packaging step to instead put all the outputs into a "dist" folder, and point the package entrypoints there. We still include original source for sourcemap usage.

Reviewed By: yungsters

Differential Revision: D56093470

fbshipit-source-id: ecd52dddd9040294aae66747cf1fdf48c7f602e7
2024-04-17 00:00:55 -07:00
Nick Gerleman
ed5d2ffc2d Set version to 3.0.3 2024-04-09 16:13:40 -07:00
Willson Haw
8a9758a2cc Add JavaScript bindings for YGHasNewLayout (#1631)
Summary:
Adds JavaScript bindings for YGHasNewLayout which introduces
two new node methods: `hasNewLayout()` and `markLayoutSeen()`.

Closes https://github.com/facebook/yoga/issues/681

Pull Request resolved: https://github.com/facebook/yoga/pull/1631

Reviewed By: joevilches

Differential Revision: D55213296

Pulled By: NickGerleman

fbshipit-source-id: 161288c3f54c2b82a6b2b842387916fe8713c2c9
2024-04-09 16:04:35 -07:00
Bela Bohlender
334eebc484 Entry point without TLA for js package (#1638)
Summary:
Follow up on https://github.com/facebook/yoga/issues/1637

TLDR: tooling for TLA is not there yet; An additional entry point without top-level-await is appropriate

- adds ./load entry to js package
- uses .js file extensions to prevent requiring [allowImportingTsExtensions](https://www.typescriptlang.org/tsconfig#allowImportingTsExtensions)

Pull Request resolved: https://github.com/facebook/yoga/pull/1638

Reviewed By: joevilches

Differential Revision: D55614636

Pulled By: NickGerleman

fbshipit-source-id: 126a94aa68d22d32b938282cfa1a5059bb9df337
2024-04-09 16:03:21 -07:00
Nick Gerleman
5b106e5dd5 Bump README 2024-04-03 20:28:56 -07:00
14 changed files with 176 additions and 20 deletions

View File

@@ -5,7 +5,6 @@ on:
push: push:
branches: branches:
- main - main
- 'release-*'
workflow_dispatch: workflow_dispatch:
jobs: jobs:

View File

@@ -6,7 +6,7 @@
Pod::Spec.new do |spec| Pod::Spec.new do |spec|
spec.name = 'Yoga' spec.name = 'Yoga'
spec.version = '3.0.2' spec.version = '3.0.4'
spec.license = { :type => 'MIT', :file => "LICENSE" } spec.license = { :type => 'MIT', :file => "LICENSE" }
spec.homepage = 'https://yogalayout.dev/' spec.homepage = 'https://yogalayout.dev/'
spec.documentation_url = 'https://yogalayout.dev/docs' spec.documentation_url = 'https://yogalayout.dev/docs'

View File

@@ -11,4 +11,4 @@ android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
VERSION_NAME=3.0.2 VERSION_NAME=3.0.4

View File

@@ -29,3 +29,12 @@ node.free();
## Requirements ## Requirements
`yoga-layout` requires a toolchain that supports ES Modules and top-level await. `yoga-layout` requires a toolchain that supports ES Modules and top-level await.
If top-level-await is not supported, use the `yoga-layout/load` entry point instead. This requires to load yoga manually:
```ts
import {loadYoga, Align} from 'yoga-layout/load';
const node = (await loadYoga).Node.create();
node.setAlignContent(Align.Center);
```

View File

@@ -13,11 +13,11 @@ const {
logger, logger,
jestTask, jestTask,
option, option,
parallel,
series, series,
spawn, spawn,
task, task,
tscTask, tscTask,
copyTask,
} = require('just-scripts'); } = require('just-scripts');
const {existsSync} = require('fs'); const {existsSync} = require('fs');
@@ -58,16 +58,32 @@ task('prepack-package-json', async () => {
const packageJsonContents = await readFile(packageJsonPath); const packageJsonContents = await readFile(packageJsonPath);
const packageJson = JSON.parse(packageJsonContents.toString('utf-8')); const packageJson = JSON.parse(packageJsonContents.toString('utf-8'));
recursiveReplace(packageJson, /(.\/src\/.*)\.ts/, '$1.js'); packageJson.main = packageJson.main.replace(
packageJson.types = packageJson.main.replace(/(.\/src\/.*)\.js/, '$1.d.ts'); /^.\/src\/(.*)\.ts/,
'./dist/src/$1.js',
);
packageJson.types = packageJson.main.replace(/(.*)\.js/, '$1.d.ts');
recursiveReplace(
packageJson.exports,
/^.\/src\/(.*)\.ts/,
'./dist/src/$1.js',
);
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2)); await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
}); });
task( task(
'prepack', 'prepack',
series( series(
parallel('build', tscTask({emitDeclarationOnly: true})), 'build',
babelTransformTask({dir: 'src'}), copyTask({paths: ['binaries'], dest: 'dist/binaries'}),
tscTask({
emitDeclarationOnly: true,
rootDir: '.',
declarationDir: 'dist',
}),
babelTransformTask({src: 'src', dst: 'dist/src'}),
'prepack-package-json', 'prepack-package-json',
), ),
); );
@@ -85,14 +101,14 @@ function recursiveReplace(obj, pattern, replacement) {
function babelTransformTask(opts) { function babelTransformTask(opts) {
return () => { return () => {
const args = [ const args = [
opts.dir, opts.src,
'--source-maps', '--source-maps',
'--out-dir', '--out-dir',
opts.dir, opts.dst,
'--extensions', '--extensions',
'.js,.cjs,.mjs,.ts,.cts,.mts', '.js,.cjs,.mjs,.ts,.cts,.mts',
]; ];
logger.info(`Transforming "${path.resolve(opts.dir)}"`); logger.info(`Transforming "${path.resolve(opts.src)}"`);
return spawn(node, [require.resolve('@babel/cli/bin/babel'), ...args], { return spawn(node, [require.resolve('@babel/cli/bin/babel'), ...args], {
cwd: __dirname, cwd: __dirname,
@@ -152,9 +168,9 @@ function installEmsdkTask() {
{stdio: 'inherit'}, {stdio: 'inherit'},
); );
await spawn(emsdkBin, ['install', emsdkVersion], {stdio: 'inherit'}); await spawnShell(emsdkBin, ['install', emsdkVersion], {stdio: 'inherit'});
await spawn(emsdkBin, ['activate', emsdkVersion], { await spawnShell(emsdkBin, ['activate', emsdkVersion], {
stdio: logger.enableVerbose ? 'inherit' : 'ignore', stdio: logger.enableVerbose ? 'inherit' : 'ignore',
}); });
}; };
@@ -200,7 +216,7 @@ function emcmakeGenerateTask() {
]; ];
logger.info(['emcmake', ...args].join(' ')); logger.info(['emcmake', ...args].join(' '));
return spawn(emcmakeBin, args, { return spawnShell(emcmakeBin, args, {
stdio: logger.enableVerbose ? 'inherit' : 'ignore', stdio: logger.enableVerbose ? 'inherit' : 'ignore',
}); });
}; };
@@ -218,7 +234,7 @@ function cmakeBuildTask(opts) {
]; ];
logger.info(['cmake', ...args].join(' ')); logger.info(['cmake', ...args].join(' '));
return spawn(cmake, args, {stdio: 'inherit'}); return spawnShell(cmake, args, {stdio: 'inherit'});
}; };
} }
@@ -230,8 +246,13 @@ function clangFormatTask(opts) {
]; ];
logger.info(['clang-format', ...args].join(' ')); logger.info(['clang-format', ...args].join(' '));
return spawn(node, [require.resolve('clang-format'), ...args], { return spawnShell(node, [require.resolve('clang-format'), ...args], {
stdio: 'inherit', stdio: 'inherit',
}); });
}; };
} }
function spawnShell(cmd, args, opts) {
// https://github.com/nodejs/node/issues/52554
return spawn(cmd, args, {...opts, shell: true});
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "yoga-layout", "name": "yoga-layout",
"version": "3.0.2", "version": "3.0.4",
"description": "An embeddable and performant flexbox layout engine with bindings for multiple languages", "description": "An embeddable and performant flexbox layout engine with bindings for multiple languages",
"license": "MIT", "license": "MIT",
"author": "Meta Open Source", "author": "Meta Open Source",
@@ -11,8 +11,14 @@
}, },
"type": "module", "type": "module",
"main": "./src/index.ts", "main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./load": "./src/load.ts"
},
"files": [ "files": [
"binaries/**", "dist/binaries/**",
"dist/src/**",
"src/**" "src/**"
], ],
"scripts": { "scripts": {

View File

@@ -413,6 +413,14 @@ bool Node::isDirty(void) const {
return YGNodeIsDirty(m_node); return YGNodeIsDirty(m_node);
} }
void Node::markLayoutSeen() {
YGNodeSetHasNewLayout(m_node, false);
}
bool Node::hasNewLayout(void) const {
return YGNodeGetHasNewLayout(m_node);
}
void Node::calculateLayout(double width, double height, int direction) { void Node::calculateLayout(double width, double height, int direction) {
YGNodeCalculateLayout( YGNodeCalculateLayout(
m_node, width, height, static_cast<YGDirection>(direction)); m_node, width, height, static_cast<YGDirection>(direction));

View File

@@ -195,6 +195,8 @@ class Node {
public: // Dirtiness accessors public: // Dirtiness accessors
void markDirty(void); void markDirty(void);
bool isDirty(void) const; bool isDirty(void) const;
void markLayoutSeen();
bool hasNewLayout(void) const;
public: // Layout mutators public: // Layout mutators
void calculateLayout(double width, double height, int direction); void calculateLayout(double width, double height, int direction);

View File

@@ -175,6 +175,9 @@ EMSCRIPTEN_BINDINGS(YOGA_LAYOUT) {
.function("markDirty", &Node::markDirty) .function("markDirty", &Node::markDirty)
.function("isDirty", &Node::isDirty) .function("isDirty", &Node::isDirty)
.function("markLayoutSeen", &Node::markLayoutSeen)
.function("hasNewLayout", &Node::hasNewLayout)
.function("calculateLayout", &Node::calculateLayout) .function("calculateLayout", &Node::calculateLayout)
.function("getComputedLeft", &Node::getComputedLeft) .function("getComputedLeft", &Node::getComputedLeft)

25
javascript/src/load.ts Normal file
View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
// @ts-ignore untyped from Emscripten
import loadYogaImpl from '../binaries/yoga-wasm-base64-esm.js';
import wrapAssembly from './wrapAssembly.ts';
export type {
Config,
DirtiedFunction,
MeasureFunction,
Node,
Yoga,
} from './wrapAssembly.ts';
export async function loadYoga() {
return wrapAssembly(await loadYogaImpl());
}
export * from './generated/YGEnums.ts';

View File

@@ -119,6 +119,8 @@ export type Node = {
isDirty(): boolean; isDirty(): boolean;
isReferenceBaseline(): boolean; isReferenceBaseline(): boolean;
markDirty(): void; markDirty(): void;
hasNewLayout(): boolean;
markLayoutSeen(): void;
removeChild(child: Node): void; removeChild(child: Node): void;
reset(): void; reset(): void;
setAlignContent(alignContent: Align): void; setAlignContent(alignContent: Align): void;

View File

@@ -0,0 +1,81 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import Yoga from 'yoga-layout';
test('new_layout_can_be_marked_seen', () => {
const root = Yoga.Node.create();
root.markLayoutSeen();
expect(root.hasNewLayout()).toBe(false);
});
test('new_layout_calculating_layout_marks_layout_as_unseen', () => {
const root = Yoga.Node.create();
root.markLayoutSeen();
root.calculateLayout(undefined, undefined);
expect(root.hasNewLayout()).toBe(true);
});
test('new_layout_calculated_layout_can_be_marked_seen', () => {
const root = Yoga.Node.create();
root.calculateLayout(undefined, undefined);
root.markLayoutSeen();
expect(root.hasNewLayout()).toBe(false);
});
test('new_layout_recalculating_layout_does_mark_as_unseen', () => {
const root = Yoga.Node.create();
root.calculateLayout(undefined, undefined);
root.markLayoutSeen();
root.calculateLayout(undefined, undefined);
expect(root.hasNewLayout()).toBe(true);
});
test('new_layout_reset_also_resets_layout_seen', () => {
const root = Yoga.Node.create();
root.markLayoutSeen();
root.reset();
expect(root.hasNewLayout()).toBe(true);
});
test('new_layout_children_sets_new_layout', () => {
const root = Yoga.Node.create();
root.setAlignItems(Yoga.ALIGN_FLEX_START);
root.setWidth(100);
root.setHeight(100);
const root_child0 = Yoga.Node.create();
root_child0.setAlignItems(Yoga.ALIGN_FLEX_START);
root_child0.setWidth(50);
root_child0.setHeight(20);
root.insertChild(root_child0, 0);
const root_child1 = Yoga.Node.create();
root_child1.setAlignItems(Yoga.ALIGN_FLEX_START);
root_child1.setWidth(50);
root_child1.setHeight(20);
root.insertChild(root_child1, 0);
expect(root.hasNewLayout()).toEqual(true);
expect(root_child0.hasNewLayout()).toEqual(true);
expect(root_child1.hasNewLayout()).toEqual(true);
root.markLayoutSeen();
root_child0.markLayoutSeen();
root_child1.markLayoutSeen();
expect(root.hasNewLayout()).toEqual(false);
expect(root_child0.hasNewLayout()).toEqual(false);
expect(root_child1.hasNewLayout()).toEqual(false);
root_child1.setHeight(30);
root.calculateLayout(undefined, undefined);
expect(root.hasNewLayout()).toEqual(true);
expect(root_child0.hasNewLayout()).toEqual(true);
expect(root_child1.hasNewLayout()).toEqual(true);
});

View File

@@ -27,7 +27,7 @@
"react": "^18.0.0", "react": "^18.0.0",
"react-dom": "^18.0.0", "react-dom": "^18.0.0",
"react-live": "^4.1.5", "react-live": "^4.1.5",
"yoga-layout": "3.0.2" "yoga-layout": "3.0.4"
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/module-type-aliases": "3.0.0", "@docusaurus/module-type-aliases": "3.0.0",

View File

@@ -1,4 +1,4 @@
# Yoga documentation and playground # Yoga legacy documentation and playground
This site uses [gatsby.js](https://www.gatsbyjs.org/) as static site generator. Which transforms all markdown and react code to static HTML and JS files. This site uses [gatsby.js](https://www.gatsbyjs.org/) as static site generator. Which transforms all markdown and react code to static HTML and JS files.