import type { MentionMarkdownRenderer } from './types'; /** * Escape characters that have meaning in markdown link/inline contexts. * Conservative — covers the chars that would break `[text](url)` and * inline emphasis when a label contains them. */ const escapeMd = (s: string): string => s.replace(/([\\\[\]()_*~`])/g, '\\$1'); /** * Built-in serializers for the `MentionConfig.renderMarkdown` callback. * * Pick one based on what consumes the markdown: * * - LLM / chat composer → `plainAt` (the default) * - Plain text export → `plainLabel` * - Web app with deep-link → `markdownLink(baseUrl)` * - Notion / Linear-style → `customUri(scheme, kind)` * - Slack-style id refs → `slackStyle` * - HTML-allowing renderer → `htmlSpan(className?)` * * Or pass a custom function — the type is just `(attrs) => string`. */ export const mentionPresets = { /** "@Label" — default, ideal for chat where LLMs read the text. */ plainAt: (({ label, id }) => `@${label || id}`) as MentionMarkdownRenderer, /** "Label" — bare label, no @ prefix. */ plainLabel: (({ label, id }) => label || id) as MentionMarkdownRenderer, /** "[@Label](baseUrl/id)" — clickable markdown link. */ markdownLink: (baseUrl: string): MentionMarkdownRenderer => ({ label, id }) => `[@${escapeMd(label || id)}](${baseUrl}${encodeURIComponent(id)})`, /** "@[Label](scheme://kind/id)" — Notion / Linear-style custom URI. */ customUri: (scheme: string, kind: string): MentionMarkdownRenderer => ({ label, id }) => `@[${escapeMd(label || id)}](${scheme}://${kind}/${encodeURIComponent(id)})`, /** "<@id>" — Slack-style id-only reference (label dropped — receivers resolve it). */ slackStyle: (({ id }) => `<@${id}>`) as MentionMarkdownRenderer, /** Inline HTML span — for products that consume markdown with raw HTML allowed. */ htmlSpan: (className = 'mention'): MentionMarkdownRenderer => ({ label, id }) => `@${escapeMd(label || id)}`, };