docs/solutions/best-practices/link-automd-should-use-autoformat-as-a-host-while-link-owns-semantics.md
Link automd for [text](url) on the closing ) needed to ship in the current
editor kits.
The trap was obvious: either stuff link behavior into generic autoformat, or keep it app-local and duplicate link semantics. Both choices are wrong.
insertTextRules runtime shape.@platejs/autoformat.AutoformatKit could always register the rule safely without
checking whether link semantics were present in the editor.Use AutoformatPlugin as the typed-input host, but keep the matcher and
formatting logic in @platejs/link.
The rule lives in the link package and resolves only on ):
export const linkAutomdInputRule = {
trigger: ')',
resolve: (editor, { options, text }) => {
if (text !== ')' || options?.at) return;
return getLinkAutomdMatch(editor);
},
format: (editor, _context, match) => {
upsertLink(editor, {
insertNodesOptions: { at: match.range },
skipValidation: true,
text: match.text,
url: match.url,
});
},
};
The matcher stays link-owned and uses link semantics directly:
const { transformInput } = editor.getOptions(BaseLinkPlugin);
const url = transformInput ? (transformInput(rawUrl) ?? '') : rawUrl;
if (!url || !validateUrl(editor, url)) return;
if (!editor.plugins[KEYS.link]) return;
Then the current kits just host it:
AutoformatPlugin.configure({
options: {
insertTextRules: [linkAutomdInputRule],
},
});
The host/runtime and the semantics stay in the right places.
@platejs/autoformat owns the typed-character dispatch path.@platejs/link owns link parsing, normalization, validation, and insertion.That gives you the UX without smearing link behavior across the wrong package.
insertTextRules only as a host.@platejs/autoformat just
because the trigger is typed.