npm package: @inkami/blx
Description: A block-based editor library
Latest version: 0.17.4

# @inkami/blx

**A block-based editor for the web.** Notion-style editing — rich text, media, tables, nesting — in a single TypeScript library with zero framework dependencies.

## Install

```bash
npm install @inkami/blx
```

## Quick Start

```ts
import { Editor, AttributedString } from "@inkami/blx";
import "@inkami/blx/style.css";

const editor = new Editor(document.getElementById("editor")!, {
  initialBlocks: [
    {
      id: "1",
      type: "paragraph",
      content: AttributedString.fromPlain("Hello, world!"),
      metadata: {},
    },
  ],
});
```

## Features

| | |
|---|---|
| **Rich text** | Bold, italic, underline, strikethrough, inline code, highlights (6 colors) |
| **Block types** | Paragraphs, headings (1-6), ordered/unordered lists, task lists, code (syntax highlighted), images, YouTube embeds, tables, horizontal rules |
| **Links** | Inline links with `[markdown](syntax)`, Cmd+K popover, `[[` internal block references with autocomplete |
| **Editing** | Slash menu, inline toolbar, block action menu, drag handles, multi-block selection |
| **Search** | Cmd+F with regex, case-sensitive toggle, find & replace |
| **Undo/Redo** | Transaction-based history with smart grouping |
| **Nesting** | Tab/Shift+Tab for lists and task lists, 4 indent levels |
| **Theming** | Light & dark mode via CSS custom properties |
| **Extensible** | Custom block types, toolbar buttons, block actions, slash menu items, autocomplete providers |

## Custom Block Types

```ts
import type { BlockTypePlugin } from "@inkami/blx";

const calloutPlugin: BlockTypePlugin = {
  type: "callout",
  label: "Callout",
  hasTextContent: true,
  defaultContent: () => AttributedString.empty(),
  defaultMetadata: () => ({ emoji: "💡" }),
  render(container, content, metadata) {
    // Build your DOM from the model
  },
};

editor.registerBlockType(calloutPlugin);
```

## API

### Editor

| Method | Description |
|---|---|
| `new Editor(root, options?)` | Create editor |
| `addBlock(typeOrBlock, index?)` | Add a block |
| `removeBlock(id)` | Remove a block |
| `moveBlock(id, toIndex)` | Reorder a block |
| `changeBlockType(id, newType)` | Convert block type |
| `focusBlock(id, offset?)` | Focus a block |
| `registerBlockType(plugin)` | Register a custom block type |
| `addToolbarButton(config)` | Add inline toolbar button |
| `addBlockActionItem(config)` | Add block action menu item |
| `addSlashMenuItem(config)` | Add slash menu entry |
| `addAutoCompleteProvider(provider)` | Add `[[` autocomplete provider |
| `toJSON()` / `Editor.fromJSON()` | Serialize / restore |
| `destroy()` | Clean up |

### AttributedString

| Method | Description |
|---|---|
| `AttributedString.empty()` | Create empty string |
| `AttributedString.fromPlain(text, attrs?)` | Create from plain text |
| `.insertAt(offset, text, attrs?)` | Insert text |
| `.deleteRange(start, end)` | Delete range |
| `.applyAttributes(start, end, attrs)` | Apply formatting |
| `.removeAttributes(start, end, keys)` | Remove formatting |
| `.slice(start, end)` | Extract substring |
| `.concat(other)` | Concatenate |
| `.toJSON()` / `AttributedString.fromJSON()` | Serialize / restore |

## License

MIT