slate icon indicating copy to clipboard operation
slate copied to clipboard

Hardcoded text node inside normalizeNode method

Open NEWESTERS opened this issue 3 years ago • 1 comments

Description There is following blocks of code inside editor's normalizeNode method:

// Ensure that block and inline nodes have at least one text child.
if (Element.isElement(node) && node.children.length === 0) {
	const child = { text: '' }; // <-- Problem here
	Transforms.insertNodes(editor, child, {
		at: path.concat(0),
		voids: true,
	});
	return;
}

and

// Ensure that inline nodes are surrounded by text nodes.
if (editor.isInline(child)) {
	if (prev == null || !Text.isText(prev)) {
		const newChild = { text: '' }; // <-- Problem here
		Transforms.insertNodes(editor, newChild, {
			at: path.concat(n),
			voids: true,
		});
		n++;
	} else if (isLast) {
		const newChild = { text: '' }; // <-- Problem here
		Transforms.insertNodes(editor, newChild, {
			at: path.concat(n + 1),
			voids: true,
		});
		n++;
	}
}

Text node structure is hardcoded with only one text field, but i want to add some properties and declare interface like this:

interface Text {
      text: string;
      bold: boolean;
}

This is correct according to docs (https://docs.slatejs.org/concepts/02-nodes#text).

Here i expect bold property to contain true or false, but sometimes i receive undefined. It's okay for boolean, but i might want to create non-boolean property:

interface Text {
      text: string;
      bold: boolean;
      fontFamily: string; // <- single source of truth for default font family
}

This is not feature request but bug, because of logical conflict between example in docs and real implementation.

Expectation I expect ability to override text nodes creation inside Slate, for example:

function createCustomTextNode(text: string): Text {
      return { text, bold: false, fontFamily: "Helvetica" }
}

function withCustomTextNode(editor: Editor): Editor {
      editor.createTextNode = createCustomTextNode;
      return editor;
}

And Slate methods should use this method instead of hardcoded values.

Environment

  • Slate Version: 0.65.3
  • Operating System: all
  • Browser: all
  • TypeScript Version: all

Workaround I've found current workaround for this problem with overriding editor's apply method:

import { Editor, Text } from 'slate';

function createCustomTextNode(text: string): Text {
      return { text, bold: false, fontFamily: "Helvetica" }
}

export function withCustomTextNode(editor: Editor): Editor {
	const { apply } = editor;

	editor.apply = (operation) => {
		if (
			operation.type === 'insert_node' &&
			Text.isText(operation.node) &&
			operation.node.text.length === 0
		) {
			apply({
				...operation,
				node: createCustomTextNode("")
			});
		} else {
			apply(operation);
		}
	};

	return editor;
}

NEWESTERS avatar Nov 30 '21 10:11 NEWESTERS

emm.. that's right,You should override the editor's apply method. I think can close the bug.

PangYiMing avatar Sep 21 '22 12:09 PangYiMing