An extensible WYSWYG editor based on Lexical.
Kalliope is a ready-to-use editor based on lexical. It is intended to be easy to use and ships with several ready to use plugins.
It does not contain a graphical interface beyond that of the editor itself, and is therefore not tied to any particular UI.
- Built in plugins
- Installation
- Usage
- Configuration
- Utility functions
- Editor commands
- Valid code languages
- Code highlight and code formatting.
- Drag and drop images.
- Emojis (english default).
- Floating link editor.
- Table cell.
- Mentions
- Citation block
- Speech to text
- Text spoiler
- Block spoiler (collapsible)
- Insert tweets
- Insert videos (Youtube, Facebook, Dailymotion, Soundcloud, Twitch).
- Basic formatting (bold, italic, underline, strikethrough, superscript, subscript).
- Text coloring (font and background).
- Different font types
- Different block types (heading, bullet list, numbered list, check list, quote and code block).
yarn add kalliope
import CalliopeEditor from 'kalliope';
The editor component takes three parameters
- config (required) : an object containing configuration options (detailed below).
- containerRef (required): a react ref used to manipulate the editor.
- setFormats (optional): a function used to set the formats applied to the selected text. Useful when building UIs.
<CalliopeEditor
config={config}
containerRef={containerRef}
setFormats={setFormats}
/>
The configuration object (config parameter) looks like this.
{
placeholderText: t('toolbar.placeholderText'),
initialState: initialState,
isReadOnly: false,
autoFocus: true,
onError: (error) => {
throw error;
},
plugins: [],
imageConfig: {
addCaptionText: t('internal.addCaption'),
defaultCaptionText: t('internal.enterCaption'),
},
twitterConfig: {
loadingComponent: ({ tweetId }) => (
<p>
{t('internal.loadingTweet')}...(ID={tweetId})
</p>
),
},
collapsibleConfig: {
open: true,
},
citation: {
sourceLinkComponent: ({ sourceLink }) => (
<a href={sourceLink} className="source-link-component">
<FontAwesomeIcon icon={sourceIcon} size="lg" />
</a>
) /*,
authorComponent: ({ author }) => (
<a href={author.link} className="author-link-container">
<AccountAvatar
avatar={author.avatar}
username={author.name}
size="5px"
shape="circle"
/>
<span className="author-link-quote">{author.name}</span>
</a>
),*/,
},
mentions: {
onSearchChange: onSearchChange,
onAddMention: (mention) => {
setMentions([...mentions, mention.name]);
},
onRemoveMention: ({ name, link }) => {
const newMentions = mentions.filter((m) => m !== name);
setMentions(newMentions);
},
entryComponent: ({ option: { avatar, name, link } }) => (
<>
<AccountAvatar avatar={avatar} username={name} size="5px" shape="circle" />
<strong className="user-name-mentions">{name}</strong>
</>
),
mentionsData: suggestions,
},
emojiConfig: {
emojiData: emojiData,
},
dragAndDropImage: {
handleDroppedFile: async (file) => {
const resp = await uploadFileToServer(file);
const { src } = resp;
if (src === null) {
notification.error({
message: 'Failed to upload File',
description: "Couldn't upload file to the server (file type not allowed).",
placement: 'topRight',
});
return;
}
const imageSrc = `/static/uploads/${src}`;
containerRef.current.executeCommand('INSERT_IMAGE', {
src: imageSrc,
altText: file.name,
});
},
},
}
Accesible using the containerRef ref.
| Name | Parameters | Description |
|---|---|---|
| getContent | () => Lexical Editor State | Gets get the current editor content. Returns a Lexical Editor State as JSON. |
| clear | () => void | Clears the editor. |
| executeCommand | ({commandName: string, commandParams: any}) => void |
Executes and editor command (toggle a block or a font style). |
| focus | () => void |
Sets the focus for the editor. |
| Name | Parameters | Description |
|---|---|---|
| UNDO | none | Undo last command |
| REDO | none | Redo last undone command |
| FORMAT | string. One of bold| italic | underline | strikethrough | superscript | subscript | code |
Apply basic text formatting. |
| KEYBOARD | none | Apply keyboard formatting. |
| SPOILER | none | Apply text spoiler formatting. |
| LINK | string link to insert |
Insert link |
| ALIGN | string one of left | center | right | justify |
Insert link |
| INDENT | none | Indent text |
| OUTDENT | none | Outdent text |
| PARAGRAPH | none | Apply paragraph block style to selected text |
| BULLET_LIST | none | Apply bullet list formatting to selected text |
| NUMBERED_LIST | none | Apply numbered list formatting to selected text |
| CHECK | none | Apply check list formatting to selected text |
| H1 | none | Apply h1 formatting to selected text |
| H2 | none | Apply h2 formatting to selected text |
| H3 | none | Apply h3 formatting to selected text |
| QUOTE | none | Apply quote block formatting to selected text |
| CODE_BLOCK | none | Apply code block formatting (w/format highlighting) to selected text. |
| CODE_LANGUAGE_CHANGE | value: string - a code language. See list of valid code languages below |
Change the code language inside a code block. The current block must already be a code block for this method to work. |
| CHANGE_FONT | string a valid font family.
Suggested values are (Arial, Courier New, Georgia, Times New Roman, Trebuchet MS, Verdana) |
Chang the font family type. |
| CHANGE_FONT_SIZE | string a valid font size. 'px' (ie: '10px') |
Chang the font size. |
| CHANGE_FONT_COLOR | string a valid hexadecimal color value. | Change the font color. |
| CHANGE_FONT_BG_COLOR | string a valid hexadecimal color value. | Change the background color. |
| INSERT_RULE | none | Insert a horizontal rule. |
| INSERT_IMAGE | object { altText: string, src: string }. src is the image url. alt text is the alt text for the image. Neither can be null.
|
Insert a resizeable image into the editor. |
| INSERT_TWEET | string tweetId. The id in the tweet url (Twitter urls are formatted like this: twitter.com//status/) | Insert a tweet into the editor. |
| INSERT_INSTAGRAM_POST | string instagramURL. The instagram URL (Instagram urls are formatted like this: "https://www.instagram.com/p//") | Insert an instagram post into the editor (only works for public instagram links). |
| INSERT_TABLE | object {columns: integer, rows: integer}
|
Insert a table into the editor. |
| INSERT_EQUATION | object { equation: string, inline: boolean }. The equation must be a valid latex formula. Inline specifies wether the equation is rendered on its own line or not.
|
Insert a LaTeX equation into the editor. Only Valid Katex formulas accepted. |
| INSERT_VIDEO | url: string . The URL of the video in question. Look below for accepted video sites.
|
Insert video content into the editor. |
| INSERT_EXCALIDRAW | none | Open excalidraw popup. This does not insert anything into the editor, the insertion is done when the user clicks the save button. |
| INSERT_BLOCK_SPOILER | open: boolean |
Insert block spoiler (a collapsible container akin to html's summary). |
| SPEECH_TO_TEXT | isSpeechToText: boolean - indicates wether speech to text is active or not |
Open the microphone to convert speech to text. When switched off it will insert the captured text into the editor |
| INSERT_CITE_QUOTE |
{
author: { name: string, link: string},
source: { content: string, link: string }
}
|
Insert a citation. |
A list of valid code languages is exported from the editor. To obtain the list use the `` function takes a parameter that indicates wether to use Shiki as a code highlighter or not (if not, it will return a list of languages that Prism can highlight).
import { getCodeLanguageOptions } from 'kalliope';
const CODE_LANGUAGES = getCodeLanguageOptions(false);
The following code languages are accepted by the highlighter. The value column indicates the value passed as the parameter of the CHANGE_CODE_LANGUAGE command.
| Value | Language |
|---|---|
| c | C |
| clike | C-Like |
| objc | Objective-C |
| html | HTML |
| xml | XML |
| css | CSS |
| sql | SQL |
| js | JavaScript |
| markdown | Markdown |
| py | Python |
| powershell | Powershell |
| rust | Rust |
| swift | Swift |
| plain | Plain Text |
| ts | Typescript |
