Next-generation editor for BobaBoard (and beyond). Still in experimental phase. Name subject to change.
Check back later for the ability to install this without exploding your whole project.
First install the editor dependencies by running yarn install
.
You can start an auto-updating dev preview of the editor by running Storybook:
yarn run storybook
This project is based on TipTap editor which is in turn based on ProseMirror. For help, try the TipTap documentation first, and (if you're really desperate) the ProseMirror docs.
Currently all our plugins and our editor are written in React.
This project uses yarn workspaces for monorepo setup. To install a dependency in
a specific package you need the name of the package you're targeting (specified
within its package.json
).
yarn workspace [target-workspace] add [target-library]
For example, to add the react-query
dependency to the main editor you can run:
yarn workspace @bobaboard/boba-editor-next add react-query
This project uses Turborepo (or tries to) to maintain a monorepo structure. We do this so we can keep multiple related projects in a single repository.
The top-level folder contains the following packages:
storybook/
: the Storybook setup that we use for development and previewOutputInspectorAddon/
: the Storybook plugin we use to display the rendered HTML output of the editor's content.src/
: the actual code for the editor and its plugins
The editor folder (src/
) is further divided in the following sub-packages:
editor/
: contains the base editor, menus and some plugin presets. (Note: this will be further split in due time)plugins/
: contains folder for each custom plugin that we createdBlockWithMenu/
(internal only): A base plugin for block items (e.g. images, embeds) that display an additional menu for extended configuration.Image
: A plugin that allows to display a (for now single) image. Comes with options like spoilers, and logic to prevent layout shifts.InlineSpoilers
: A plugin that allows to select text and hide it from onlookers' eyes until clicked.OEmbed
: A plugin that allows loading URLs from a variety of websites as embeds. Needs an iframely instance to connect to for embed data.GifSelector
(in progress): Allows to search for and insert a GIF.
- Create a new folder within
src/plugins
. - Create a
package.json
and avite.config.ts
files. Since we're using a monorepo, every plugin needs its own configuration. You can generally copy these from other plugins, but make sure to change thename
inpackage.json
to match your plugin's. - Create a
Plugin.tsx
file. This file should export a TipTap plugin that creates either a Mark (for inline formatting) or a Node (for content). - If you're creating a new type of Node, you might want to create a
Component.tsx
file to contain the components that are needed by the plugin. - Create a
index.ts
file to re-export the plugin exported byPlugin.tsx
.
Before you can use your plugin with Storybook you will need to add it to the
dependencies specified in storybook/package.json
. You can do so by copying the
name
field in the package.json
of the plugin and adding an additional entry
in the dependencies
object.
Example:
"dependencies": {
// more dependencies
// ...
"@bobaboard/tiptap-inline-spoilers": "*",
// ...
// more dependencies
}
Make sure to run yarn install
from the root directory of the project after
modifying these dependencies.
[!NOTE] If you want to include a plugin within another one, you will need to follow a similar procedure.
There are 3 different modes a plugin can be outputted as:
- Edit: In this mode, the editor is being used to input content. The plugin might display additional interfaces that allow to customize the final content displayed in view mode.
- View: In this mode, the editor is being used to display content. The plugin might still display additional interfaces that allow the viewer to interact with the displayed content (for example, the option to toggle spoilers).
- HTML: In this mode, the editor prints out the HTML used to render the
content created by the plugin. The HTML in output should only contain what's
needed to statically display the content, without additional menus or
interaction-only nodes. In this mode, we also include any additional data
attribute needed to reconstruct the intended semantic of the output (for
example, an image might include the
data-spoiler=true
attribute to indicate that it's meant to be initially hidden from view).
Contributions are always welcome! You can check currently-planned features by looking at this issue or the other issues in this repo.