volto-slate API#

The volto-slate API provides methods to integrate the Slate editor into projects that use Plone's React-based frontend Volto.

Extensions#

An extension in volto-slate is a function which takes Slate's Editor object and returns its extended version This allows a developer to modify and add several functionalities to a Slate Editor. For example, to define link elements as inline nodes, we override isInline from the Editor object.

export const isInline = (editor) => {
  const { isInline } = editor;

  editor.isInline = (element) => {
    return element && element.type === 'link' ? true : isInline(element);
  };

  return editor;
};

Plugins#

Plugins are the way to extend the capabilities of volto-slate by adding extra features to elementEditor.

See the default plugins.

Refer to How to write a Slate editor plugin for how to write your own plugin.

SlateEditor component#

SlateEditor is a top-level React component. It can be directly used in widgets to create a slateJSON field. For example, the following snippet creates a rich text SlateEditor component:

<FormFieldWrapper {...props} draggable={false} className="slate_wysiwyg">
  <div
    className="slate_wysiwyg_box"
    role="textbox"
    tabIndex="-1"
    onClick={() => {}}
    onKeyDown={() => {}}
  >
    <SlateEditor
      className={className}
      readOnly={readOnly}
      id={id}
      name={id}
      value={value}
      onChange={(newValue) => {
        onChange(id, newValue);
      }}
      block={block}
      selected={selected}
      properties={properties}
      placeholder={placeholder}
    />
  </div>
</FormFieldWrapper>

elementEditor#

The elementEditor is a top-level wrapper of all plugins used in volto-slate that exposes the plugins API in the form of makeInlineElementPlugin. It consists of various modules:

makeInlineElementPlugin

Used to build and install a custom schema based plugin from volto-slate API. It expects a set of options passed as a property to your plugin.

PluginEditor

Editor component for your Plugin.

ToolbarButton

Custom plugin ToolbarButton.

Note

You will get to know more about elementEditor in How to write a Slate editor plugin.

Serialization#

Serialization is the conversion of Slate JSON data into common formats such as text, HTML, and Markdown. Common serializers used in volto-slate are serializeNodes, serializeNodesToText, and serializeNodesToHtml.

Deserialization#

Deserialization is the transformation of arbitrary inputs into a Slate-compatible JSON structure. volto-slate uses Slate's own mechanism of deserialization using slate-hyperscript package. Deserialization helps control what data comes into Slate per element. It is called before the editorElement component for a plugin.

Following is the deserialization method for simpleLink plugin:

export const simpleLinkDeserializer = (editor, el) => {
  let parent = el;

  let children = Array.from(parent.childNodes)
    .map((el) => deserialize(editor, el))
    .flat();

  if (!children.length) children = [{ text: '' }];

  const attrs = {
    type: SIMPLELINK,
    data: {
      url: el.getAttribute('href'),
    },
  };

  return jsx('element', attrs, children);
};

Normalization#

Normalization ensures that Slate's data is always in its standard form. It is used as a part of the extensions for a particular plugin or a Slate editor itself.

Slate's data model should adhere to constraints provided in Slate's Normalizing documentation.

However, we can customize the functionality to add our own set of conditions by extending the normalizeNode method of the Slate editor.

For example, remove all img nodes inside p nodes.

const removeImgChild = (editor) => {
  const { normalizeNode } = editor;

  editor.normalizeNode = (entry) => {
    const [node, path] = entry;
    if (Element.isElement(node) && node.type === 'p') {
      for (const [child, childPath] of Node.children(editor, path)) {
        if (Element.isElement(child) && child.type === 'img') {
          Transforms.removeNodes(editor, { at: childPath });
          return;
        }
      }
    }
    normalizeNode(entry);
  };

  return editor;
};