Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/backend/src/altNodes/jsonNodeConversion.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { describe, expect, it } from "vitest";
import { hugSizingIsMeaningless } from "./jsonNodeConversion";

describe("hugSizingIsMeaningless", () => {
it("is false for a TEXT node with no children — it hugs its own characters", () => {
expect(hugSizingIsMeaningless({ type: "TEXT" })).toBe(false);
expect(hugSizingIsMeaningless({ type: "TEXT", children: [] })).toBe(false);
});

it("is true for an empty non-text frame — nothing to hug around", () => {
expect(hugSizingIsMeaningless({ type: "FRAME" })).toBe(true);
expect(hugSizingIsMeaningless({ type: "FRAME", children: [] })).toBe(true);
});

it("is false for a non-text frame with children — hugs its child content", () => {
expect(
hugSizingIsMeaningless({ type: "FRAME", children: [{}] })
).toBe(false);
});
});
35 changes: 26 additions & 9 deletions packages/backend/src/altNodes/jsonNodeConversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,24 @@ function adjustChildrenOrder(node: any) {
node.children = [...absoluteChildren, ...fixedChildren];
}

/**
* True when a node's HUG sizing has nothing to hug — an empty frame, where
* HUG-with-no-content is meaningless and falling back to FIXED is correct.
*
* A TEXT node never has a `children` array (its content is `characters`, a
* string, not child elements), so a plain "does it have children" check
* reads every TEXT node as having nothing to hug and forces it to FIXED —
* wrong, since text hugs its own characters. TEXT is therefore never
* "meaningless" here regardless of `children`.
*/
export function hugSizingIsMeaningless(node: {
type: string;
children?: unknown[];
}): boolean {
if (node.type === "TEXT") return false;
return !Array.isArray(node.children) || node.children.length === 0;
}

/**
* Recursively process both JSON node and Figma node to update with data not available in JSON
* This now includes the functionality from convertNodeToAltNode
Expand Down Expand Up @@ -537,17 +555,16 @@ const processNodePair = async (
jsonNode.counterAxisAlignItems = "MIN";
}

// If layout sizing is HUG but there are no children, set it to FIXED
const hasChildren =
"children" in jsonNode &&
jsonNode.children &&
Array.isArray(jsonNode.children) &&
jsonNode.children.length > 0;

if (jsonNode.layoutSizingHorizontal === "HUG" && !hasChildren) {
if (
jsonNode.layoutSizingHorizontal === "HUG" &&
hugSizingIsMeaningless(jsonNode)
) {
jsonNode.layoutSizingHorizontal = "FIXED";
}
if (jsonNode.layoutSizingVertical === "HUG" && !hasChildren) {
if (
jsonNode.layoutSizingVertical === "HUG" &&
hugSizingIsMeaningless(jsonNode)
) {
jsonNode.layoutSizingVertical = "FIXED";
}

Expand Down