diff --git a/packages/koenig-lexical/src/components/ui/cards/HeaderCard/v2/HeaderCard.jsx b/packages/koenig-lexical/src/components/ui/cards/HeaderCard/v2/HeaderCard.jsx index 6d227e63c4..f624697d89 100644 --- a/packages/koenig-lexical/src/components/ui/cards/HeaderCard/v2/HeaderCard.jsx +++ b/packages/koenig-lexical/src/components/ui/cards/HeaderCard/v2/HeaderCard.jsx @@ -314,6 +314,7 @@ export function HeaderCard({alignment, {/* Subheading */} { { const html = $generateHtmlFromNodes(this.__headerTextEditor, null); - const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: true, allowBr: true}); + const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: false, allowBr: true}); json.header = cleanedHtml; }); } diff --git a/packages/koenig-lexical/src/nodes/ProductNode.jsx b/packages/koenig-lexical/src/nodes/ProductNode.jsx index ad56a2013f..861da55f48 100644 --- a/packages/koenig-lexical/src/nodes/ProductNode.jsx +++ b/packages/koenig-lexical/src/nodes/ProductNode.jsx @@ -68,14 +68,14 @@ export class ProductNode extends BaseProductNode { if (this.__productTitleEditor) { this.__productTitleEditor.getEditorState().read(() => { const html = $generateHtmlFromNodes(this.__productTitleEditor, null); - const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: true}); + const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: false, allowBr: true}); json.productTitle = cleanedHtml; }); } if (this.__productDescriptionEditor) { this.__productDescriptionEditor.getEditorState().read(() => { const html = $generateHtmlFromNodes(this.__productDescriptionEditor, null); - const cleanedHtml = cleanBasicHtml(html, {allowBr: true}); + const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: false, allowBr: true}); json.productDescription = cleanedHtml; }); } diff --git a/packages/koenig-lexical/src/nodes/SignupNode.jsx b/packages/koenig-lexical/src/nodes/SignupNode.jsx index 7e265d91c0..bb43ca5c5e 100644 --- a/packages/koenig-lexical/src/nodes/SignupNode.jsx +++ b/packages/koenig-lexical/src/nodes/SignupNode.jsx @@ -71,7 +71,7 @@ export class SignupNode extends BaseSignupNode { if (this.__disclaimerTextEditor) { this.__disclaimerTextEditor.getEditorState().read(() => { const html = $generateHtmlFromNodes(this.__disclaimerTextEditor, null); - const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: true, allowBr: true}); + const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: false, allowBr: true}); json.disclaimer = cleanedHtml; }); } @@ -79,7 +79,7 @@ export class SignupNode extends BaseSignupNode { if (this.__headerTextEditor) { this.__headerTextEditor.getEditorState().read(() => { const html = $generateHtmlFromNodes(this.__headerTextEditor, null); - const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: true, allowBr: true}); + const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: false, allowBr: true}); json.header = cleanedHtml; }); } diff --git a/packages/koenig-lexical/src/nodes/ToggleNode.jsx b/packages/koenig-lexical/src/nodes/ToggleNode.jsx index 447013b701..046a550ad3 100644 --- a/packages/koenig-lexical/src/nodes/ToggleNode.jsx +++ b/packages/koenig-lexical/src/nodes/ToggleNode.jsx @@ -67,7 +67,7 @@ export class ToggleNode extends BaseToggleNode { if (this.__headingEditor) { this.__headingEditor.getEditorState().read(() => { const html = $generateHtmlFromNodes(this.__headingEditor, null); - const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: true}); + const cleanedHtml = cleanBasicHtml(html, {firstChildInnerContent: false, allowBr: true}); json.heading = cleanedHtml; }); } diff --git a/packages/koenig-lexical/src/utils/nested-editors.js b/packages/koenig-lexical/src/utils/nested-editors.js index a90935d3c5..3539e3b892 100644 --- a/packages/koenig-lexical/src/utils/nested-editors.js +++ b/packages/koenig-lexical/src/utils/nested-editors.js @@ -42,7 +42,7 @@ export function populateNestedEditor(node, editorProperty, html) { const nestedEditor = node[editorProperty]; const editorState = generateEditorState({ editor: nestedEditor, - initialHtml: html + initialHtml: `

${html}

` }); nestedEditor.setEditorState(editorState, {tag: 'history-merge'}); // use history merge to prevent undo clearing the initial state diff --git a/packages/koenig-lexical/test/e2e/cards/header-card.test.js b/packages/koenig-lexical/test/e2e/cards/header-card.test.js index 828c730b03..ef25912718 100644 --- a/packages/koenig-lexical/test/e2e/cards/header-card.test.js +++ b/packages/koenig-lexical/test/e2e/cards/header-card.test.js @@ -441,6 +441,45 @@ test.describe('Header card V2', () => { await expect(page.locator('[data-kg-card="header"] [data-kg="editor"]').nth(0)).toHaveText('hello world'); }); + test('can import serialized header card nodes with br', async function () { + const contentParam = encodeURIComponent(JSON.stringify({ + root: { + children: [{ + version: 2, + type: 'header', + size: 'small', + style: 'image', + buttonEnabled: false, + buttonUrl: '', + buttonText: '', + header: 'hello world
byebye world', + subheader: 'hello sub
byebye sub', + backgroundImageSrc: 'blob:http://localhost:5173/fa0956a8-5fb4-4732-9368-18f9d6d8d25a', + alignment: 'left', + buttonColor: '#ffffff', + buttonTextColor: '#000000', + backgroundColor: 'accent', + textColor: '#ffffff', + swapped: false + }], + direction: null, + format: '', + indent: 0, + type: 'root', + version: 1 + } + })); + + await initialize({page, uri: `/#/?content=${contentParam}`}); + await page.waitForSelector('[data-kg-card="header"]'); + await page.waitForSelector('[data-kg-card="header"] [data-kg="editor"]'); + await expect(page.locator('[data-kg-card="header"] [data-kg="editor"] p span').nth(0)).toHaveText('hello world'); + await expect(page.locator('[data-kg-card="header"] [data-kg="editor"] p br').nth(0)).toBeAttached(); + await expect(page.locator('[data-kg-card="header"] [data-kg="editor"] p span').nth(1)).toHaveText('byebye world'); + await expect(page.getByTestId('header-subheader-editor').locator('p span').nth(0)).toHaveText('hello sub'); + await expect(page.getByTestId('header-subheader-editor').locator('p br').nth(0)).toBeAttached(); + await expect(page.getByTestId('header-subheader-editor').locator('p span').nth(1)).toHaveText('byebye sub'); + }); test('renders header card node', async function () { await createHeaderCard({page, version: 2}); @@ -460,6 +499,47 @@ test.describe('Header card V2', () => { const firstEditor = page.locator('[data-kg-card="header"] [data-kg="editor"]').nth(0); await expect(firstEditor).toHaveText('Hello world'); }); + test('can add a shift-enter to header and subheader', async function () { + await createHeaderCard({page, version: 2}); + + await page.keyboard.type('Hello world'); + await page.keyboard.press('Shift+Enter'); + await page.keyboard.type('This is second line'); + await page.keyboard.press('Enter'); + await page.keyboard.type('Hello subheader'); + await page.keyboard.press('Shift+Enter'); + await page.keyboard.type('This is second subheader'); + await page.keyboard.press('Escape'); + await page.waitForSelector('[data-kg-card-editing="false"]'); + await assertHTML(page, html` +
+

Hello world +
+ This is second line +

+
`, + {selector: '[data-kg-card="header"] [data-kg="editor"]'}); + await assertHTML(page, html` +
+

Hello subheader +
+ This is second subheader +

+
`, + {selector: '[data-kg-card="header"] [data-testid="header-subheader-editor"] [data-kg="editor"]'}); + }); test('can edit sub header', async function () { await createHeaderCard({page, version: 2}); diff --git a/packages/koenig-lexical/test/e2e/cards/product-card.test.js b/packages/koenig-lexical/test/e2e/cards/product-card.test.js index ab5790da52..79f0bbe671 100644 --- a/packages/koenig-lexical/test/e2e/cards/product-card.test.js +++ b/packages/koenig-lexical/test/e2e/cards/product-card.test.js @@ -108,7 +108,99 @@ test.describe('Product card', async () => { `, {ignoreCardToolbarContents: true, ignoreInnerSVG: true}); }); + test('can import serialized product card nodes with a br', async function () { + const contentParam = encodeURIComponent(JSON.stringify({ + root: { + children: [{ + type: 'product', + productImageSrc: '/content/images/2022/11/koenig-lexical.jpg', + productTitle: 'This is title
Second line', + productDescription: '

Description
Moar description

', + productUrl: 'https://google.com/', + productButton: 'Button', + productButtonEnabled: true, + productRatingEnabled: true, + productStarRating: 4 + }], + direction: null, + format: '', + indent: 0, + type: 'root', + version: 1 + } + })); + + await initialize({page, uri: `/#/?content=${contentParam}`}); + await assertHTML(page, html` +
+
+
+
+ Product thumbnail +
+
+
+
+
+
+

+ This is + title +
+ Second line +

+
+
+
+
+
+ + + + + +
+
+
+
+
+
+

+ Description +
+ Moar description +

+
+
+
+
+
+ Button +
+
+
+
+
+ `, {ignoreCardToolbarContents: true, ignoreInnerSVG: true}); + }); test('renders product card node', async function () { await focusEditor(page); await insertCard(page, {cardName: 'product'}); @@ -454,6 +546,107 @@ test.describe('Product card', async () => {


`, {ignoreCardToolbarContents: true, ignoreInnerSVG: true}); }); + test('can handle new shift-enter in title and description', async () => { + await focusEditor(page); + await insertCard(page, {cardName: 'product'}); + + await page.keyboard.type('Test title'); + await page.keyboard.press('Shift+Enter'); + await page.keyboard.type('Second line of title'); + + await page.keyboard.press('Enter'); + await page.keyboard.type('Test description'); + await page.keyboard.press('Shift+Enter'); + await page.keyboard.type('Second line of description'); + await assertHTML(page, html` +
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+

+ Test title +
+ Second line of title +

+
+
+
+
+
+
+
+
+
+

Test description +
+ Second line of description +

+
+
+
+
+
+
+
+ + +
+
+
+
+


+ `, {ignoreCardToolbarContents: true, ignoreInnerSVG: true}); + }); }); async function uploadImg(page, src = 'large-image.png') { diff --git a/packages/koenig-lexical/test/e2e/cards/signup-card.test.js b/packages/koenig-lexical/test/e2e/cards/signup-card.test.js index 6b7df5e715..5f0aaec53c 100644 --- a/packages/koenig-lexical/test/e2e/cards/signup-card.test.js +++ b/packages/koenig-lexical/test/e2e/cards/signup-card.test.js @@ -106,6 +106,101 @@ test.describe('Signup card', async () => { `); }); + test('can import when brs are present in the serialized content', async function () { + const contentParam = encodeURIComponent(JSON.stringify({ + root: { + children: [{ + alignment: 'left', + backgroundColor: 'accent', + backgroundImageSrc: '__GHOST_URL__/content/images/2023/05/fake-image.jpg', + buttonColor: '#ffffff', + buttonText: '', + buttonTextColor: '#000000', + disclaimer: 'Disclaimer
Moar legal stuffz', + header: 'Header
More header', + labels: [], + layout: 'split', + subheader: 'Subheader
More subheader', + textColor: '#FFFFFF', + type: 'signup', + swaped: false, + version: 1 + }], + direction: null, + format: '', + indent: 0, + type: 'root', + version: 1 + } + })); + + await initialize({page, uri: `/#/?content=${contentParam}`}); + + await assertHTML(page, html` +
+
+
+
+
+ Background image +
+
+ + +
+
+
+
+
+
+

Header +
+ More header +

+
+
+
+
+
+
+

Subheader +
+ More subheader +

+
+
+
+
+
+ + +
+
+
+
+
+

Disclaimer +
+ Moar legal stuffz +

+
+
+
+
+
+
+
+
+
+ `); + }); test('renders signup card node', async function () { await focusEditor(page); @@ -157,6 +252,71 @@ test.describe('Signup card', async () => { await expect(thirdEditor).toHaveText('No spam. Unsubscribe anytime. For real.'); }); + test('can put a br anywhere', async function () { + await focusEditor(page); + await insertCard(page, {cardName: 'signup'}); + await page.keyboard.press('Shift+Enter'); + await page.keyboard.type('line two'); + await page.keyboard.press('Enter'); + await page.keyboard.press('Shift+Enter'); + await page.keyboard.type('line two'); + await page.keyboard.press('Enter'); + await page.keyboard.press('Shift+Enter'); + await page.keyboard.type('pickles'); + await page.keyboard.press('Escape'); + + await assertHTML(page, html` +
+
+
+
+
+
+
+
+

Sign up for Koenig Lexical +
+ line two +

+
+
+
+
+
+
+

There's a whole lot to discover in this editor. Let us help you settle in. +
+ line two +

+
+
+
+
+
+ + +
+
+
+
+
+

No spam. Unsubscribe anytime. +
+ pickles +

+
+
+
+
+
+
+
+
+
+
+


+ `, {ignoreCardToolbarContents: true}); + }); test('header, subheader and disclaimer texts are prepopulated', async function () { await focusEditor(page); diff --git a/packages/koenig-lexical/test/e2e/cards/toggle-card.test.js b/packages/koenig-lexical/test/e2e/cards/toggle-card.test.js index 2a318698b6..770ede073a 100644 --- a/packages/koenig-lexical/test/e2e/cards/toggle-card.test.js +++ b/packages/koenig-lexical/test/e2e/cards/toggle-card.test.js @@ -89,6 +89,76 @@ test.describe('Toggle card', async () => { `, {ignoreCardToolbarContents: true, ignoreInnerSVG: true}); }); + test('can import serialized toggle card nodes with br', async function () { + const contentParam = encodeURIComponent(JSON.stringify({ + root: { + children: [{ + type: 'toggle', + heading: 'Heading
Part 2!', // heading shouldn't have wrapper element like

or

+ content: '

Content

More Content

' + }], + direction: null, + format: '', + indent: 0, + type: 'root', + version: 1 + } + })); + + await initialize({page, uri: `/#/?content=${contentParam}`}); + + await assertHTML(page, html` +
+
+
+
+
+
+
+
+

Heading +
+ Part 2! +

+
+
+
+
+
+ +
+
+
+
+
+
+

Content

+

More Content

+
+
+
+
+
+
+
+
+ `, {ignoreCardToolbarContents: true, ignoreInnerSVG: true}); + }); test('renders toggle card node from slash command', async function () { await focusEditor(page); diff --git a/packages/koenig-lexical/test/e2e/editors/minimal-editor.test.js b/packages/koenig-lexical/test/e2e/editors/minimal-editor.test.js index 2f6beb2b8e..86719cfaa1 100644 --- a/packages/koenig-lexical/test/e2e/editors/minimal-editor.test.js +++ b/packages/koenig-lexical/test/e2e/editors/minimal-editor.test.js @@ -115,4 +115,15 @@ test.describe('Koening Editor with minimal nodes', async function () { await expect(await page.locator(h3ButtonSelector)).toHaveCount(0); }); }); + test('allows shift-enter', async function () { + await focusEditor(page); + + await page.keyboard.type('Hello World'); + await page.keyboard.press('Shift+Enter'); + await page.keyboard.type('This is second line'); + + await assertHTML(page, html` +

Hello World
This is second line

+ `); + }); });