API Reference
ContentAreaElement #
A custom element (<content-area>) with an API modeled after HTMLTextAreaElement. Wraps a contenteditable element and translates DOM mutations into Edit objects.
import {ContentAreaElement} from "@b9g/revise/contentarea.js";customElements.define("content-area", ContentAreaElement);
Properties #
| Property | Type | Description |
|---|---|---|
value | string | The text content of the element |
selectionStart | number | The start index of the selection |
selectionEnd | number | The end index of the selection |
selectionDirection | SelectionDirection | The direction of the selection |
Methods #
getSelectionRange(): SelectionRangeโ Returns{start, end, direction}for the current selection.setSelectionRange(start, end, direction?): voidโ Sets the selection within the content area.indexAt(node, offset): numberโ Converts a DOM position (node + offset) to a text index.nodeOffsetAt(index): [Node | null, number]โ Converts a text index to a DOM position.source(name): booleanโ Tags the next DOM mutation cycle socontentchangeevents include asourceproperty. Call this before making DOM changes from your rendering code so you can distinguish render-triggered changes from user edits. Returnstrueif the content actually changed.
Events #
contentchange โ Dispatched when the content changes. The event's detail contains:
{edit: Edit; // The edit describing the changesource: string | null; // The source tag, or null for user edits}
Call event.preventDefault() to revert the DOM mutation. This lets you apply the edit to your own state and re-render instead of letting the browser's mutation stand.
Edit #
A compact, composable data structure for representing changes to strings.
import {Edit} from "@b9g/revise/edit.js";
Instance Methods #
apply(text): stringโ Apply the edit to a string, returning the new string.invert(): Editโ Return the inverse edit. Applying the inverse undoes the original edit.compose(that): Editโ Compose two sequential edits into one. If edit A transforms text from state 1 to state 2, and edit B transforms from state 2 to state 3, thenA.compose(B)transforms directly from state 1 to state 3.normalize(): Editโ Normalize the edit by removing no-op operations.operations(): Array<Operation>โ Get the list of retain, insert, and delete operations.hasChangesBetween(start, end): booleanโ Check whether the edit modifies text in the given range.
Static Methods #
Edit.diff(text1, text2, hint?): Editโ Compute an edit that transformstext1intotext2. The optionalhintparameter is an index to improve diff performance.Edit.createBuilder(value): EditBuilderโ Create a builder for constructing edits operation-by-operation.
EditBuilder #
Fluent builder for constructing edits:
const edit = Edit.createBuilder("Hello World").retain(5).delete(6).insert(" Revise").build();edit.apply("Hello World"); // "Hello Revise"
insert(value): EditBuilderretain(length): EditBuilderdelete(length): EditBuilderconcat(edit): EditBuilderbuild(): Edit
EditHistory #
Undo/redo stack that automatically composes consecutive simple edits into groups.
import {EditHistory} from "@b9g/revise/history.js";
append(edit): voidโ Record an edit. Consecutive simple edits (single insert or delete) are composed together. Complex edits (multiple operations) trigger an automatic checkpoint.checkpoint(): voidโ Break the current edit group. Call this when the cursor moves without editing.undo(): Edit | undefinedโ Pop the undo stack and return the inverted edit. Returnsundefinedif there's nothing to undo.redo(): Edit | undefinedโ Pop the redo stack and return the edit. Returnsundefinedif there's nothing to redo.canUndo(): booleancanRedo(): boolean
Keyer #
Assigns stable integer keys to text positions and keeps them in sync as edits are applied.
import {Keyer} from "@b9g/revise/keyer.js";
keyAt(index): numberโ Get or create a stable key for the character at a given index. Returns the same key for the same position across renders, as long astransform()is called after each edit.transform(edit): voidโ Update all key positions after an edit. Must be called after every edit to keep keys in sync.
EditableState #
A framework-agnostic state coordinator that ties together value, keyer, history, and selection.
import {EditableState} from "@b9g/revise/state.js";const state = new EditableState({value: "initial text"});
Properties #
| Property | Type | Description |
|---|---|---|
value | string | The current text |
keyer | Keyer | The keyer for stable line keys |
history | EditHistory | The undo/redo history |
selection | SelectionRange | undefined | Selection computed from the last edit |
Methods #
applyEdit(edit, options?): voidโ Apply an edit, updating value, keyer, history, and selection. Options can be a source string or{source?, history?}.setValue(newValue, options?): voidโ Set a new value by computing a diff against the current value.undo(): booleanโ Undo the last edit group. Returnstrueif successful.redo(): booleanโ Redo the last undone edit group. Returnstrueif successful.canUndo(): booleancanRedo(): booleancheckpoint(): voidโ Break the current edit group.reset(value?): voidโ Reset all state (value, history, keyer, selection).