Skip to content

[Bug][Editor] Enter appears dead in empty textblocks nested inside div wrappers (liftEmptyBlock wins over splitBlockKeepMarks) #3766

Description

@fuery

I'm submitting a...

  • Bug report

Package: @progress/kendo-react-editor (schema/keymap from @progress/kendo-editor-common)

Current behavior

When the caret is inside an empty textblock nested in one or more div nodes, pressing Enter appears to do nothing. The document does change, but invisibly: liftEmptyBlock lifts the empty block out of its parent div, which renders pixel-identically. Depending on the structure, either the next Enter finally splits (block reached top level), or — when the empty block has siblings inside the divevery Enter keeps lifting/splitting the div wrapper and a visible new line is never produced.

This is very common in real content: HTML email bodies (Gmail/Outlook) wrap every line in <div>, producing structures like <div>line1</div><div><br></div><div>line2</div>. Users placing the caret on the blank line and pressing Enter get a "dead" key.

Expected behavior

Enter in an empty block nested in plain div wrappers should produce a visible new line (split), like it does at top level.

Root cause analysis

buildKeymap in @progress/kendo-editor-common/dist/es/config/keymap.js binds:

keys.Enter = chainCommands(newlineInCode, createParagraphNear, liftEmptyBlock, splitBlockKeepMarks);

Because the schema's div node is content: 'block*', an empty paragraph inside a div satisfies liftEmptyBlock's preconditions, so it wins the chain ahead of splitBlockKeepMarks. The lift is structurally correct ProseMirror behaviour, but with a styling-neutral div wrapper the result is visually indistinguishable from a no-op.

Minimal reproduction (headless, uses only your packages)

// All symbols re-exported by the editor package itself
const { ProseMirror } = require('@progress/kendo-react-editor');
const {
    Schema, EditorState, TextSelection,
    chainCommands, newlineInCode, createParagraphNear,
    liftEmptyBlock, splitBlockKeepMarks,
} = ProseMirror;
const { nodes, marks } = require('@progress/kendo-editor-common');

const schema = new Schema({ nodes, marks });
const { doc, paragraph, div } = schema.nodes;
const enter = chainCommands(newlineInCode, createParagraphNear, liftEmptyBlock, splitBlockKeepMarks);

// <div><p>a</p><p></p><p>b</p></div> — caret in the empty middle paragraph
let d = doc.create(null, [div.create(null, [
    paragraph.create(null, schema.text('a')),
    paragraph.create(),
    paragraph.create(null, schema.text('b')),
])]);
let state = EditorState.create({ doc: d });
state = state.apply(state.tr.setSelection(TextSelection.create(state.doc, 5)));

for (let i = 1; i <= 3; i++) {
    enter(state, tr => { state = state.apply(tr); });
    console.log(`Enter #${i}:`, state.doc.toString());
}

Output — no visible new line is ever created; the div wrapper is repeatedly split instead:

Enter #1: doc(div(paragraph("a")), div(paragraph, paragraph("b")))
Enter #2: doc(div(paragraph("a")), div, div(paragraph, paragraph("b")))
Enter #3: doc(div(paragraph("a")), div, div, div(paragraph, paragraph("b")))

In the Editor UI this reproduces by setting defaultContent to
<div>line1</div><div><br></div><div>line2</div>, clicking the blank middle line, and pressing Enter.

Suggested fix

In buildKeymap, guard liftEmptyBlock so it does not apply when all ancestors of the empty block are plain div nodes (no styling semantics), falling through to splitBlockKeepMarks instead. Lifting should be preserved for semantically meaningful wrappers (blockquote, list items).

Workaround we ship in production — a prepended keymap plugin:

const enterInEmptyDivBlock = (state, dispatch) => {
    const { $cursor } = state.selection;
    if (!$cursor || $cursor.parent.content.size > 0 || $cursor.depth < 2) return false;
    for (let d = $cursor.depth - 1; d >= 1; d--) {
        if ($cursor.node(d).type.name !== 'div') return false;
    }
    return splitBlockKeepMarks(state, dispatch);
};

Environment

  • KendoReact version: @progress/kendo-react-editor 14.4.1 / @progress/kendo-editor-common 1.12.5
  • React version: 18.3.1
  • Browser: all (Chrome, Firefox, Safari — logic-level bug, not rendering)
  • OS: all

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions