For installation instructions check out Setting Up Your DevEnv.

Overview

The BobaEditor Codebase contains all code pertaining to BobaBoard's text editing capabilities (see demo). It's written in Typescript and React.

There are two important folders:

Src Folder

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/459e83cb-ddc7-4b2a-bcad-e82e3161c850/classes.png

The main editor component is Editor.tsx. This is a React Class Component which wraps a QuillJS editor within itself. It takes care of displaying text both in edit mode (when the editable props is true) as well as read-only mode (with editable props = false). ****Documentation for every prop is available in the comments for the TypeScript interface.

Within Editor.tsx the Toolbar component, contains the options in edit mode (e.g. bold, italic, spoilers, headers and so on). This should not be confused with Tooltip.tsx which, instead, contains the options that are only available on empty new lines (e.g. add image, embed video, search gif and so on). The display of the Tooltip is controlled by the maybeShowEmptyLineTooltip method within Editor.tsx, which checks whether the cursor is presently on an empty line.

Delta Overview

<aside> ⚠️ TODO: add a quick overview of how the delta format works to help people get a rough understanding of it.

</aside>

Custom Nodes & Embeds

Custom elements and formatting are implemented using Parchment, Quill's document model, and stored under custom-nodes. Rather than reading the suboptimal Parchment documentation, the easiest way to understand how these work is to look at how other types are implemented.

How Custom Nodes Work

There's two types of custom nodes: inline and block. If you're familiar with inline vs block CSS elements, I understand these to be roughly equivalent.

The entry point for block nodes (e.g. embeds) is the "create" method. This is called by Quill every time an embed of the given type is added to the editor, either manually by the user or as part of loading a saved delta. In the first case the argument will be the value supplied by the user (e.g. the embed URL in case of embeds), in the latter the argument will be the value stored in the embed configuration, which you can see returned by the "value" method.

Embeds loaded through iFramely are handled by subclassing OEmbedBase.ts with embed-specific logic. OEmbedBase.ts ****also handles "best effort load" embeds.

Styling for embeds is handled by CustomNodesStyle.tsx. Note the :global() instruction wrapping class names, which will have to be cleaned up at some point (but is necessary for now).