diff --git a/packages/uikit/package.json b/packages/uikit/package.json index 26f28618..b2143e5e 100644 --- a/packages/uikit/package.json +++ b/packages/uikit/package.json @@ -32,9 +32,9 @@ "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", + "check:prettier": "prettier --check src scripts tests", "check:eslint": "eslint 'src/**/*.{tsx,ts}'", - "fix:prettier": "prettier --write src", + "fix:prettier": "prettier --write src scripts tests", "fix:eslint": "eslint 'src/**/*.{tsx,ts}' --fix" }, "peerDependencies": { diff --git a/packages/uikit/scripts/flex-generate-setter.ts b/packages/uikit/scripts/flex-generate-setter.ts index 580db6f7..c857c1a2 100644 --- a/packages/uikit/scripts/flex-generate-setter.ts +++ b/packages/uikit/scripts/flex-generate-setter.ts @@ -1,4 +1,4 @@ -import { writeFileSync } from "fs"; +import { writeFileSync } from 'fs' import { EDGE_BOTTOM, EDGE_LEFT, @@ -9,191 +9,172 @@ import { 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"; +} from 'yoga-wasm-web' +import { GUTTER_ROW, GUTTER_COLUMN } from 'yoga-wasm-web' +import { loadYogaBase64 } from '../src/flex/load-base64.js' async function main() { - const yoga = await loadYogaBase64(); - const node = yoga.Node.create(); + const yoga = await loadYogaBase64() + const node = yoga.Node.create() - const propertiesWithEdge = new Set(["border", "padding", "margin", "position"]); - const propertiesWithGutter = new Set(["gap"]); - const propertiesWithoutPointUnit = new Set(["aspectRatio", "flexGrow", "flexShrink"]); + const propertiesWithEdge = new Set(['border', 'padding', 'margin', 'position']) + const propertiesWithGutter = new Set(['gap']) + const propertiesWithoutPointUnit = new Set(['aspectRatio', 'flexGrow', 'flexShrink']) const enumsToPrefix: { [key in string]: string } = { - alignContent: "ALIGN_", - alignItems: "ALIGN_", - alignSelf: "ALIGN_", - display: "DISPLAY_", - flexDirection: "FLEX_DIRECTION_", - flexWrap: "WRAP_", - justifyContent: "JUSTIFY_", - overflow: "OVERFLOW_", - positionType: "POSITION_TYPE_", - }; + alignContent: 'ALIGN_', + alignItems: 'ALIGN_', + alignSelf: 'ALIGN_', + display: 'DISPLAY_', + flexDirection: 'FLEX_DIRECTION_', + flexWrap: 'WRAP_', + justifyContent: 'JUSTIFY_', + overflow: 'OVERFLOW_', + positionType: 'POSITION_TYPE_', + } const edgeMap = { Top: EDGE_TOP, Left: EDGE_LEFT, Right: EDGE_RIGHT, Bottom: EDGE_BOTTOM, - }; + } const gutterMap = { Row: GUTTER_ROW, Column: GUTTER_COLUMN, - }; - const yogaKeys = Object.entries(yoga); + } + const yogaKeys = Object.entries(yoga) const kebabCaseFromSnakeCase = (str: string) => - str.toLowerCase().replace(/_[a-z]/g, (letter) => `-${letter.slice(1)}`); + str.toLowerCase().replace(/_[a-z]/g, (letter) => `-${letter.slice(1)}`) - const nodeKeys = Object.keys(Object.getPrototypeOf(node)); + const nodeKeys = Object.keys(Object.getPrototypeOf(node)) const properties = nodeKeys .filter( (keyName) => - keyName.startsWith("get") && - !keyName.includes("Child") && - !keyName.includes("Parent") && - !keyName.startsWith("getComputed"), + keyName.startsWith('get') && + !keyName.includes('Child') && + !keyName.includes('Parent') && + !keyName.startsWith('getComputed'), ) .map<[string, string]>((fnName) => { - const baseFnName = fnName.slice("get".length); - const propertyName = `${baseFnName.charAt(0).toLowerCase()}${baseFnName.slice(1)}`; - return [propertyName, baseFnName]; - }); - const lookupTables = new Map(); - const importedTypesFromYoga = new Set(); - const setterFunctions: Array<[string, string]> = []; + const baseFnName = fnName.slice('get'.length) + const propertyName = `${baseFnName.charAt(0).toLowerCase()}${baseFnName.slice(1)}` + return [propertyName, baseFnName] + }) + const lookupTables = new Map() + const importedTypesFromYoga = new Set() + const setterFunctions: Array<[string, string]> = [] for (const [propertyName, functionName] of properties) { - const enumPrefix = enumsToPrefix[propertyName]; - let convertFunction: ( - defaultValue: string | number | null, - setter: (value?: string) => string, - ) => string; - let types: Array; + const enumPrefix = enumsToPrefix[propertyName] + let convertFunction: (defaultValue: string | number | null, setter: (value?: string) => string) => string + let types: Array if (enumPrefix != null) { - const enums = yogaKeys.filter(([key]) => key.startsWith(enumPrefix)); - const lutName = `${enumPrefix}LUT`; + const enums = yogaKeys.filter(([key]) => key.startsWith(enumPrefix)) + const lutName = `${enumPrefix}LUT` if (!lookupTables.has(lutName)) { lookupTables.set( lutName, createLookupTable( lutName, - enums.map(([name, value]) => [ - kebabCaseFromSnakeCase(name.slice(enumPrefix.length)), - value as any, - name, - ]), + enums.map(([name, value]) => [kebabCaseFromSnakeCase(name.slice(enumPrefix.length)), value as any, name]), importedTypesFromYoga, ), - ); + ) } convertFunction = (defaultValue, setter) => { const enumType = enumPrefix .slice(0, -1) - .split("_") + .split('_') .map((split) => split[0] + split.slice(1).toLowerCase()) - .join(""); - importedTypesFromYoga.add(enumType); + .join('') + importedTypesFromYoga.add(enumType) return setter( `convertEnum(${lutName}, input, ${ - defaultValue === null || isNaN(defaultValue as any) - ? "NaN" - : JSON.stringify(defaultValue) + defaultValue === null || isNaN(defaultValue as any) ? 'NaN' : JSON.stringify(defaultValue) } as ${enumType})`, - ); - }; - types = [ - ...enums.map(([name]) => `"${kebabCaseFromSnakeCase(name.slice(enumPrefix.length))}"`), - "undefined", - ]; + ) + } + types = [...enums.map(([name]) => `"${kebabCaseFromSnakeCase(name.slice(enumPrefix.length))}"`), 'undefined'] } else { - const percentUnit = node[`set${functionName}Percent` as keyof Node] != null; - const autoUnit = node[`set${functionName}Auto` as keyof Node] != null; - const pointUnit = !propertiesWithoutPointUnit.has(propertyName); - types = ["undefined", "number"]; + const percentUnit = node[`set${functionName}Percent` as keyof Node] != null + const autoUnit = node[`set${functionName}Auto` as keyof Node] != null + const pointUnit = !propertiesWithoutPointUnit.has(propertyName) + types = ['undefined', 'number'] if (percentUnit) { - types.push("`${number}%`"); + types.push('`${number}%`') } if (autoUnit) { - types.push(`"auto"`); + types.push(`"auto"`) } convertFunction = (defaultValue, setter) => { const defaultValueString = - defaultValue === null || isNaN(defaultValue as any) - ? "NaN" - : JSON.stringify(defaultValue); + defaultValue === null || isNaN(defaultValue as any) ? 'NaN' : JSON.stringify(defaultValue) return setter( pointUnit - ? `convertPoint(input, precision, ${defaultValueString})${ - propertyName === "margin" ? " as number" : "" - }` + ? `convertPoint(input, precision, ${defaultValueString})${propertyName === 'margin' ? ' as number' : ''}` : `input ?? ${defaultValueString}`, - ); - }; + ) + } } if (propertiesWithEdge.has(propertyName)) { 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 defaultValue = fromYoga(propertyName, node[`get${functionName}` as 'getBorder'](edge)) + const edgePropertyName = `${propertyName}${edgeKey}` + const edgeType = `EDGE_${edgeKey.toUpperCase()}` + importedTypesFromYoga.add(edgeType) setterFunctions.push([ edgePropertyName, - `(node: Node, precision: number, input: ${types.join(" | ")}) => + `(node: Node, precision: number, input: ${types.join(' | ')}) => ${convertFunction( defaultValue, (value) => ` node.set${functionName}(${edge} as ${edgeType}, ${value})`, )}`, - ]); + ]) } } else if (propertiesWithGutter.has(propertyName)) { 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 defaultValue = fromYoga(propertyName, node[`get${functionName}` as 'getGap'](gutter)) + const gutterPropertyName = `${propertyName}${gutterKey}` + const gutterType = `GUTTER_${gutterKey.toUpperCase()}` + importedTypesFromYoga.add(gutterType) setterFunctions.push([ gutterPropertyName, - `(node: Node, precision: number, input: ${types.join(" | ")}) => + `(node: Node, precision: number, input: ${types.join(' | ')}) => ${convertFunction( defaultValue, (value) => ` node.set${functionName}(${gutter} as ${gutterType}, ${value})`, )}`, - ]); + ]) } } else { - const defaultValue = fromYoga(propertyName, node[`get${functionName}` as "getWidth"]()); + const defaultValue = fromYoga(propertyName, node[`get${functionName}` as 'getWidth']()) setterFunctions.push([ propertyName, - `(node: Node, precision: number, input: ${types.join(" | ")}) => + `(node: Node, precision: number, input: ${types.join(' | ')}) => ${convertFunction( defaultValue, (value) => ` node.set${functionName}(${value})`, )}`, - ]); + ]) } } writeFileSync( - "src/flex/setter.ts", + 'src/flex/setter.ts', `import { Node } from "yoga-wasm-web" - import type { ${Array.from(importedTypesFromYoga).join(", ")} } from "yoga-wasm-web" + import type { ${Array.from(importedTypesFromYoga).join(', ')} } from "yoga-wasm-web" function convertEnum(lut: T, input: keyof T | undefined, defaultValue: T[keyof T]): T[keyof T] { if(input == null) { return defaultValue } const resolvedValue = lut[input] if(resolvedValue == null) { - throw new Error(\`unexpected value ${"${input as string}"}, expected ${'${Object.keys(lut).join(", ")}'}\`) + throw new Error(\`unexpected value ${'${input as string}'}, expected ${'${Object.keys(lut).join(", ")}'}\`) } return resolvedValue } @@ -203,11 +184,11 @@ async function main() { } return input ?? defaultValue } - ${Array.from(lookupTables.values()).join("\n")} + ${Array.from(lookupTables.values()).join('\n')} export const setter = { ${setterFunctions .map(([propertyName, functionCode]) => `${propertyName}: ${functionCode}`) - .join(",\n")} }`, - ); + .join(',\n')} }`, + ) } function createLookupTable( @@ -218,30 +199,30 @@ function createLookupTable( return `const ${name} = { ${values .map(([key, value, type]) => { - importedTypesFromYoga.add(type); - return `"${key}": ${value} as ${type}`; + importedTypesFromYoga.add(type) + return `"${key}": ${value} as ${type}` }) - .join(",\n")} - } as const`; + .join(',\n')} + } as const` } -function fromYoga(name: string, value: any): "auto" | `${number}%` | number | null { - if (typeof value === "object") { +function fromYoga(name: string, value: any): 'auto' | `${number}%` | number | null { + if (typeof value === 'object') { switch (value.unit) { case UNIT_AUTO: - return "auto"; + return 'auto' case UNIT_PERCENT: - return `${value.value}%`; + return `${value.value}%` case UNIT_POINT: - return value.value ?? null; + return value.value ?? null case UNIT_UNDEFINED: - return null; + return null } } - if (typeof value === "number") { - return value; + if (typeof value === 'number') { + return value } - throw `can't convert value "${JSON.stringify(value)}" for property "${name}" from yoga`; + throw `can't convert value "${JSON.stringify(value)}" for property "${name}" from yoga` } -main().catch(console.error); +main().catch(console.error) diff --git a/packages/uikit/tests/clipping.spec.ts b/packages/uikit/tests/clipping.spec.ts index d643498a..feb83c59 100644 --- a/packages/uikit/tests/clipping.spec.ts +++ b/packages/uikit/tests/clipping.spec.ts @@ -1,13 +1,8 @@ -import { Matrix4, Vector3 } from "three"; -import { ClippingRect } from "../src/clipping.js"; -import { expect } from "chai"; +import { Matrix4, Vector3 } from 'three' +import { ClippingRect } from '../src/clipping.js' +import { expect } from 'chai' -const defaultPlaneNormals = [ - new Vector3(0, 1, 0), - new Vector3(1, 0, 0), - new Vector3(0, -1, 0), - new Vector3(-1, 0, 0), -]; +const defaultPlaneNormals = [new Vector3(0, 1, 0), new Vector3(1, 0, 0), new Vector3(0, -1, 0), new Vector3(-1, 0, 0)] function expectClippingCenterAndSize( clippingRect: ClippingRect, @@ -17,46 +12,46 @@ function expectClippingCenterAndSize( height: number, ): void { for (let i = 0; i < 4; i++) { - expect(clippingRect.planes[i].normal.distanceTo(defaultPlaneNormals[i])).to.be.lessThan(0.01); + expect(clippingRect.planes[i].normal.distanceTo(defaultPlaneNormals[i])).to.be.lessThan(0.01) } - const minY = -clippingRect.planes[0].constant; - const minX = -clippingRect.planes[1].constant; - const maxY = clippingRect.planes[2].constant; - const maxX = clippingRect.planes[3].constant; - const actualCenterX = (maxX + minX) * 0.5; - const actualCenterY = (maxY + minY) * 0.5; - const actualWidth = maxX - minX; - const actualHeight = maxY - minY; - expect(actualCenterX).to.be.closeTo(centerX, 0.01); - expect(actualCenterY).to.be.closeTo(centerY, 0.01); - expect(actualWidth).to.be.closeTo(width, 0.01); - expect(actualHeight).to.be.closeTo(height, 0.01); + const minY = -clippingRect.planes[0].constant + const minX = -clippingRect.planes[1].constant + const maxY = clippingRect.planes[2].constant + const maxX = clippingRect.planes[3].constant + const actualCenterX = (maxX + minX) * 0.5 + const actualCenterY = (maxY + minY) * 0.5 + const actualWidth = maxX - minX + const actualHeight = maxY - minY + expect(actualCenterX).to.be.closeTo(centerX, 0.01) + expect(actualCenterY).to.be.closeTo(centerY, 0.01) + expect(actualWidth).to.be.closeTo(width, 0.01) + expect(actualHeight).to.be.closeTo(height, 0.01) } -describe("clipping", () => { - it("should setup planes", () => { - const rect1 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(44, 55, 0)), 10, 22); - expectClippingCenterAndSize(rect1, 44, 55, 10, 22); - }); +describe('clipping', () => { + it('should setup planes', () => { + const rect1 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(44, 55, 0)), 10, 22) + expectClippingCenterAndSize(rect1, 44, 55, 10, 22) + }) - it("should intersect of 2 translated clips", () => { - const rect1 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(0, 0, 0)), 2, 1); - const rect2 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(0.5, -1, 0)), 1, 2); - rect1.min(rect2); - expectClippingCenterAndSize(rect1, 0.5, -0.25, 1, 0.5); - }); + it('should intersect of 2 translated clips', () => { + const rect1 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(0, 0, 0)), 2, 1) + const rect2 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(0.5, -1, 0)), 1, 2) + rect1.min(rect2) + expectClippingCenterAndSize(rect1, 0.5, -0.25, 1, 0.5) + }) - it("should intersect of 2 translated clips (inverted min call)", () => { - const rect1 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(0, 0, 0)), 2, 1); - const rect2 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(0.5, -1, 0)), 1, 2); - rect2.min(rect1); - expectClippingCenterAndSize(rect2, 0.5, -0.25, 1, 0.5); - }); + it('should intersect of 2 translated clips (inverted min call)', () => { + const rect1 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(0, 0, 0)), 2, 1) + const rect2 = new ClippingRect(new Matrix4().makeTranslation(new Vector3(0.5, -1, 0)), 1, 2) + rect2.min(rect1) + expectClippingCenterAndSize(rect2, 0.5, -0.25, 1, 0.5) + }) - it("should intersect intersect clip with clip rotated on x-axis", () => { - const rect1 = new ClippingRect(new Matrix4(), 1, 1); - const rect2 = new ClippingRect(new Matrix4().makeRotationY((65 / 180) * Math.PI), 0.5, 1); - rect1.min(rect2); - expectClippingCenterAndSize(rect1, 0, 0, 1, 1); - }); -}); + it('should intersect intersect clip with clip rotated on x-axis', () => { + const rect1 = new ClippingRect(new Matrix4(), 1, 1) + const rect2 = new ClippingRect(new Matrix4().makeRotationY((65 / 180) * Math.PI), 0.5, 1) + rect1.min(rect2) + expectClippingCenterAndSize(rect1, 0, 0, 1, 1) + }) +}) diff --git a/packages/uikit/tests/flex.spec.ts b/packages/uikit/tests/flex.spec.ts index ecc5030c..8886b807 100644 --- a/packages/uikit/tests/flex.spec.ts +++ b/packages/uikit/tests/flex.spec.ts @@ -1,4 +1,4 @@ -import { expect } from "chai"; +import { expect } from 'chai' import { ALIGN_CENTER, ALIGN_FLEX_END, @@ -16,34 +16,28 @@ import { UNIT_POINT, WRAP_WRAP_REVERSE, Yoga, -} from "yoga-wasm-web"; -import { EDGE_TOP } from "yoga-wasm-web"; -import { - FlexNode, - YogaProperties, - loadYogaBase64, - setMeasureFunc, - setter, -} from "../src/flex/index.js"; -import { signal } from "@preact/signals-core"; +} from 'yoga-wasm-web' +import { EDGE_TOP } from 'yoga-wasm-web' +import { FlexNode, YogaProperties, loadYogaBase64, setMeasureFunc, setter } from '../src/flex/index.js' +import { signal } from '@preact/signals-core' const testValues: YogaProperties = { - alignContent: "center", - alignItems: "flex-end", - alignSelf: "space-around", + alignContent: 'center', + alignItems: 'flex-end', + alignSelf: 'space-around', aspectRatio: 2, borderBottom: 3, borderLeft: 4, borderRight: 5, borderTop: 6, - display: "none", + display: 'none', flexBasis: 7, - flexDirection: "row-reverse", + flexDirection: 'row-reverse', flexGrow: 8, flexShrink: 9, - flexWrap: "wrap-reverse", + flexWrap: 'wrap-reverse', height: 10, - justifyContent: "space-evenly", + justifyContent: 'space-evenly', marginBottom: 11, marginLeft: 12, marginRight: 13, @@ -52,7 +46,7 @@ const testValues: YogaProperties = { maxWidth: 16, minHeight: 17, minWidth: 18, - overflow: "scroll", + overflow: 'scroll', paddingBottom: 19, paddingLeft: 20, paddingRight: 21, @@ -61,9 +55,9 @@ const testValues: YogaProperties = { positionLeft: 24, positionRight: 25, positionTop: 26, - positionType: "absolute", - width: "50%", -}; + positionType: 'absolute', + width: '50%', +} export const rawTestValues = { alignContent: ALIGN_CENTER, @@ -101,237 +95,239 @@ export const rawTestValues = { positionTop: 26, positionType: POSITION_TYPE_ABSOLUTE, width: 50, //50% -}; +} -const properties = Object.keys(testValues) as Array; +const properties = Object.keys(testValues) as Array -const propertiesWithEdge = ["border", "padding", "margin", "position"] as const; +const propertiesWithEdge = ['border', 'padding', 'margin', 'position'] as const function capitalize(value: string): string { - return value.charAt(0).toUpperCase() + value.slice(1); + return value.charAt(0).toUpperCase() + value.slice(1) } function getRawValue(property: string, node: Node): any { for (const propertyWithEdge of propertiesWithEdge) { if (property.startsWith(propertyWithEdge)) { - if (property.endsWith("Top")) { - return flatten(node[`get${capitalize(property.slice(0, -3))}` as "getBorder"](EDGE_TOP)); + if (property.endsWith('Top')) { + return flatten(node[`get${capitalize(property.slice(0, -3))}` as 'getBorder'](EDGE_TOP)) } - if (property.endsWith("Bottom")) { - return flatten(node[`get${capitalize(property.slice(0, -6))}` as "getBorder"](EDGE_BOTTOM)); + if (property.endsWith('Bottom')) { + return flatten(node[`get${capitalize(property.slice(0, -6))}` as 'getBorder'](EDGE_BOTTOM)) } - if (property.endsWith("Right")) { - return flatten(node[`get${capitalize(property.slice(0, -5))}` as "getBorder"](EDGE_RIGHT)); + if (property.endsWith('Right')) { + return flatten(node[`get${capitalize(property.slice(0, -5))}` as 'getBorder'](EDGE_RIGHT)) } - if (property.endsWith("Left")) { - return flatten(node[`get${capitalize(property.slice(0, -4))}` as "getBorder"](EDGE_LEFT)); + if (property.endsWith('Left')) { + return flatten(node[`get${capitalize(property.slice(0, -4))}` as 'getBorder'](EDGE_LEFT)) } } } - return flatten(node[`get${capitalize(property)}` as "getWidth"]()); + return flatten(node[`get${capitalize(property)}` as 'getWidth']()) } -describe("set & get properties", () => { - let yoga: any; - let node: Node; +describe('set & get properties', () => { + let yoga: any + let node: Node - const rawValues: any = {}; + const rawValues: any = {} before(async () => { - yoga = await loadYogaBase64().catch(console.error); - node = yoga.Node.create(); - }); + yoga = await loadYogaBase64().catch(console.error) + node = yoga.Node.create() + }) - it("it should throw an error", () => { - expect( - () => setter.alignItems(node, 1, "centerx" as any), - "assign alignItems a unknown value", - ).to.throw( + it('it should throw an error', () => { + expect(() => setter.alignItems(node, 1, 'centerx' as any), 'assign alignItems a unknown value').to.throw( `unexpected value centerx, expected auto, flex-start, center, flex-end, stretch, baseline, space-between, space-around`, - ); + ) - expect( - () => setter.alignItems(node, 1, 1 as any), - "assign alignItems a wrong value type", - ).to.throw( + expect(() => setter.alignItems(node, 1, 1 as any), 'assign alignItems a wrong value type').to.throw( `unexpected value 1, expected auto, flex-start, center, flex-end, stretch, baseline, space-between, space-around`, - ); - }); + ) + }) - it("should get raw vaues", () => { + it('should get raw vaues', () => { properties.forEach((property) => { - rawValues[property] = getRawValue(property, node); - }); - }); + rawValues[property] = getRawValue(property, node) + }) + }) - it("it should set new values", () => { - (Object.entries(testValues) as Array<[keyof YogaProperties, any]>).forEach(([name, value]) => + it('it should set new values', () => { + ;(Object.entries(testValues) as Array<[keyof YogaProperties, any]>).forEach(([name, value]) => setter[name](node, 1, value), - ); + ) properties.forEach((property) => expect(getRawValue(property, node), `compare ${property} to expected value`).to.equal( rawTestValues[property as any as keyof typeof rawTestValues], ), - ); - }); + ) + }) - it("it should reset all values", () => { - (Object.keys(testValues) as Array).forEach((name) => - setter[name](node, 1, undefined), - ); + it('it should reset all values', () => { + ;(Object.keys(testValues) as Array).forEach((name) => setter[name](node, 1, undefined)) properties.forEach((property) => { - expect( - equal(getRawValue(property, node), rawValues[property]), - `compare ${property} to the default value`, - ).to.be.true; - }); - }); + expect(equal(getRawValue(property, node), rawValues[property]), `compare ${property} to the default value`).to.be + .true + }) + }) - it("it should set value with and without precision", () => { - setter.width(node, 0.01, 1); + it('it should set value with and without precision', () => { + setter.width(node, 0.01, 1) expect(node.getWidth()).to.deep.equal({ unit: UNIT_POINT, value: 100, - }); - setter.width(node, 0.01, "50%"); + }) + setter.width(node, 0.01, '50%') expect(node.getWidth()).to.deep.equal({ unit: UNIT_PERCENT, value: 50, - }); - }); + }) + }) - it("it should set and unset measure func", () => { + it('it should set and unset measure func', () => { expect(() => { - setMeasureFunc(node, 0.01, () => ({ width: 0, height: 0 })); - node.unsetMeasureFunc(); - }).to.not.throw(); - }); -}); + setMeasureFunc(node, 0.01, () => ({ width: 0, height: 0 })) + node.unsetMeasureFunc() + }).to.not.throw() + }) +}) -describe("flex node", () => { - let yoga: any; - let parent: FlexNode; - let child1: FlexNode; - let child2: FlexNode; +describe('flex node', () => { + let yoga: any + let parent: FlexNode + let child1: FlexNode + let child2: FlexNode before(async () => { - yoga = await loadYogaBase64(); - parent = new FlexNode(signal(yoga), 0.01, 1, () => {}); - child1 = parent.createChild(); - child2 = parent.createChild(); - }); + yoga = await loadYogaBase64() + parent = new FlexNode(signal(yoga), 0.01, 1, () => {}) + child1 = parent.createChild() + child2 = parent.createChild() + }) - it("should receive yoga instance after setting up", () => { - const yogaSignal = signal(undefined); - const parent = new FlexNode(yogaSignal, 0.01, 1, () => {}); - const child1 = parent.createChild(); - const child2 = parent.createChild(); - child1.nextProperties.flexGrow = 0; - child1.finalizeProperties(); - child1.nextProperties.flexGrow = 1; - child1.finalizeProperties(); - child2.nextProperties.flexGrow = 1; - child2.finalizeProperties(); - parent.nextProperties.height = 1; - parent.finalizeProperties(); - expect(child1.outerBounds.value, "child 1 top").to.deep.equal([[0, 0], [0, 0]]); - expect(child2.outerBounds.value, "child 2 top").to.deep.equal([[0, 0], [0, 0]]); - yogaSignal.value = yoga; - parent.calculateLayout(); - expect(child1.outerBounds.value, "child 1 top").to.deep.equal([[0, 0.25], [0, 0.5]]); - expect(child2.outerBounds.value, "child 2 top").to.deep.equal([[0, -0.25], [0, 0.5]]); - }); + it('should receive yoga instance after setting up', () => { + const yogaSignal = signal(undefined) + const parent = new FlexNode(yogaSignal, 0.01, 1, () => {}) + const child1 = parent.createChild() + const child2 = parent.createChild() + child1.nextProperties.flexGrow = 0 + child1.finalizeProperties() + child1.nextProperties.flexGrow = 1 + child1.finalizeProperties() + child2.nextProperties.flexGrow = 1 + child2.finalizeProperties() + parent.nextProperties.height = 1 + parent.finalizeProperties() + expect(child1.outerBounds.value, 'child 1 top').to.deep.equal([ + [0, 0], + [0, 0], + ]) + expect(child2.outerBounds.value, 'child 2 top').to.deep.equal([ + [0, 0], + [0, 0], + ]) + yogaSignal.value = yoga + parent.calculateLayout() + expect(child1.outerBounds.value, 'child 1 top').to.deep.equal([ + [0, 0.25], + [0, 0.5], + ]) + expect(child2.outerBounds.value, 'child 2 top').to.deep.equal([ + [0, -0.25], + [0, 0.5], + ]) + }) - it("should add children in order", () => { - child1.nextProperties.flexGrow = 1; - child1.finalizeProperties(); - child2.nextProperties.flexGrow = 1; - child2.finalizeProperties(); - parent.nextProperties.height = 1; - parent.finalizeProperties(); - parent.calculateLayout(); - expect(child1.outerBounds.value[0][1], "child 1 top").to.equal(0); - expect(child1.outerBounds.value[1][1], "child 1 height").to.equal(0.5); - expect(child2.outerBounds.value[0][1], "child 2 top").to.equal(0.5); - expect(child2.outerBounds.value[1][1], "child 2 height").to.equal(0.5); - }); + it('should add children in order', () => { + child1.nextProperties.flexGrow = 1 + child1.finalizeProperties() + child2.nextProperties.flexGrow = 1 + child2.finalizeProperties() + parent.nextProperties.height = 1 + parent.finalizeProperties() + parent.calculateLayout() + expect(child1.outerBounds.value[0][1], 'child 1 top').to.equal(0) + expect(child1.outerBounds.value[1][1], 'child 1 height').to.equal(0.5) + expect(child2.outerBounds.value[0][1], 'child 2 top').to.equal(0.5) + expect(child2.outerBounds.value[1][1], 'child 2 height').to.equal(0.5) + }) - it("should remove a property", () => { + it('should remove a property', () => { //no addProperties => remove all - child1.finalizeProperties(); - parent.calculateLayout(); - expect(child1.outerBounds.value[0][1], "child 1 top").to.equal(0); - expect(child1.outerBounds.value[1][1], "child 1 height").to.equal(0); - expect(child2.outerBounds.value[0][1], "child 2 top").to.equal(0); - expect(child2.outerBounds.value[1][1], "child 2 height").to.equal(1); - }); + child1.finalizeProperties() + parent.calculateLayout() + expect(child1.outerBounds.value[0][1], 'child 1 top').to.equal(0) + expect(child1.outerBounds.value[1][1], 'child 1 height').to.equal(0) + expect(child2.outerBounds.value[0][1], 'child 2 top').to.equal(0) + expect(child2.outerBounds.value[1][1], 'child 2 height').to.equal(1) + }) - it("change children order", () => { - child1.nextProperties.flexGrow = 1; - child1.finalizeProperties(); - child1.index = 1; - child2.index = 0; - parent.calculateLayout(); - expect(child1.outerBounds.value[0][1], "child 1 top").to.equal(0.5); - expect(child1.outerBounds.value[1][1], "child 1 height").to.equal(0.5); - expect(child2.outerBounds.value[0][1], "child 2 top").to.equal(0); - expect(child2.outerBounds.value[1][1], "child 2 height").to.equal(0.5); - }); + it('change children order', () => { + child1.nextProperties.flexGrow = 1 + child1.finalizeProperties() + child1.index = 1 + child2.index = 0 + parent.calculateLayout() + expect(child1.outerBounds.value[0][1], 'child 1 top').to.equal(0.5) + expect(child1.outerBounds.value[1][1], 'child 1 height').to.equal(0.5) + expect(child2.outerBounds.value[0][1], 'child 2 top').to.equal(0) + expect(child2.outerBounds.value[1][1], 'child 2 height').to.equal(0.5) + }) - it("change nothing", () => { - parent.calculateLayout(); - expect(child1.outerBounds.value[0][1], "child 1 top").to.equal(0.5); - expect(child1.outerBounds.value[1][1], "child 1 height").to.equal(0.5); - expect(child2.outerBounds.value[0][1], "child 2 top").to.equal(0); - expect(child2.outerBounds.value[1][1], "child 2 height").to.equal(0.5); - }); + it('change nothing', () => { + parent.calculateLayout() + expect(child1.outerBounds.value[0][1], 'child 1 top').to.equal(0.5) + expect(child1.outerBounds.value[1][1], 'child 1 height').to.equal(0.5) + expect(child2.outerBounds.value[0][1], 'child 2 top').to.equal(0) + expect(child2.outerBounds.value[1][1], 'child 2 height').to.equal(0.5) + }) - it("remove child & destroy before commit", () => { - parent.removeChild(child2); - child2.destroy(); - parent.nextProperties.height = 2; - parent.finalizeProperties(); - parent.calculateLayout(); - expect(child1.outerBounds.value[0][1], "child 1 top").to.equal(0); - expect(child1.outerBounds.value[1][1], "child 1 height").to.equal(2); - }); + it('remove child & destroy before commit', () => { + parent.removeChild(child2) + child2.destroy() + parent.nextProperties.height = 2 + parent.finalizeProperties() + parent.calculateLayout() + expect(child1.outerBounds.value[0][1], 'child 1 top').to.equal(0) + expect(child1.outerBounds.value[1][1], 'child 1 height').to.equal(2) + }) - it("remove child & destroy after commit", () => { - const c = parent.createChild(); - parent.removeChild(c); - parent.calculateLayout(); - expect(child1.outerBounds.value[0][1], "child 1 top").to.equal(0); - expect(child1.outerBounds.value[1][1], "child 1 height").to.equal(2); - c.destroy(); - }); + it('remove child & destroy after commit', () => { + const c = parent.createChild() + parent.removeChild(c) + parent.calculateLayout() + expect(child1.outerBounds.value[0][1], 'child 1 top').to.equal(0) + expect(child1.outerBounds.value[1][1], 'child 1 height').to.equal(2) + c.destroy() + }) - it("use percentage", () => { - child1.nextProperties.height = "25%"; - child1.finalizeProperties(); - parent.calculateLayout(); - expect(child1.outerBounds.value[0][1], "child 1 top").to.equal(0); - expect(child1.outerBounds.value[1][1], "child 1 height").to.equal(0.5); - }); + it('use percentage', () => { + child1.nextProperties.height = '25%' + child1.finalizeProperties() + parent.calculateLayout() + expect(child1.outerBounds.value[0][1], 'child 1 top').to.equal(0) + expect(child1.outerBounds.value[1][1], 'child 1 height').to.equal(0.5) + }) - it("use absolute value", () => { - child1.nextProperties.height = 0.33; - child1.finalizeProperties(); - parent.calculateLayout(); - expect(child1.outerBounds.value[0][1], "child 1 top").to.equal(0); - expect(child1.outerBounds.value[1][1], "child 1 height").to.equal(0.33); - }); -}); + it('use absolute value', () => { + child1.nextProperties.height = 0.33 + child1.finalizeProperties() + parent.calculateLayout() + expect(child1.outerBounds.value[0][1], 'child 1 top').to.equal(0) + expect(child1.outerBounds.value[1][1], 'child 1 height').to.equal(0.33) + }) +}) function equal(val1: any, val2: any) { - return val1 === val2 || (isNaN(val1) && isNaN(val2)); + return val1 === val2 || (isNaN(val1) && isNaN(val2)) } function flatten(val: any): any { if (val == null) { - return val; + return val } - if (typeof val === "object" && "value" in val) { - return val.value; + if (typeof val === 'object' && 'value' in val) { + return val.value } - return val; + return val }