Skip to content

Commit 5ff6bb7

Browse files
authored
fix: preserve leading space in inline element following text without trailing space (#5712)
1 parent 395385f commit 5ff6bb7

2 files changed

Lines changed: 25 additions & 3 deletions

File tree

apps/builder/app/shared/html.test.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,17 @@ test("collapse any spacing characters inside rich text", () => {
225225
);
226226
});
227227

228+
test("preserve leading space in inline element following text without trailing space", () => {
229+
expect(generateFragmentFromHtml(`<h2>About<span> Us</span></h2>`)).toEqual(
230+
renderTemplate(
231+
<ws.element ws:tag="h2">
232+
{"About"}
233+
<ws.element ws:tag="span">{" Us"}</ws.element>
234+
</ws.element>
235+
)
236+
);
237+
});
238+
228239
test("generate style attribute as local styles", () => {
229240
expect(
230241
generateFragmentFromHtml(`

apps/builder/app/shared/html.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,10 @@ export const generateFragmentFromHtml = (
598598
// Map of instanceId → resolved class names (for post-processing token assignments)
599599
const instanceTokenClasses = new Map<string, string[]>();
600600

601-
const convertElementToInstance = (node: ElementNode) => {
601+
const convertElementToInstance = (
602+
node: ElementNode,
603+
{ preserveLeadingSpace = false }: { preserveLeadingSpace?: boolean } = {}
604+
) => {
602605
if (node.tagName === "script" && node.sourceCodeLocation) {
603606
const { startCol, startOffset, endOffset } = node.sourceCodeLocation;
604607
const indent = startCol - 1;
@@ -859,7 +862,13 @@ export const generateFragmentFromHtml = (
859862
for (let index = 0; index < node.childNodes.length; index += 1) {
860863
const childNode = node.childNodes[index];
861864
if (defaultTreeAdapter.isElementNode(childNode)) {
862-
const child = convertElementToInstance(childNode);
865+
const lastChild = instance.children.at(-1);
866+
const nextPreserveLeadingSpace =
867+
instance.children.length > 0 &&
868+
!(lastChild?.type === "text" && lastChild.value.endsWith(" "));
869+
const child = convertElementToInstance(childNode, {
870+
preserveLeadingSpace: nextPreserveLeadingSpace,
871+
});
863872
if (child) {
864873
instance.children.push(child);
865874
}
@@ -880,7 +889,9 @@ export const generateFragmentFromHtml = (
880889
// collapse spacing characters inside of text to avoid preserved newlines
881890
child.value = child.value.replaceAll(/\s+/g, " ");
882891
// remove unnecessary spacing in nodes
883-
if (index === 0) {
892+
// skip trimStart if the parent signaled that leading space is semantic
893+
// (e.g. `<span> Us</span>` following `About` with no intervening space)
894+
if (index === 0 && !preserveLeadingSpace) {
884895
child.value = child.value.trimStart();
885896
}
886897
if (index === node.childNodes.length - 1) {

0 commit comments

Comments
 (0)