@muze-nl/cobalt
v0.1.0
Published
Range based HTML manipulation library for WYSIWYG editors.
Maintainers
Readme
Cobalt v2
A focused HTML manipulation library designed for WYSIWYG editors. Provides a clean API for parsing HTML, applying annotations (tags), and rendering back to valid HTML.
Installation
npm install @muze-nl/cobaltQuick Start
import cobalt from '@muze-nl/cobalt'
// Parse HTML
const cb = cobalt.parse('<h1>Hello</h1><p>World</p>')
// Apply annotations
cb.annotate([0, 5], '<em>')
cb.annotate([6, 11], '<strong>')
// Render back to HTML
const html = cb.toString()
console.log(html)API Reference
cobalt.parse(html: string | DocumentFragment): Cobalt
Parse an HTML string or DocumentFragment into a Cobalt instance.
const cb = cobalt.parse('<p>Hello world</p>')instance.annotate(range: [number, number], tagstring: string): this
Apply an annotation (opening or closing tag) to a range. Returns this for chaining.
cb.annotate([0, 5], '<em>')
cb.annotate([5, 10], '</em>')Parameters:
range—[start, end]pair whereend > start; empty ranges are not allowedtagstring— Opening tag like<em>,<h1 class="highlight">or closing tag like</em>
instance.list(range: [number, number]): Annotation[]
Get all annotations whose ranges overlap the given range.
const anns = cb.list([0, 5])instance.toString(): string
Render the Cobalt instance back to valid HTML.
const html = cb.toString()Properties
instance.text— Internal flat text string (includes PLACEHOLDER characters for embedded elements)instance.annotations— Array of all annotations (returns shallow copy)
Examples
Override an existing tag
const cb = cobalt.parse('<h1>Title</h1>')
cb.annotate([0, 5], '<h1 class="highlight">')
const html = cb.toString()Later annotations override earlier ones, so this results in:
<h1 class="highlight">Title</h1>Specification
Internal Representation
@muze-nl/cobalt represents HTML as:
- Text — Single flat string where text content is contiguous and embedded elements (images, videos) occupy a single character (PLACEHOLDER)
- Annotations — Ordered list of tags with ranges
[start, end]whereend > start
Range Semantics
- Ranges are inclusive of start, exclusive of end:
[start, end) - Empty ranges are forbidden:
end > startmust hold - Annotations are ordered by start offset, then by end offset
- Embedded elements take up a single character in the internal text
HTML Validity
When rendering, the library ensures output is valid HTML by:
- Removing invalid nested structures
- Closing tags early if nesting would violate HTML rules
- Later annotations override earlier conflicting ones
Testing
Run the test suite:
npm test # Run all tests
npm run test:watch # Run tests in watch mode
npm run test:coverage # Generate coverage reportLicense
MIT
