Honeycomb

Markdown Editor

CodeMirror-based Markdown editor with toolbar, live preview, image upload, draft auto-save, and Hive blockchain integration.

Full Toolbar

Bold, italic, headings, lists, tables, code blocks, links, images, spoilers

Live Preview

Split, tab, or off -- three preview modes

Hive Image Upload

Upload to Hive imagehoster with signing challenge

Draft Auto-save

LocalStorage drafts with debounce and TTL

Dark Mode

Auto, light, or dark theme (one-dark-pro)

Plugin System

Custom toolbar items, keyboard shortcuts, paste handlers

CodeMirror peer dependencies

The editor uses CodeMirror 6 internally. You need to install the CodeMirror packages as peer dependencies alongside the honeycomb package.

Installation

pnpm add @codemirror/state @codemirror/view @codemirror/language @codemirror/lang-markdown @codemirror/commands @codemirror/theme-one-dark

Basic Usage

import { createSignal } from "solid-js";
import { MdEditor } from "@hiveio/honeycomb-solid";

function PostEditor() {
  const [content, set_content] = createSignal("");

  return <MdEditor value={content()} onChange={set_content} />;
}

Preview

Write your markdown here...

Examples

Hive Image Upload

Use create_hive_upload_handler to upload images to the Hive imagehoster with a signing challenge.

import { createSignal, createMemo } from "solid-js";
import { MdEditor, create_hive_upload_handler } from "@hiveio/honeycomb-solid";

function PostEditor(props: { username: string }) {
  const [content, set_content] = createSignal("");

  const upload_handler = createMemo(() =>
    create_hive_upload_handler({
      imageEndpoint: "https://images.hive.blog/",
      username: props.username,
      signChallenge: async (challenge) => {
        return await keychain.requestSignBuffer(props.username, challenge);
      },
    }),
  );

  return (
    <MdEditor
      value={content()}
      onChange={set_content}
      config={{ uploadHandler: upload_handler() }}
    />
  );
}

Preview Modes

"split"

Editor and preview side by side

"tab"

Switchable Write/Preview tabs

"off"

Editor only (default)

<MdEditor
  value={content()}
  onChange={set_content}
  config={{ previewMode: "split" }}
/>

{/* "tab" - switchable Write/Preview tabs */}
<MdEditor
  value={content()}
  onChange={set_content}
  config={{ previewMode: "tab" }}
/>

Custom Toolbar

Filter or reorder DEFAULT_TOOLBAR to create a minimal editor.

import { MdEditor, DEFAULT_TOOLBAR } from "@hiveio/honeycomb-solid";
import type { ToolbarItem } from "@hiveio/honeycomb-solid";

const minimal_toolbar: ToolbarItem[] = DEFAULT_TOOLBAR.filter(
  (item) =>
    item.type === "bold" ||
    item.type === "italic" ||
    item.type === "link" ||
    item.type === "image" ||
    item.type === "separator",
);

function MinimalEditor() {
  const [content, set_content] = createSignal("");

  return (
    <MdEditor
      value={content()}
      onChange={set_content}
      config={{ toolbar: minimal_toolbar }}
    />
  );
}

Draft Auto-save

Enable draft auto-save to localStorage with configurable debounce and TTL.

<MdEditor
  value={content()}
  onChange={set_content}
  config={{
    draftConfig: {
      enabled: true,
      key: "post-draft-my-post",
      debounceMs: 1000,
      ttlMs: 7 * 24 * 60 * 60 * 1000,
    },
  }}
/>

Dark Mode

The "auto" value follows the system preference via prefers-color-scheme.

// "auto" follows system preference (default)
<MdEditor value={content()} onChange={set_content} config={{ theme: "auto" }} />

// Force light or dark
<MdEditor value={content()} onChange={set_content} config={{ theme: "dark" }} />

Props

PropTypeDefaultDescription
valuestring-Markdown content (controlled)
onChange(value: string) => void-Called on content change
configPartial<MdEditorConfig>See config tableEditor configuration
classstring-CSS class on wrapper element
rendererOptionsPartial<RendererOptions>-Options passed to the preview renderer
onFocus() => void-Called when editor gains focus
onBlur() => void-Called when editor loses focus
onUploadStart(file: File) => void-Called when image upload starts
onUploadComplete(result: UploadResult) => void-Called when upload succeeds
onUploadError(error: Error) => void-Called when upload fails
onDraftSave(draft: DraftData) => void-Called when draft is saved
onDraftRestore(draft: DraftData) => void-Called when draft is restored on mount

MdEditorConfig

Pass via the config prop. All fields are optional.

FieldTypeDefaultDescription
placeholderstring-Placeholder text
minHeightnumber300Minimum height in pixels
maxHeightnumber-Maximum height in pixels
autoFocusbooleanfalseFocus editor on mount
toolbarToolbarItem[]DEFAULT_TOOLBARCustom toolbar actions
pluginsEditorPlugin[][]Editor plugins (toolbar items, shortcuts, paste handlers)
uploadHandlerUploadHandler-Image upload handler (enables upload button)
draftConfigDraftConfig-Auto-save draft configuration
previewMode"split" | "tab" | "off""off"Initial preview mode
theme"light" | "dark" | "auto""auto"Editor color theme
convertHiveUrlsbooleanfalseAuto-convert Hive blog URLs to @mention/permlink format

Default Toolbar Actions

Keyboard shortcuts use Mod (Cmd on macOS, Ctrl on Windows/Linux).

ActionTypeShortcut
BoldboldMod-B
ItalicitalicMod-I
StrikethroughstrikethroughMod-Shift-S
Inline CodecodeMod-E
Headingheading-
Quotequote-
Horizontal Rulehorizontal_rule-
Code Blockcode_block-
Tabletable-
LinklinkMod-K
Imageimage-
Spoilerspoiler-
Unordered Listunordered_list-
Ordered Listordered_list-
Task Listtask_list-
Content Renderer