Slate editor active state always false using isBlockActive from examples

1.6k views Asked by At

I have created an editor from composing a couple of slates examples together, namely https://www.slatejs.org/examples/richtext and https://www.slatejs.org/examples/links

However when I added these the active state for all block level nodes it doesn't work at all, meaning I can't toggle list items on and off, anchor links end up getting nested etc.

The broken code seems to be these lines, coming from isBlockActive function in all the examples:

const isBlockActive = (editor, format) => {
    const [match] = Editor.nodes(editor, {
        match: n => {
            console.log('n.type', n.type);
            return n.type === format;
        },
    });

    return !!match;
};

match is always undefined no matter where my cursor is located.

I am running latest on all the packages currently 0.58.1.

Below is my toggleBlock function I also took from the examples that uses the isBlockActive function to work out the toggling logic.

const toggleBlock = (editor, format) => {
    const isActive = isBlockActive(editor, format);
    const isList = LIST_TYPES.includes(format);

    Transforms.unwrapNodes(editor, {
        match: n => LIST_TYPES.includes(n.type),
        split: true,
    });

    Transforms.setNodes(editor, {
        type: isActive ? 'paragraph' : isList ? 'list-item' : format,
    });

    if (!isActive && isList) {
        const block = { type: format, children: [] };
        Transforms.wrapNodes(editor, block);
    }
};

Has anyone run into this problem before, perhaps the codebase is not in sync with the examples and Editor.nodes isn't recommended anymore?

All inline formatting options work as the example uses a different approach:

const isMarkActive = (editor, format) => {
    const marks = Editor.marks(editor);
    return marks ? marks[format] === true : false;
};

Also here is my toolbar and renderElement functions if it helps:

<Slate editor={editor} value={value} onChange={handleChange}>
  <div className={styles.toolbar}>
    <MarkButton format="bold" icon="bold" />
    <MarkButton format="italic" icon="italic" />
    <MarkButton format="underline" icon="underline" />
    <MarkButton format="code" icon="code" />
    <BlockButton format="heading-one" icon="h1" />
    <BlockButton format="heading-two" icon="h2" />
    <BlockButton format="heading-three" icon="h3" />
    <BlockButton format="quote" icon="quote-left" />
    <BlockButton format="numbered-list" icon="list-ol" />
    <BlockButton format="bulleted-list" icon="list-ul" />
    <BlockButton format="break" icon="horizontal-rule" />
    <LinkButton />
  </div>
  ...
const Element = ({ attributes, children, element }) => {
    switch (element.type) {
        case 'quote':
            return <blockquote {...attributes}>{children}</blockquote>;
        case 'code':
            return (
                <pre>
                    <code {...attributes}>{children}</code>
                </pre>
            );
        case 'heading-one':
            return <h1 {...attributes}>{children}</h1>;
        case 'heading-two':
            return <h2 {...attributes}>{children}</h2>;
        case 'heading-three':
            return <h3 {...attributes}>{children}</h3>;
        case 'heading-four':
            return <h4 {...attributes}>{children}</h4>;
        case 'heading-five':
            return <h5 {...attributes}>{children}</h5>;
        case 'heading-six':
            return <h6 {...attributes}>{children}</h6>;
        case 'list-item':
            return <li {...attributes}>{children}</li>;
        case 'numbered-list':
            return <ol {...attributes}>{children}</ol>;
        case 'bulleted-list':
            return <ul {...attributes}>{children}</ul>;
        case 'link':
            return (
                <a {...attributes} href={element.url}>
                    {children}
                </a>
            );
        default:
            return <p {...attributes}>{children}</p>;
    }
};
1

There are 1 answers

1
atng On BEST ANSWER

Editor.nodes() returns an iterator.

You'll need to change the isBlockActive function to:

const isBlockActive = (editor, format) => {
  const nodes = Editor.nodes(editor, {
    match: n => n.type === format,
  })
  return !!nodes.next().value
}