Files
yoga/website/src/components/YogaViewer.tsx
Nick Gerleman 733ba24064 Add Yoga 3.2 Release notes (#1761)
Summary:
Pull Request resolved: https://github.com/facebook/yoga/pull/1761

Whips up some release notes for what is new since Yoga 3.1.

https://github.com/facebook/yoga/compare/v3.1.0...v3.2.0

The relevant packages have already been published.

Reviewed By: joevilches

Differential Revision: D66679637

fbshipit-source-id: dd94e2a52f2bdc80541c331d1fb39de82669cc7a
2024-12-02 17:39:41 -08:00

130 lines
3.2 KiB
TypeScript

/**
* 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
*/
import {useMemo} from 'react';
import Yoga, {
Direction,
Display,
Overflow,
Node as YogaNode,
} from 'yoga-layout';
import {FlexStyle, applyStyle} from './FlexStyle';
import LayoutBox from './LayoutBox';
import type {LayoutMetrics} from './LayoutBox';
export type Props = Readonly<{
rootNode: StyleNode;
width?: number;
height?: number;
className?: string;
useWebDefaults?: boolean;
}>;
export type StyleNode = {
style?: FlexStyle;
children?: StyleNode[];
};
export default function YogaViewer({
rootNode,
width,
height,
className,
useWebDefaults,
}: Props) {
const layout = useMemo(
() => layoutStyleTree(rootNode, width, height, {useWebDefaults}),
[rootNode, width, height, useWebDefaults],
);
return <LayoutBox metrics={layout} depth={0} className={className} />;
}
type LayoutConfig = Readonly<{
useWebDefaults?: boolean;
}>;
// This is not efficient and not a good real-world-example for the best way to use Yoga, but sufficient for a playground
function layoutStyleTree(
node: StyleNode,
rootWidth: number | undefined,
rootHeight: number | undefined,
layoutConfig: LayoutConfig,
): LayoutMetrics {
const root = yogaNodeFromStyleNode(node, layoutConfig);
root.calculateLayout(rootWidth, rootHeight, Direction.LTR);
const layoutMetrics = metricsFromYogaNode(root);
layoutMetrics.overflow = node.style?.overflow;
root.freeRecursive();
return layoutMetrics;
}
function yogaNodeFromStyleNode(
styleNode: StyleNode,
layoutConfig: LayoutConfig,
): YogaNode {
const node = Yoga.Node.create(
layoutConfig.useWebDefaults ? webDefaultsConfig : undefined,
);
applyStyle(node, styleNode.style);
for (const child of styleNode.children ?? []) {
node.insertChild(
yogaNodeFromStyleNode(child, layoutConfig),
node.getChildCount(),
);
}
return node;
}
const webDefaultsConfig = Yoga.Config.create();
webDefaultsConfig.setUseWebDefaults(true);
function metricsFromYogaNode(node: YogaNode): LayoutMetrics {
const children: LayoutMetrics[] = [];
for (let i = 0; i < node.getChildCount(); i++) {
children.push(metricsFromYogaNode(node.getChild(i)));
}
// Offset is relative to parent padding box, so we need to subtract the extra
// border we show as part of the box.
const parentBorderThickness = 1;
return {
top: node.getComputedTop() - parentBorderThickness,
left: node.getComputedLeft() - parentBorderThickness,
width: node.getComputedWidth(),
height: node.getComputedHeight(),
overflow: (() => {
switch (node.getOverflow()) {
case Overflow.Hidden:
return 'hidden';
case Overflow.Scroll:
return 'scroll';
case Overflow.Visible:
return 'visible';
}
})(),
display: (() => {
switch (node.getDisplay()) {
case Display.Flex:
return 'flex';
case Display.None:
return 'none';
case Display.Contents:
return 'contents';
}
})(),
children,
};
}