diff --git a/craft/src/components/basic/Heading.toHtml.test.ts b/craft/src/components/basic/Heading.toHtml.test.ts
index 1236510..298820b 100644
--- a/craft/src/components/basic/Heading.toHtml.test.ts
+++ b/craft/src/components/basic/Heading.toHtml.test.ts
@@ -154,3 +154,10 @@ describe('Heading.toHtml inline rich text (#46)', () => {
test('Heading default colour is the text token', () => {
expect((Heading as any).craft.props.style.color).toBe('var(--wsb-text)');
});
+
+describe('Heading.toHtml newlines (canvas parity)', () => {
+ test('plain text newlines become
, like the editor canvas', () => {
+ const { html } = (Heading as any).toHtml({ text: 'a\nb', level: 'h2' }, '');
+ expect(html).toContain('a
b');
+ });
+});
diff --git a/craft/src/components/basic/Heading.tsx b/craft/src/components/basic/Heading.tsx
index dab636f..8ebe900 100644
--- a/craft/src/components/basic/Heading.tsx
+++ b/craft/src/components/basic/Heading.tsx
@@ -1,8 +1,7 @@
import React, { CSSProperties } from 'react';
import { useNode, UserComponent } from '@craftjs/core';
import { cssPropsToString } from '../../utils/style-helpers';
-import { escapeHtml } from '../../utils/escape';
-import { resolveInlineHtml } from '../../utils/inline-html';
+import { resolveInlineHtml, textToInlineHtml } from '../../utils/inline-html';
import { tokenRef } from '../../utils/tokens';
import { useInlineEditable } from './useInlineEditable';
@@ -102,7 +101,7 @@ Heading.craft = {
(Heading as any).toHtml = (props: HeadingProps, _childrenHtml: string) => {
const tag = sanitizeHeadingLevel(props.level);
- const safeText = resolveInlineHtml(props.text, props.html) ?? escapeHtml(props.text || '');
+ const safeText = resolveInlineHtml(props.text, props.html) ?? textToInlineHtml(props.text || '');
const styleStr = cssPropsToString(props.style);
return { html: `<${tag}${styleStr ? ` style="${styleStr}"` : ''}>${safeText}${tag}>` };
};
diff --git a/craft/src/components/basic/TextBlock.toHtml.test.ts b/craft/src/components/basic/TextBlock.toHtml.test.ts
index 564d1e5..be03998 100644
--- a/craft/src/components/basic/TextBlock.toHtml.test.ts
+++ b/craft/src/components/basic/TextBlock.toHtml.test.ts
@@ -117,3 +117,10 @@ describe('TextBlock.toHtml design tokens (#44)', () => {
for (const hex of ["#3f3f46"]) expect(lower, `old ${hex}`).not.toContain(hex);
});
});
+
+describe('TextBlock.toHtml newlines (canvas parity)', () => {
+ test('plain text newlines become
, like the editor canvas (textToInlineHtml)', () => {
+ const { html } = toHtml({ text: 'a\n\nb ' }, '');
+ expect(html).toBe('
a
b <i>
${escapedText}
` }; }; diff --git a/craft/src/utils/responsive-style.test.ts b/craft/src/utils/responsive-style.test.ts index 6b6d636..e20622f 100644 --- a/craft/src/utils/responsive-style.test.ts +++ b/craft/src/utils/responsive-style.test.ts @@ -205,10 +205,10 @@ describe('responsiveCssForNode', () => { import { dropBlankStyle as _dropBlankStyle } from './responsive-style'; describe('dropBlankStyle (canvas == exporter: blanks are not declarations)', () => { - it('drops "", null, undefined; keeps 0 and real values', () => { + test('drops "", null, undefined; keeps 0 and real values', () => { expect(_dropBlankStyle({ padding: '20px', paddingTop: '', a: null, b: undefined, opacity: 0, zIndex: '0' } as any)).toEqual({ padding: '20px', opacity: 0, zIndex: '0' }); }); - it('returns the same object when nothing is blank, and passes non-objects through', () => { + test('returns the same object when nothing is blank, and passes non-objects through', () => { const s = { color: 'red' }; expect(_dropBlankStyle(s)).toBe(s); expect(_dropBlankStyle(undefined)).toBeUndefined();