fix(site-builder): published Text/Heading keep plain-text newlines as <br> like the canvas
Canvas renders plain text via textToInlineHtml (newline -> <br>); toHtml used escapeHtml, so line breaks typed in the editor vanished on publish (TTM about page: ~100px shorter). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7d77201e5a
commit
d75f9d90ca
5 files changed
+20
-8
No files matched your search
@@ -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 <br>, like the editor canvas', () => {
|
||||
const { html } = (Heading as any).toHtml({ text: 'a\nb', level: 'h2' }, '');
|
||||
expect(html).toContain('a<br>b');
|
||||
});
|
||||
});
|
||||
@@ -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}>` };
|
||||
};
|
||||
@@ -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 <br>, like the editor canvas (textToInlineHtml)', () => {
|
||||
const { html } = toHtml({ text: 'a\n\nb <i>' }, '');
|
||||
expect(html).toBe('<p>a<br><br>b <i></p>');
|
||||
});
|
||||
});
|
||||
@@ -2,8 +2,7 @@ import React, { CSSProperties } from 'react';
|
||||
import { tokenRef } from '../../utils/tokens';
|
||||
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 { useInlineEditable } from './useInlineEditable';
|
||||
|
||||
interface TextBlockProps {
|
||||
@@ -94,6 +93,6 @@ TextBlock.craft = {
|
||||
|
||||
(TextBlock as any).toHtml = (props: TextBlockProps, _childrenHtml: string) => {
|
||||
const styleStr = cssPropsToString(props.style);
|
||||
const escapedText = resolveInlineHtml(props.text, props.html) ?? escapeHtml(props.text || '');
|
||||
const escapedText = resolveInlineHtml(props.text, props.html) ?? textToInlineHtml(props.text || '');
|
||||
return { html: `<p${styleStr ? ` style="${styleStr}"` : ''}>${escapedText}</p>` };
|
||||
};
|
||||
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user