Migration: v0.2 → v0.3
v0.3 introduces a headless architecture with MentionController — a framework-agnostic state machine. The <Mentions> component and compound component APIs remain the same.
What Changed
- New:
MentionControllerclass in core — subscribe/getState pattern for multi-framework support - New: DOM utilities (
getPlainTextFromDOM,getMarkupFromDOM,getCursorOffset,getCaretRect,buildMentionHTML) now exported from core - New: Typed ARIA props (
InputAriaProps,ListAriaProps,ItemAriaProps) - Changed:
connect()now requires anidparameter (was optional with random fallback) - Changed:
connect()returns pure ARIA props only — no DOM event handlers - Changed: React adapter uses
useSyncExternalStoreinternally instead ofuseReducer - Changed:
buildHTMLrenamed to_buildHTML(internal).handleInputremains public. - Removed:
syncEditorfrom the hook return — editor sync is now handled internally - Removed:
QUERY_CHANGEaction type - Removed:
initialState,escapeRegexfrom public exports
Drop-in Component — No Changes
If you use the <Mentions> component, no migration needed:
// Works the same in v0.2 and v0.3
<Mentions
triggers={[{ char: "@", data: users }]}
onChange={(markup, plainText) => save(markup)}
/> Compound Components — No Changes
<Mentions.Editor>, <Mentions.List>, <Mentions.Item>, etc. all work the same.
Headless Hook — Minor Changes
// Before (v0.2):
const { handleInput, buildHTML, ... } = useMentions(opts);
<div onInput={handleInput} ... />
// After (v0.3):
const { _handleInput, _buildHTML, ... } = useMentions(opts);
<div onInput={_handleInput} ... /> The underscore prefix signals these are internal plumbing. For most custom editors, you only need editorRef, inputProps, listProps, getItemProps, and the state accessors.
Using MentionController Directly
v0.3 exposes the core controller for building adapters in other frameworks:
import { MentionController, connect } from "@skyastrall/mentions-core";
const ctrl = new MentionController({
triggers: [{ char: "@", data: users }],
callbacks: {
onChange: (markup, plainText) => console.log(markup),
onSelect: (item, trigger) => console.log(item),
},
});
// Subscribe to state changes
const unsub = ctrl.subscribe(() => {
const state = ctrl.getState();
const aria = connect(state, "my-id");
// Update your UI...
});
// Feed input changes
ctrl.handleInputChange(markup, plainText, cursor);
// Keyboard
const result = ctrl.handleKeyDown("ArrowDown");
if (result.handled) preventDefault();
// Cleanup
ctrl.destroy(); New Core Exports
// DOM utilities (for building framework adapters)
import {
getPlainTextFromDOM,
getMarkupFromDOM,
getCursorOffset,
getCaretRect,
insertTextAtCursor,
buildMentionHTML,
} from "@skyastrall/mentions-core";