샘플
yoga-layout 3.2.1: Configure Yoga.Config with useWebDefaults and pointScaleFactor to apply CSS flexbox defaults and subpixel rounding across parent and child nodes
검증된 샘플 — npm yoga-layout 3.2.1: Configure Yoga.Config with useWebDefaults and pointScaleFactor to apply CSS flexbox defaults and subpixel rounding across…
sha256:213ce2ec407485da262aa6339bc72e3486919b672c93e548819586c905ed88f2
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
MIT-0
실행 증거
선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.
- 증거 기준
- 서명된 컨트랙트 통과
- 검증 영수증
- 3
- 빌드한 서명 키
- 3
선언된 환경
node linux x64 node node npm
검증 실행 환경
| 환경 | 컨트랙트 | 단계 | 실행일 |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-16 |
| node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-18 |
| node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5… |
2026-09-07 |
케이스
HOW- 목표
- Configure Yoga.Config with useWebDefaults and pointScaleFactor to apply CSS flexbox defaults and subpixel rounding across parent and child nodes
- 심벌
-
- Yoga.Config.create
- Config.setUseWebDefaults
- Config.setPointScaleFactor
- Yoga.Node.create
- Node.calculateLayout
- Node.getComputedWidth
- Node.getFlexShrink
- Node.getFlexDirection
- Node.insertChild
- Node.freeRecursive
- Config.free
- 환경
- node
- 생성일
- 2026-08-16T07:08:30Z
컨트랙트
- assert yoga-layout resolved version is 3.2.1
- assert default Config has useWebDefaults disabled (false) and default Node uses React Native defaults (flexDirection Column, flexShrink 0, alignContent FlexStart)
- assert Config with setUseWebDefaults(true) sets web defaults (flexDirection Row, flexShrink 1, alignContent Stretch)
- assert child Node does not inherit Config from parent upon insertion and retains flexShrink 0 unless created with the Config
- assert overflowing children in a fixed row fail to shrink under Yoga defaults (overflowing container to 300px width)
- assert overflowing children in a fixed row shrink to fit (100px each, 200px total) when created with useWebDefaults Config
- assert pointScaleFactor 1.0 rounds coordinates to integer pixel boundaries (10.6 to 11 and 10.4 to 10)
- assert pointScaleFactor 0.0 disables pixel snapping and preserves exact subpixel floating point values
- assert pointScaleFactor 2.0 snaps coordinates to half-pixel multiples (10.25 to 10.5 and 10.75 to 11.0)
- assert freeing root node with freeRecursive releases entire tree and Config.free releases config allocation
파일
- NOTES.md
- csx.json
- package-lock.json
- package.json
- src/index.js
- test/contract.mjs
소스
# Notes: yoga-layout Config Defaults, Isolation, and Subpixel Snapping
### search_known_solution Response
`search_known_solution` returned existing sample `sha256:c7071dcdb5556a42d993b28cdf9b1adba12d8ef2436ee1bdd1b9029e2acff699` ("require() an ESM-only npm package from CommonJS without ERR_REQUIRE_ESM or ERR_REQUIRE_ASYNC_MODULE", demonstrating dynamic `import()` workaround for top-level await in `p-limit` and `yoga-layout`).
### What a Model Would Have Written Instead
A model simulating CSS flexbox with `yoga-layout` assumes default nodes inherit standard web flexbox properties (`flexDirection: Row`, `flexShrink: 1`, `alignContent: Stretch`), or assumes that setting `config.setUseWebDefaults(true)` on the root container automatically propagates to child nodes added via `.insertChild()`.
### How the Wrong Version Fails
Fails silently with a green build: without `setUseWebDefaults(true)` explicitly passed to `Node.create(config)` for each child node, `flexShrink` remains `0` (React Native default) and child nodes do not shrink, overflowing parent container boundaries with zero runtime errors or warnings.
{"case":{"caseId":"case:sha256:15935269e55659f485f4181325dc64a6a56a158b53257b8c038ee0b12404f744","contract":["assert yoga-layout resolved version is 3.2.1","assert default Config has useWebDefaults disabled (false) and default Node uses React Native defaults (flexDirection Column, flexShrink 0, alignContent FlexStart)","assert Config with setUseWebDefaults(true) sets web defaults (flexDirection Row, flexShrink 1, alignContent Stretch)","assert child Node does not inherit Config from parent upon insertion and retains flexShrink 0 unless created with the Config","assert overflowing children in a fixed row fail to shrink under Yoga defaults (overflowing container to 300px width)","assert overflowing children in a fixed row shrink to fit (100px each, 200px total) when created with useWebDefaults Config","assert pointScaleFactor 1.0 rounds coordinates to integer pixel boundaries (10.6 to 11 and 10.4 to 10)","assert pointScaleFactor 0.0 disables pixel snapping and preserves exact subpixel floating point values","assert pointScaleFactor 2.0 snaps coordinates to half-pixel multiples (10.25 to 10.5 and 10.75 to 11.0)","assert freeing root node with freeRecursive releases entire tree and Config.free releases config allocation"],"goal":"Configure Yoga.Config with useWebDefaults and pointScaleFactor to apply CSS flexbox defaults and subpixel rounding across parent and child nodes","kind":"HOW","packages":["pkg:npm/yoga-layout@3.2.1"],"schemaVersion":1,"symbols":["Yoga.Config.create","Config.setUseWebDefaults","Config.setPointScaleFactor","Yoga.Node.create","Node.calculateLayout","Node.getComputedWidth","Node.getFlexShrink","Node.getFlexDirection","Node.insertChild","Node.freeRecursive","Config.free"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/yoga-layout@3.2.1"],"schemaVersion":1,"symbols":["Yoga.Config.create","Config.setUseWebDefaults","Config.setPointScaleFactor","Yoga.Node.create","Node.calculateLayout","Node.getComputedWidth","Node.getFlexShrink","Node.getFlexDirection","Node.insertChild","Node.freeRecursive","Config.free"],"verifierAdapter":"node-typescript@1"}
{
"name": "npm-yoga-layout-config",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "npm-yoga-layout-config",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"yoga-layout": "^3.2.1"
}
},
"node_modules/yoga-layout": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz",
"integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==",
"license": "MIT"
}
}
}
{
"name": "npm-yoga-layout-config",
"version": "1.0.0",
"private": true,
"type": "module",
"license": "MIT-0",
"dependencies": {
"yoga-layout": "3.2.1"
}
}
import Yoga, { Direction, FlexDirection, Align } from 'yoga-layout';
/**
* Creates a configured Yoga layout engine instance.
*
* In Yoga (React Native's flexbox engine), the default configuration disables
* standard W3C CSS web flexbox behavior (useWebDefaults is false):
* - flexDirection defaults to Column (instead of Row)
* - flexShrink defaults to 0 (items do NOT shrink when overflowing)
* - alignContent defaults to FlexStart (instead of Stretch)
*
* Additionally, child nodes do NOT inherit Config from parent nodes upon
* insertion; every node in the hierarchy must be instantiated with the Config
* (or manually configure its flexShrink/flexDirection).
*
* @param {object} [options]
* @param {boolean} [options.useWebDefaults=true] Whether to apply W3C CSS flexbox defaults.
* @param {number} [options.pointScaleFactor=1.0] Point scale factor for pixel snapping (0.0 disables snapping).
* @returns {{ config: import('yoga-layout').Config, createNode: () => import('yoga-layout').Node, free: () => void }}
*/
export function createLayoutEngine({ useWebDefaults = true, pointScaleFactor = 1.0 } = {}) {
const config = Yoga.Config.create();
if (useWebDefaults) {
config.setUseWebDefaults(true);
}
if (pointScaleFactor !== undefined) {
config.setPointScaleFactor(pointScaleFactor);
}
return {
config,
createNode: () => Yoga.Node.create(config),
free: () => config.free(),
};
}
/**
* Computes layout for a set of items placed in a row container.
*
* @param {Array<{ width: number, height: number }>} items
* @param {number} containerWidth
* @param {number} containerHeight
* @param {object} [options]
* @param {boolean} [options.useWebDefaults=true]
* @param {number} [options.pointScaleFactor=1.0]
* @returns {Array<{ left: number, top: number, width: number, height: number }>}
*/
export function computeRowLayout(items, containerWidth, containerHeight, options = {}) {
const engine = createLayoutEngine(options);
const root = engine.createNode();
root.setWidth(containerWidth);
root.setHeight(containerHeight);
root.setFlexDirection(FlexDirection.Row);
const childNodes = items.map((item, idx) => {
const child = engine.createNode();
child.setWidth(item.width);
child.setHeight(item.height);
root.insertChild(child, idx);
return child;
});
root.calculateLayout(containerWidth, containerHeight, Direction.LTR);
const layouts = childNodes.map((child) => {
const layout = child.getComputedLayout();
return {
left: layout.left,
top: layout.top,
width: layout.width,
height: layout.height,
};
});
root.freeRecursive();
engine.free();
return layouts;
}
import assert from 'node:assert/strict';
import fs from 'node:fs';
import Yoga, { Direction, FlexDirection, Align, BoxSizing } from 'yoga-layout';
import { createLayoutEngine, computeRowLayout } from '../src/index.js';
// ---------------------------------------------------------------------------
// 1. Verify exact resolved package version
// ---------------------------------------------------------------------------
const pkgPath = new URL('../node_modules/yoga-layout/package.json', import.meta.url);
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
assert.equal(pkg.version, '3.2.1', 'Expected yoga-layout resolved version 3.2.1');
// ---------------------------------------------------------------------------
// 2. Default Config vs Web Defaults Config
// ---------------------------------------------------------------------------
const defaultConfig = Yoga.Config.create();
assert.equal(
defaultConfig.useWebDefaults(),
false,
'Default Config must have useWebDefaults disabled (React Native semantics)'
);
const webConfig = Yoga.Config.create();
webConfig.setUseWebDefaults(true);
assert.equal(
webConfig.useWebDefaults(),
true,
'Config with setUseWebDefaults(true) must report useWebDefaults enabled'
);
// ---------------------------------------------------------------------------
// 3. Node property defaults under Default Config vs Web Config
// ---------------------------------------------------------------------------
const defaultNode = Yoga.Node.create(defaultConfig);
assert.equal(
defaultNode.getFlexDirection(),
FlexDirection.Column,
'Default Node flexDirection must be Column (React Native default), not Row'
);
assert.equal(
defaultNode.getFlexShrink(),
0,
'Default Node flexShrink must be 0 (no shrink), not CSS default 1'
);
assert.equal(
defaultNode.getAlignContent(),
Align.FlexStart,
'Default Node alignContent must be FlexStart, not CSS default Stretch'
);
const webNode = Yoga.Node.create(webConfig);
assert.equal(
webNode.getFlexDirection(),
FlexDirection.Row,
'Web Node flexDirection must be Row (CSS Flexbox standard)'
);
assert.equal(
webNode.getFlexShrink(),
1,
'Web Node flexShrink must be 1 (CSS Flexbox standard)'
);
assert.equal(
webNode.getAlignContent(),
Align.Stretch,
'Web Node alignContent must be Stretch (CSS Flexbox standard)'
);
// ---------------------------------------------------------------------------
// 4. Config is NOT inherited by child nodes upon insertion
// ---------------------------------------------------------------------------
const parentWeb = Yoga.Node.create(webConfig);
const childDefault = Yoga.Node.create(); // Created without webConfig
assert.equal(childDefault.getFlexShrink(), 0, 'Child created with Node.create() has default flexShrink 0');
parentWeb.insertChild(childDefault, 0);
assert.equal(
childDefault.getFlexShrink(),
0,
'Child node must NOT inherit Config from parent upon insertion'
);
// ---------------------------------------------------------------------------
// 5. Silent layout failure: Contained row overflowing vs shrinking
// ---------------------------------------------------------------------------
// A. Default / Naive behavior: Two 150px children in a 200px row container
const rootDefault = Yoga.Node.create(defaultConfig);
rootDefault.setWidth(200);
rootDefault.setHeight(50);
rootDefault.setFlexDirection(FlexDirection.Row);
const itemDef1 = Yoga.Node.create(defaultConfig);
itemDef1.setWidth(150);
itemDef1.setHeight(50);
const itemDef2 = Yoga.Node.create(defaultConfig);
itemDef2.setWidth(150);
itemDef2.setHeight(50);
rootDefault.insertChild(itemDef1, 0);
rootDefault.insertChild(itemDef2, 1);
rootDefault.calculateLayout(200, 50, Direction.LTR);
assert.equal(itemDef1.getComputedWidth(), 150, 'Without useWebDefaults, item 1 fails to shrink');
assert.equal(itemDef2.getComputedWidth(), 150, 'Without useWebDefaults, item 2 fails to shrink');
assert.equal(
itemDef1.getComputedWidth() + itemDef2.getComputedWidth(),
300,
'Combined width silently overflows 200px container to 300px without error'
);
// B. Web Defaults behavior: Two 150px children shrink equally to 100px each
const rootWeb = Yoga.Node.create(webConfig);
rootWeb.setWidth(200);
rootWeb.setHeight(50);
const itemWeb1 = Yoga.Node.create(webConfig);
itemWeb1.setWidth(150);
itemWeb1.setHeight(50);
const itemWeb2 = Yoga.Node.create(webConfig);
itemWeb2.setWidth(150);
itemWeb2.setHeight(50);
rootWeb.insertChild(itemWeb1, 0);
rootWeb.insertChild(itemWeb2, 1);
rootWeb.calculateLayout(200, 50, Direction.LTR);
assert.equal(itemWeb1.getComputedWidth(), 100, 'With useWebDefaults, item 1 shrinks to 100px');
assert.equal(itemWeb2.getComputedWidth(), 100, 'With useWebDefaults, item 2 shrinks to 100px');
assert.equal(
itemWeb1.getComputedWidth() + itemWeb2.getComputedWidth(),
200,
'Combined width exactly matches 200px container width'
);
// ---------------------------------------------------------------------------
// 6. PointScaleFactor pixel rounding / subpixel behavior
// ---------------------------------------------------------------------------
// A. pointScaleFactor 1.0 (default integer pixel snapping)
const configPixelSnap = Yoga.Config.create();
configPixelSnap.setPointScaleFactor(1.0);
const nodePixelSnap = Yoga.Node.create(configPixelSnap);
nodePixelSnap.setWidth(10.6);
nodePixelSnap.setHeight(10.4);
nodePixelSnap.calculateLayout(undefined, undefined, Direction.LTR);
assert.equal(nodePixelSnap.getComputedWidth(), 11, 'pointScaleFactor 1.0 snaps 10.6 up to 11');
assert.equal(nodePixelSnap.getComputedHeight(), 10, 'pointScaleFactor 1.0 snaps 10.4 down to 10');
// B. pointScaleFactor 0.0 (disabled pixel snapping, raw subpixels)
const configSubpixel = Yoga.Config.create();
configSubpixel.setPointScaleFactor(0.0);
const nodeSubpixel = Yoga.Node.create(configSubpixel);
nodeSubpixel.setWidth(10.6);
nodeSubpixel.setHeight(10.4);
nodeSubpixel.calculateLayout(undefined, undefined, Direction.LTR);
assert.ok(
Math.abs(nodeSubpixel.getComputedWidth() - 10.6) < 0.001,
'pointScaleFactor 0.0 preserves fractional subpixel width (10.6)'
);
assert.ok(
Math.abs(nodeSubpixel.getComputedHeight() - 10.4) < 0.001,
'pointScaleFactor 0.0 preserves fractional subpixel height (10.4)'
);
// C. pointScaleFactor 2.0 (Retina 2x, half-pixel snapping)
const configRetina = Yoga.Config.create();
configRetina.setPointScaleFactor(2.0);
const nodeRetina = Yoga.Node.create(configRetina);
nodeRetina.setWidth(10.25);
nodeRetina.setHeight(10.75);
nodeRetina.calculateLayout(undefined, undefined, Direction.LTR);
assert.equal(nodeRetina.getComputedWidth(), 10.5, 'pointScaleFactor 2.0 snaps 10.25 to 10.5');
assert.equal(nodeRetina.getComputedHeight(), 11, 'pointScaleFactor 2.0 snaps 10.75 to 11.0');
// ---------------------------------------------------------------------------
// 7. Verify computeRowLayout helper function from src/index.js
// ---------------------------------------------------------------------------
const helperWebResults = computeRowLayout(
[{ width: 150, height: 50 }, { width: 150, height: 50 }],
200,
50,
{ useWebDefaults: true }
);
assert.deepEqual(
helperWebResults,
[
{ left: 0, top: 0, width: 100, height: 50 },
{ left: 100, top: 0, width: 100, height: 50 },
],
'computeRowLayout with useWebDefaults shrinks items to fit container'
);
const helperDefaultResults = computeRowLayout(
[{ width: 150, height: 50 }, { width: 150, height: 50 }],
200,
50,
{ useWebDefaults: false }
);
assert.deepEqual(
helperDefaultResults,
[
{ left: 0, top: 0, width: 150, height: 50 },
{ left: 150, top: 0, width: 150, height: 50 },
],
'computeRowLayout with useWebDefaults false maintains un-shrunk overflowing items'
);
// ---------------------------------------------------------------------------
// 8. Clean up WASM allocations
// ---------------------------------------------------------------------------
defaultNode.free();
webNode.free();
parentWeb.freeRecursive();
rootDefault.freeRecursive();
rootWeb.freeRecursive();
nodePixelSnap.free();
nodeSubpixel.free();
nodeRetina.free();
defaultConfig.free();
webConfig.free();
configPixelSnap.free();
configSubpixel.free();
configRetina.free();
console.log('Contract passed: Yoga.Config settings (useWebDefaults, config isolation, pointScaleFactor) verified.');