Skip to content

Creating a Lake plugin

Overview

A Lake plugin is a function that extends the capabilities of Lake. It receives the current Editor instance as its parameter and can optionally return a cleanup function that will be called when the Editor instance is destroyed. This cleanup function is useful for tasks such as removing event listeners or destroying popup instances. If no cleanup is needed, returning a function is optional.

Basic plugin structure:

js
export default (editor) => {
  // Setup code here
  return () => {
    // Cleanup code here
  };
};

A simple plugin

The example below demonstrates how to register a removeFormat plugin using the plugin.add() method. This plugin registers a command to remove formatting from the current selection.

js
import { Editor } from 'lakelib';

const removeFormat = (editor) => {
  editor.command.add('removeFormat', {
    execute: () => {
      editor.selection.removeMark();
      editor.history.save();
    },
  });
};

Editor.plugin.add('removeFormat', removeFormat);
  • command.add(): Registers a new command.

  • selection.removeMark(): Removes styling like bold, underline, or font color from the current selection.

  • history.save(): Stores the current content in the memory, allowing you to undo or redo.

After registering the removeFormat plugin, you can remove formatting by executing the following command:

js
editor.command.execute('removeFormat');

Try the removeFormat plugin in the demo below:

A plugin with box

Lake supports embedding custom components, called boxes, using its Box interface. Plugins that include a box typically follow this structure:

hello-world
├─ hello-world-box.js
├─ hello-world-box.css
└─ index.js

Below is the code for these files:

js
import './hello-world-box.css';
import helloWorldBox from './hello-world-box';

export { helloWorldBox };

export default (editor) => {
  if (editor.readonly) {
    return;
  }
  editor.command.add('helloWorld', {
    execute: (value) => {
      editor.selection.insertBox('helloWorld', value);
      editor.history.save();
    },
  });
};
js
import { query, template } from 'lakelib';

export default {
  type: 'block',
  name: 'helloWorld',
  value: {
    number: 0,
  },
  render: (box) => {
    const editor = box.getEditor();
    const value = box.value;
    const boxContainer = box.getContainer();
    const rootNode = query(template`
      <div class="lake-hello-world">
        <div>Hello World!</div>
        <div>
          <button type="button" class="lake-button lake-text-button">Count</button>
          <span>${value.number}</span>
        </div>
      </div>
    `);
    boxContainer.empty();
    boxContainer.append(rootNode);
    const numberNode = rootNode.find('span');
    rootNode.find('button').on('click', () => {
      const nextNumber = Number.parseInt(numberNode.text(), 10) + 1;
      numberNode.text(nextNumber.toString(10));
      box.updateValue({
        number: nextNumber,
      });
      editor.history.save();
    });
    rootNode.on('click', () => {
      editor.selection.selectBox(box);
    });
  },
};
css
lake-box[name='helloWorld'] {
  margin-bottom: 8px;
}

.lake-hello-world {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border: 1px solid transparent;
  border-radius: 5px;
  background-color: var(--lake-box-background-color);
  padding: 12px 24px;
  user-select: none;
}

lake-box[name='helloWorld'] .lake-box-selected .lake-hello-world,
lake-box[name='helloWorld'] .lake-box-focused .lake-hello-world {
  border-color: var(--lake-box-border-color);
}

.lake-hello-world .lake-button {
  margin: 0 12px;
  border: 0;
  background-color: #5672cd;
  color: #fff;
}

.lake-hello-world .lake-button:hover {
  background-color: #3a5ccc;
}

Before the helloWorld plugin can be used, you must register its box and add a corresponding button to your toolbar. When clicked, the button executes the command to insert a helloWorld box into the editor.

js
import { Editor, Toolbar } from 'lakelib';
import helloWorld, { helloWorldBox } from './hello-world';

Editor.box.add(helloWorldBox);

Editor.plugin.add('helloWorld', helloWorld);

const helloWorldItem = {
  name: 'helloWorld',
  type: 'button',
  icon: '<img> or <svg>',
  tooltip: 'Hello World',
  onClick: (editor) => {
    editor.command.execute('helloWorld');
  },
};

const toolbar = new Toolbar({
  root: '.my-toolbar',
  items: [ helloWorldItem ],
});

const editor = new Editor({
  root: '.my-content',
  toolbar,
});
editor.render();

Try the helloWorld plugin in the demo below:

The complete example above is also available on CodeSandbox. You can visit it to explore and experiment with the source code.

Released under the MIT License.