docs/solutions/ui-bugs/2026-04-02-blockquote-transforms-must-keep-selection-inside-the-new-quote.md
After blockquote became a real container node, the app-level editor helpers in apps/www still treated it like a flat text block.
That mismatch broke the editing flow: inserting or converting a quote created the right shape eventually, but the caret landed in the previous block instead of inside the new quote.
/quote in /blocks/editor-ai inserted a blockquote, then typing went into the previous paragraph.[1, 0] to the previous block instead of the wrapped paragraph at [1, 0, 0].editor.tf.blockquote.toggle() did not reproduce the bug by itself, so the broken seam was easy to misread.BaseBlockquotePlugin regression. The core wrap transform already preserved selection.setBlockType(...) on flat setNodes({ type: KEYS.blockquote }). That let normalization repair the node shape later, after selection had already drifted.select: true after inserting a blockquote node. For a container block, that is not precise enough.Fix the shared apps/www editor transform seam instead of patching one UI caller at a time.
createBlockquote(...) helper that inserts a container quote with an inner paragraph.selectBlockquoteStart(...) so quote insertion explicitly selects the nested paragraph start.insertBlock(editor, KEYS.blockquote) to insert the container shape and select [path, 0, 0].setBlockType(editor, KEYS.blockquote) to call editor.tf.toggleBlock(type, { wrap: true }) instead of flat setNodes.setBlockType(...) so it uses the same fixed path.The important transform seams became:
if (type === KEYS.blockquote) {
const insertPath = PathApi.next(path);
editor.tf.insertNodes(createBlockquote(editor), { at: insertPath });
selectBlockquoteStart(editor, insertPath);
return;
}
if (type === KEYS.blockquote) {
editor.tf.toggleBlock(type, {
...(at ? { at } : {}),
wrap: true,
});
return;
}
blockquote is now a container element, so insertion and conversion must preserve two things together:
The core wrap transform already knew how to do that. The app helpers did not. Once the app seam stopped creating flat quotes and stopped using flat block conversion, selection stayed anchored inside the new quote.
setNodes or generic select: true for container-block insertion when the user must land inside a nested text block.#4898