{"_id":"@cursortag/mention-kit","_rev":"5-578ad4011909dc91a7fe5abee31d7d51","name":"@cursortag/mention-kit","dist-tags":{"latest":"0.5.0"},"versions":{"0.1.0":{"name":"@cursortag/mention-kit","version":"0.1.0","keywords":["mention","editor","contenteditable","react","vue","typescript","headless","at-mention","rich-text"],"author":{"name":"Amay Churi"},"license":"MIT","_id":"@cursortag/mention-kit@0.1.0","maintainers":[{"name":"amaychuri","email":"churi.amay@gmail.com"}],"homepage":"https://github.com/amchuri/mention-kit#readme","bugs":{"url":"https://github.com/amchuri/mention-kit/issues"},"dist":{"shasum":"48f3809e43a7603a956824de87dc5d8539a2c4a0","tarball":"https://registry.npmjs.org/@cursortag/mention-kit/-/mention-kit-0.1.0.tgz","fileCount":23,"integrity":"sha512-F2VnbMVPv1Euyc1mFezhX08kKIy69a5NNXYTc3Juo0MBU+6Y9Zir5A05n0ycO+KQoipE2XWskBENjmm3Ij6sIQ==","signatures":[{"sig":"MEUCIA8D0wxmA0pXLVfXWpCSK3jQbw45bQ5mLX1cXlFsUMQDAiEAxz+ab0j7/qHAPX1IjMU7NNTy1z9yMc3OX7CaT9m6jyI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":735830},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./vue":{"types":"./dist/vue.d.ts","import":"./dist/vue.mjs","require":"./dist/vue.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.js"}},"gitHead":"a4e3957beee3a0dbcba48a0d1a54867285490dd8","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest run","build":"tsup","format":"prettier --write .","prepare":"husky","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"yarn build && yarn typecheck"},"_npmUser":{"name":"amaychuri","email":"churi.amay@gmail.com"},"repository":{"url":"git+https://github.com/amchuri/mention-kit.git","type":"git"},"_npmVersion":"11.6.0","description":"Headless zero-dependency TypeScript mention editor for React, Vue 3, and vanilla JS","directories":{},"lint-staged":{"*.{ts,tsx}":["prettier --write"],"*.{js,json,md}":["prettier --write"]},"sideEffects":false,"_nodeVersion":"23.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.32","tsup":"^8.0.0","husky":"^9.1.7","react":"^19.2.5","vitest":"^2.0.0","prettier":"^3.8.2","happy-dom":"^20.9.0","typescript":"^5.0.0","@types/node":"^22.0.0","lint-staged":"^16.4.0","@types/react":"^19.2.14","@vitest/coverage-v8":"^2.0.0","@testing-library/vue":"^8.1.0","@testing-library/react":"^16.3.2"},"peerDependencies":{"vue":">=3","react":">=17"},"peerDependenciesMeta":{"vue":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mention-kit_0.1.0_1776725526046_0.3940984779068888","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@cursortag/mention-kit","version":"0.1.1","keywords":["mention","editor","contenteditable","react","vue","typescript","headless","at-mention","rich-text"],"author":{"name":"Amay Churi"},"license":"MIT","_id":"@cursortag/mention-kit@0.1.1","maintainers":[{"name":"amaychuri","email":"churi.amay@gmail.com"}],"homepage":"https://github.com/amchuri/mention-kit#readme","bugs":{"url":"https://github.com/amchuri/mention-kit/issues"},"dist":{"shasum":"9697516c8d48b11089f6c891d614fd79f5a6120a","tarball":"https://registry.npmjs.org/@cursortag/mention-kit/-/mention-kit-0.1.1.tgz","fileCount":23,"integrity":"sha512-wiF752YSFTcPODVw5NmTFHPiNUerEhF8RyxyKPzlhJCHaoo72jLOHAiDgrqWmsam4zTr96LROTSbwhYBpOpSOw==","signatures":[{"sig":"MEUCIQDLouVjMgf+rVlkzAKVEbMvaJONxMX/Yb+twEOOHpK7YwIgKkWIsxeLsh0kEykWcjRKyRSWDhj6eKljobsHf4T/X9M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":758041},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./vue":{"types":"./dist/vue.d.ts","import":"./dist/vue.mjs","require":"./dist/vue.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.js"}},"gitHead":"fc5f30f4539dcf779f18e504a73943d79438b63d","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest run","build":"tsup","format":"prettier --write .","prepare":"husky","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"yarn build && yarn typecheck"},"_npmUser":{"name":"amaychuri","email":"churi.amay@gmail.com"},"repository":{"url":"git+https://github.com/amchuri/mention-kit.git","type":"git"},"_npmVersion":"11.6.0","description":"Headless zero-dependency TypeScript mention editor for React, Vue 3, and vanilla JS","directories":{},"lint-staged":{"*.{ts,tsx}":["prettier --write"],"*.{js,json,md}":["prettier --write"]},"sideEffects":false,"_nodeVersion":"23.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.32","tsup":"^8.0.0","husky":"^9.1.7","react":"^19.2.5","vitest":"^2.0.0","prettier":"^3.8.2","happy-dom":"^20.9.0","typescript":"^5.0.0","@types/node":"^22.0.0","lint-staged":"^16.4.0","@types/react":"^19.2.14","@vitest/coverage-v8":"^2.0.0","@testing-library/vue":"^8.1.0","@testing-library/react":"^16.3.2"},"peerDependencies":{"vue":">=3","react":">=17"},"peerDependenciesMeta":{"vue":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mention-kit_0.1.1_1776767704157_0.6375996411344513","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@cursortag/mention-kit","version":"0.1.2","keywords":["mention","editor","contenteditable","react","vue","typescript","headless","at-mention","rich-text"],"author":{"name":"Amay Churi"},"license":"MIT","_id":"@cursortag/mention-kit@0.1.2","maintainers":[{"name":"amaychuri","email":"churi.amay@gmail.com"}],"homepage":"https://github.com/amchuri/mention-kit#readme","bugs":{"url":"https://github.com/amchuri/mention-kit/issues"},"dist":{"shasum":"c8a861bebf0624ac00ee3f280f54cea7f8f2ad58","tarball":"https://registry.npmjs.org/@cursortag/mention-kit/-/mention-kit-0.1.2.tgz","fileCount":23,"integrity":"sha512-MFG+rt3NrLrKnV2yvIFAlKBObPdY0RKTd1CctB1Ye0pn7SXjBVst6PKekdVb//9Ce0gCDo6/tL2+F9IGMB5uKQ==","signatures":[{"sig":"MEUCIQCFlN3K0W7u4o0gXoPHDUUq4/0qDBrJYM20AP78/LCqPQIgE0I2GUFq+mxmWPsf+PthvGe6/s9/FNRgQbDPnhUaRWM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":801525},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./vue":{"types":"./dist/vue.d.ts","import":"./dist/vue.mjs","require":"./dist/vue.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.js"}},"gitHead":"6a03f7866d057d6faab36d86ebbdabda58cd0231","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest run","build":"tsup","format":"prettier --write .","prepare":"husky","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"yarn build && yarn typecheck"},"_npmUser":{"name":"amaychuri","email":"churi.amay@gmail.com"},"repository":{"url":"git+https://github.com/amchuri/mention-kit.git","type":"git"},"_npmVersion":"11.6.0","description":"Headless zero-dependency TypeScript mention editor for React, Vue 3, and vanilla JS","directories":{},"lint-staged":{"*.{ts,tsx}":["prettier --write"],"*.{js,json,md}":["prettier --write"]},"sideEffects":false,"_nodeVersion":"23.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.32","tsup":"^8.0.0","husky":"^9.1.7","react":"^19.2.5","vitest":"^2.0.0","prettier":"^3.8.2","happy-dom":"^20.9.0","typescript":"^5.0.0","@types/node":"^22.0.0","lint-staged":"^16.4.0","@types/react":"^19.2.14","@vitest/coverage-v8":"^2.0.0","@testing-library/vue":"^8.1.0","@testing-library/react":"^16.3.2"},"peerDependencies":{"vue":">=3","react":">=17"},"peerDependenciesMeta":{"vue":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mention-kit_0.1.2_1776770747314_0.3742916527455322","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@cursortag/mention-kit","version":"0.2.1","keywords":["mention","editor","contenteditable","react","vue","typescript","headless","at-mention","rich-text"],"author":{"name":"Amay Churi"},"license":"MIT","_id":"@cursortag/mention-kit@0.2.1","maintainers":[{"name":"amaychuri","email":"churi.amay@gmail.com"}],"homepage":"https://github.com/amchuri/mention-kit#readme","bugs":{"url":"https://github.com/amchuri/mention-kit/issues"},"dist":{"shasum":"33b8cc1a13aba93e38b2869583ab3fcad7e02969","tarball":"https://registry.npmjs.org/@cursortag/mention-kit/-/mention-kit-0.2.1.tgz","fileCount":24,"integrity":"sha512-HZSCciDjjkyIdU8jhjV2uUodL0PD5a3CoHsnVPnXkXvxUvr758Wb1/hGk21y+T01cnnQ7bQZ79l8EdvTNbcArQ==","signatures":[{"sig":"MEQCIEm86iC6cWiOJGMDkXKDBKCdWx/NliMzy/UcPl9M59VlAiA0eb7F6jK1qA3qj2IANK5ey74Ird/qiMKK/oRESKUxIA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1546158},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./vue":{"types":"./dist/vue.d.ts","import":"./dist/vue.mjs","require":"./dist/vue.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.js"}},"gitHead":"e8a5fe5ec89377c472219c1093fe78f5fe79b07f","scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"vitest run","build":"tsup","format":"prettier --write .","prepare":"husky","release":"npm publish --access public --registry https://registry.npmjs.org","typecheck":"tsc --noEmit","test:watch":"vitest","release:dry":"npm publish --dry-run --access public --registry https://registry.npmjs.org","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"yarn build && yarn typecheck && yarn test"},"_npmUser":{"name":"amaychuri","email":"churi.amay@gmail.com"},"repository":{"url":"git+https://github.com/amchuri/mention-kit.git","type":"git"},"_npmVersion":"11.6.0","description":"Headless zero-dependency TypeScript mention editor for React, Vue 3, and vanilla JS","directories":{},"lint-staged":{"*.{ts,tsx}":["prettier --write"],"*.{js,json,md}":["prettier --write"]},"sideEffects":false,"_nodeVersion":"23.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.32","tsup":"^8.0.0","husky":"^9.1.7","react":"^19.2.5","vitest":"^2.0.0","prettier":"^3.8.2","happy-dom":"^20.9.0","typescript":"^5.0.0","@types/node":"^22.0.0","lint-staged":"^16.4.0","@types/react":"^19.2.14","@vitest/coverage-v8":"^2.0.0","@testing-library/vue":"^8.1.0","@testing-library/react":"^16.3.2"},"peerDependencies":{"vue":">=3","react":">=17"},"peerDependenciesMeta":{"vue":{"optional":true},"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/mention-kit_0.2.1_1783164299600_0.06477563985957047","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@cursortag/mention-kit","version":"0.5.0","description":"Headless zero-dependency TypeScript mention editor for React, Vue 3, and vanilla JS","author":{"name":"Amay Churi"},"license":"MIT","keywords":["mention","editor","contenteditable","react","vue","typescript","headless","at-mention","rich-text"],"repository":{"type":"git","url":"git+https://github.com/amchuri/mention-kit.git"},"homepage":"https://github.com/amchuri/mention-kit#readme","bugs":{"url":"https://github.com/amchuri/mention-kit/issues"},"main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.mjs","require":"./dist/react.js"},"./vue":{"types":"./dist/vue.d.ts","import":"./dist/vue.mjs","require":"./dist/vue.js"}},"sideEffects":false,"peerDependencies":{"react":">=17","vue":">=3"},"peerDependenciesMeta":{"react":{"optional":true},"vue":{"optional":true}},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","lint":"eslint src --ext .ts,.tsx","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","format":"prettier --write .","format:check":"prettier --check .","prepublishOnly":"yarn build && yarn typecheck && yarn test","release":"npm publish --access public --registry https://registry.npmjs.org","release:dry":"npm publish --dry-run --access public --registry https://registry.npmjs.org","prepare":"husky"},"lint-staged":{"*.{ts,tsx}":["prettier --write"],"*.{js,json,md}":["prettier --write"]},"devDependencies":{"@testing-library/dom":"^10","@testing-library/react":"^16.3.2","@testing-library/vue":"^8.1.0","@types/node":"^22.0.0","@types/react":"^19.2.14","@vitest/coverage-v8":"^3","happy-dom":"^20.10.6","husky":"^9.1.7","lint-staged":"^16.4.0","prettier":"^3.8.2","react":"19.2.7","react-dom":"19.2.7","tsup":"^8.5.1","typescript":"^5.0.0","vitest":"^3","vue":"^3.5.32"},"resolutions":{"postcss":"^8.5.10","brace-expansion":"^2.0.2","js-cookie":"^3.0.7","esbuild":"^0.28.1"},"engines":{"node":">=18"},"publishConfig":{"access":"public"},"_id":"@cursortag/mention-kit@0.5.0","gitHead":"684e3f3e862806ea4cedbce619bcc77586abff52","_nodeVersion":"23.10.0","_npmVersion":"11.6.0","dist":{"integrity":"sha512-K8k0h3BQCZT/+2tPv4CxeG41A+cJYniii/ouhiGlT2VkPQWkF98GgsvL4l/PS49Mz1H9dZPpmBTQAR5dB59bfg==","shasum":"8d177b6544af1c90b5c5ccfc27f5165fac2650ef","tarball":"https://registry.npmjs.org/@cursortag/mention-kit/-/mention-kit-0.5.0.tgz","fileCount":24,"unpackedSize":1806562,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIE6Rux7E/JH8Hgm6/9qLNuMvli4oAGAOWWkgCfUW0eUHAiBlrz2vUXap41P69SMLH9aXAiYtCcYQnx6QoV3Io6LEGA=="}]},"_npmUser":{"name":"amaychuri","email":"churi.amay@gmail.com"},"directories":{},"maintainers":[{"name":"amaychuri","email":"churi.amay@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mention-kit_0.5.0_1783179717155_0.23146281690143944"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-20T22:52:05.934Z","modified":"2026-07-04T15:41:57.466Z","0.1.0":"2026-04-20T22:52:06.257Z","0.1.1":"2026-04-21T10:35:04.412Z","0.1.2":"2026-04-21T11:25:47.590Z","0.2.1":"2026-07-04T11:24:59.757Z","0.5.0":"2026-07-04T15:41:57.321Z"},"bugs":{"url":"https://github.com/amchuri/mention-kit/issues"},"author":{"name":"Amay Churi"},"license":"MIT","homepage":"https://github.com/amchuri/mention-kit#readme","keywords":["mention","editor","contenteditable","react","vue","typescript","headless","at-mention","rich-text"],"repository":{"type":"git","url":"git+https://github.com/amchuri/mention-kit.git"},"description":"Headless zero-dependency TypeScript mention editor for React, Vue 3, and vanilla JS","maintainers":[{"name":"amaychuri","email":"churi.amay@gmail.com"}],"readme":"# mention-kit\n\n<p align=\"center\">\n  <img src=\"media/banner.svg\" alt=\"mention-kit — headless mention editor\" width=\"100%\" />\n</p>\n\n<p align=\"center\">\n  <strong>Headless, zero-dependency TypeScript mention editor</strong><br/>\n  Built on <code>contentEditable</code> — works with React, Vue 3, or vanilla JS.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/@cursortag/mention-kit\"><img src=\"https://img.shields.io/npm/v/@cursortag/mention-kit?color=7c3aed&label=npm\" alt=\"npm version\" /></a>\n  <a href=\"https://github.com/amchuri/mention-kit/blob/main/LICENSE\"><img src=\"https://img.shields.io/npm/l/@cursortag/mention-kit?color=059669\" alt=\"license\" /></a>\n  <a href=\"https://www.npmjs.com/package/@cursortag/mention-kit\"><img src=\"https://img.shields.io/npm/dt/@cursortag/mention-kit?color=0891b2\" alt=\"downloads\" /></a>\n  <a href=\"https://amchuri.github.io/mention-kit/\"><img src=\"https://img.shields.io/badge/demo-live-d97706\" alt=\"demo\" /></a>\n</p>\n\n---\n\n## See it in action\n\n**▶ [Live demo](https://amchuri.github.io/mention-kit/)** — interactive React + Vue examples: multiple triggers, async search, creatable tags, hovercards, themes, and a rendered preview of each submitted comment.\n\n<!--\n  DEMO MEDIA (drop-in — recorded GIFs render here once added; nothing breaks until then).\n  Record ~8–12s clips against the live demo (e.g. with Kap / LICEcap / QuickTime), 640px wide,\n  save under media/, and uncomment the matching line:\n\n  ![Overview](media/demo.gif)\n  ![Multiple triggers + creatable tags](media/triggers.gif)\n  ![Async / commands](media/async.gif)\n  ![Hovercards + themes](media/hovercards.gif)\n-->\n\n---\n\n## Features\n\n- **Zero dependencies** — no framework required for the core\n- **Dual CJS + ESM** builds with full TypeScript types\n- **React** — `<MentionInput />` component and `useMentionEditor()` hook\n- **Vue 3** — `<MentionInput />` component and `useMentionEditor()` composable\n- **Headless** — renders a plain `<div>`, style with Tailwind / MUI / shadcn / anything\n- **Multiple triggers** — `@` people, `#` tags, `/` commands, `:` emoji, each with its own data, colors, and filter; tags render as label pills, people as avatars\n- **Async suggestions** — fetch results from a server as you type (debounced, with a loading state)\n- **Creatable items** — offer a \"Create …\" row so users can add a new `#tag` on the fly\n- **Slash commands** — a trigger can run an action (insert text, open a dialog) instead of inserting a chip\n- **Hover user-info cards** — hover a mention to reveal avatar, meta, and copyable fields\n- **Themeable** — `--mk-*` CSS variables (light/dark presets) or a `theme` object; per-user or shared palette\n- **Controlled or uncontrolled** — drive it with a `value` prop, or leave it self-managed\n- **Accessible** — ARIA combobox semantics (`aria-expanded` / `aria-controls` / `aria-activedescendant`), keyboard-first\n- **Persistence format** — `@{userId}` / `#{tagId}` tokens for easy storage and re-render\n\n---\n\n## Installation\n\n```bash\n# npm\nnpm install @cursortag/mention-kit\n\n# yarn\nyarn add @cursortag/mention-kit\n\n# pnpm\npnpm add @cursortag/mention-kit\n```\n\nReact and Vue are optional peer dependencies — install only what you use:\n\n```bash\n# React\nyarn add @cursortag/mention-kit react\n\n# Vue\nyarn add @cursortag/mention-kit vue\n```\n\n---\n\n## Quick start\n\n### React\n\n```tsx\nimport { MentionInput } from '@cursortag/mention-kit/react';\n\nconst users = [\n  { id: 'u1', name: 'Alice Johnson', meta: 'Engineering' },\n  { id: 'u2', name: 'Bob Smith', meta: 'Design' },\n];\n\nfunction CommentBox() {\n  return (\n    <MentionInput\n      users={users}\n      placeholder=\"Write a comment… (@ to mention)\"\n      onSubmit={(text) => console.log(text)}\n      className=\"rounded border p-2 min-h-[80px]\"\n    />\n  );\n}\n```\n\n### Vue 3\n\n```vue\n<script setup lang=\"ts\">\nimport { MentionInput } from '@cursortag/mention-kit/vue';\n\nconst users = [\n  { id: 'u1', name: 'Alice Johnson', meta: 'Engineering' },\n  { id: 'u2', name: 'Bob Smith', meta: 'Design' },\n];\n</script>\n\n<template>\n  <MentionInput\n    :users=\"users\"\n    placeholder=\"Write a comment…\"\n    class=\"rounded border p-2 min-h-[80px]\"\n    @submit=\"(text) => console.log(text)\"\n  />\n</template>\n```\n\n### Vanilla JS\n\n```ts\nimport { createMentionEditor } from '@cursortag/mention-kit';\n\nconst editor = createMentionEditor({\n  container: document.getElementById('editor')!,\n  users: [\n    { id: 'u1', name: 'Alice Johnson' },\n    { id: 'u2', name: 'Bob Smith' },\n  ],\n  placeholder: 'Write a comment…',\n  onSubmit: (text, { mentionedUsers }) => {\n    console.log(text); // \"Hey @Alice Johnson, check this\"\n    console.log(mentionedUsers); // [{ id: 'u1', name: 'Alice Johnson', ... }]\n  },\n});\n\n// Cleanup\neditor.destroy();\n```\n\n---\n\n## Callback signature\n\nAll callbacks receive `text` as the first argument and an optional `meta` object as the second:\n\n```ts\nonChange?: (text: string, meta: EditorCallbackMeta) => void;\nonSubmit?: (text: string, meta: EditorCallbackMeta) => void;\n```\n\n| Argument              | Type            | Description                                          |\n| --------------------- | --------------- | ---------------------------------------------------- |\n| `text`                | `string`        | Plain text with mentions as `@displayName`           |\n| `meta.nodes`          | `EditorNode[]`  | Full structured document (for storage/serialization) |\n| `meta.mentionedUsers` | `MentionUser[]` | De-duplicated list of mentioned users                |\n\n**Simple usage** — just use `text`:\n\n```tsx\nonSubmit={(text) => saveComment(text)}\n```\n\n**Power-user usage** — destructure `meta` when needed:\n\n```tsx\nonSubmit={(text, { nodes, mentionedUsers }) => {\n  saveComment(text);\n  notifyUsers(mentionedUsers.map(u => u.id));\n  storeNodes(nodes); // for re-rendering later\n}}\n```\n\n---\n\n## React\n\n### `<MentionInput />` — drop-in component\n\n```tsx\nimport { useRef } from 'react';\nimport {\n  MentionInput,\n  type MentionEditorInstance,\n} from '@cursortag/mention-kit/react';\n\nfunction CommentBox() {\n  const ref = useRef<MentionEditorInstance>(null);\n\n  return (\n    <>\n      <MentionInput\n        ref={ref}\n        users={users}\n        placeholder=\"Write a comment…\"\n        onSubmit={(text, { mentionedUsers }) => {\n          console.log(text, mentionedUsers);\n          ref.current?.clear();\n        }}\n        className=\"rounded border border-gray-300 p-3 min-h-[80px] text-sm\"\n      />\n      <button onClick={() => ref.current?.clear()}>Clear</button>\n    </>\n  );\n}\n```\n\n**Props**\n\n| Prop             | Type                              | Description                       |\n| ---------------- | --------------------------------- | --------------------------------- |\n| `users`          | `MentionUser[]`                   | List of mentionable users         |\n| `placeholder`    | `string`                          | Placeholder text                  |\n| `onSubmit`       | `(text, meta) => void`            | Called on `Enter`                 |\n| `onChange`       | `(text, meta) => void`            | Called on every edit              |\n| `disabled`       | `boolean`                         | Disables editing                  |\n| `maxSuggestions` | `number`                          | Max dropdown items (default `8`)  |\n| `palette`        | `string[]`                        | Fallback colors for user chips    |\n| `defaultNodes`   | `EditorNode[]`                    | Initial content                   |\n| `className`      | `string`                          | CSS class on the container div    |\n| `style`          | `CSSProperties`                   | Inline style on the container div |\n| `renderUser`     | `(user, selected) => HTMLElement` | Custom dropdown row renderer      |\n\n**Ref methods** (`useRef<MentionEditorInstance>`)\n\n| Method                   | Description                                     |\n| ------------------------ | ----------------------------------------------- |\n| `getNodes()`             | Returns current document as `EditorNode[]`      |\n| `setNodes(nodes, emit?)` | Replace content; pass `true` to fire `onChange` |\n| `clear()`                | Clear all content                               |\n| `focus()`                | Move focus into the editor                      |\n| `setPlaceholder(text)`   | Update placeholder after mount                  |\n\n---\n\n### `useMentionEditor()` — hook for custom containers\n\nUse this when you need to embed the editor inside a MUI `<Box>`, shadcn `<Textarea>`, or any element you control.\n\n```tsx\nimport { useMentionEditor } from '@cursortag/mention-kit/react';\n\nfunction MyEditor() {\n  const editor = useMentionEditor({\n    users,\n    onChange: (text) => console.log(text),\n    onSubmit: (text) => {\n      save(text);\n      editor.clear();\n    },\n  });\n\n  return (\n    <div\n      ref={editor.containerRef}\n      className=\"rounded border border-gray-300 p-3 min-h-[80px]\"\n    />\n  );\n}\n```\n\n**MUI example**\n\n```tsx\n<Box\n  ref={editor.containerRef}\n  sx={{\n    border: 1,\n    borderColor: 'divider',\n    borderRadius: 1,\n    p: 1.5,\n    minHeight: 80,\n  }}\n/>\n```\n\n**shadcn / Radix example**\n\n```tsx\n<div\n  ref={editor.containerRef}\n  className={cn(\n    'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm',\n    'ring-offset-background focus-within:ring-2 focus-within:ring-ring',\n  )}\n/>\n```\n\n**Returns**\n\n| Field                    | Type                  | Description                      |\n| ------------------------ | --------------------- | -------------------------------- |\n| `containerRef`           | `Ref<HTMLDivElement>` | Attach to your container element |\n| `getNodes()`             | `() => EditorNode[]`  | Read current content             |\n| `setNodes(nodes, emit?)` | `function`            | Replace content                  |\n| `clear()`                | `function`            | Clear all content                |\n| `focus()`                | `function`            | Focus the editor                 |\n| `setPlaceholder(text)`   | `function`            | Update placeholder               |\n\n---\n\n## Vue 3\n\n### `<MentionInput />` — drop-in component\n\n```vue\n<script setup lang=\"ts\">\nimport { ref } from 'vue';\nimport {\n  MentionInput,\n  type MentionEditorInstance,\n} from '@cursortag/mention-kit/vue';\n\nconst editorRef = ref<MentionEditorInstance | null>(null);\n</script>\n\n<template>\n  <MentionInput\n    ref=\"editorRef\"\n    :users=\"users\"\n    placeholder=\"Write a comment…\"\n    class=\"rounded border border-gray-300 p-3 min-h-[80px] text-sm\"\n    @submit=\"\n      (text) => {\n        save(text);\n        editorRef?.clear();\n      }\n    \"\n    @change=\"(text) => console.log(text)\"\n  />\n  <button @click=\"editorRef?.clear()\">Clear</button>\n</template>\n```\n\n**Props**\n\n| Prop             | Type            | Description                      |\n| ---------------- | --------------- | -------------------------------- |\n| `users`          | `MentionUser[]` | List of mentionable users        |\n| `placeholder`    | `string`        | Placeholder text                 |\n| `disabled`       | `boolean`       | Disables editing                 |\n| `maxSuggestions` | `number`        | Max dropdown items (default `8`) |\n| `palette`        | `string[]`      | Fallback colors for user chips   |\n| `defaultNodes`   | `EditorNode[]`  | Initial content                  |\n\n**Emits**\n\n| Event    | Arguments                                  | Description         |\n| -------- | ------------------------------------------ | ------------------- |\n| `change` | `(text: string, meta: EditorCallbackMeta)` | Fires on every edit |\n| `submit` | `(text: string, meta: EditorCallbackMeta)` | Fires on `Enter`    |\n\n**Exposed methods** (via template ref)\n\nSame as the React ref methods — `getNodes`, `setNodes`, `clear`, `focus`, `setPlaceholder`.\n\n---\n\n### `useMentionEditor()` — composable for custom containers\n\n```vue\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { useMentionEditor } from '@cursortag/mention-kit/vue';\n\nconst editor = useMentionEditor({\n  get users() {\n    return filteredUsers.value;\n  },\n  onSubmit: (text) => {\n    save(text);\n    editor.clear();\n  },\n});\n</script>\n\n<template>\n  <div ref=\"editor.containerRef\" class=\"rounded border p-3 min-h-[80px]\" />\n</template>\n```\n\n**Element Plus example**\n\n```vue\n<el-input :ref=\"editor.containerRef\" type=\"textarea\" :rows=\"3\" />\n```\n\n**Vuetify example**\n\n```vue\n<v-textarea :ref=\"editor.containerRef\" variant=\"outlined\" />\n```\n\n---\n\n## Utility functions\n\nThese are standalone exports — use them anywhere, no editor instance needed.\n\n### `serializeToText(nodes)`\n\nConverts an `EditorNode[]` to a plain text string. Mentions become `@displayName`.\n\n```ts\nimport { serializeToText } from '@cursortag/mention-kit';\n\nconst text = serializeToText(nodes);\n// \"Hey @Alice Johnson, check this PR\"\n```\n\n### `serializeToMarkdown(nodes)`\n\nConverts an `EditorNode[]` to a markdown-style string with user IDs. Best for storage — you can re-render it later.\n\n```ts\nimport { serializeToMarkdown } from '@cursortag/mention-kit';\n\nconst md = serializeToMarkdown(nodes);\n// \"Hey @[Alice Johnson](u1), check this PR\"\n```\n\n### `renderCommentMessage(message, users, palette?)`\n\nTakes a stored `@{userId}` message string and returns an array of text strings and `HTMLElement` chips. Use this to display stored messages in a non-editable context.\n\n```ts\nimport { renderCommentMessage } from '@cursortag/mention-kit';\n\nconst stored = 'Great work @{u1}, please check with @{u2}';\nconst parts = renderCommentMessage(stored, users);\n// [ 'Great work ', <span>Alice Johnson</span>, ', please check with ', <span>Bob Smith</span>, '' ]\n\n// Append to DOM\nparts.forEach((part) => {\n  container.appendChild(\n    typeof part === 'string' ? document.createTextNode(part) : part,\n  );\n});\n```\n\n### `renderCommentMessageToHTML(message, users, palette?)`\n\nSame as `renderCommentMessage`, but returns a single HTML string. Great for emails, server-side rendering, or `dangerouslySetInnerHTML`.\n\n```ts\nimport { renderCommentMessageToHTML } from '@cursortag/mention-kit';\n\nconst html = renderCommentMessageToHTML('Hey @{u1}!', users);\n// '<span style=\"...\">Alice Johnson</span>'\n\n// In React (use with caution):\n<div dangerouslySetInnerHTML={{ __html: html }} />\n```\n\n### `DEFAULT_MENTION_PALETTE`\n\nThe built-in array of hex colors used when a user has no `color` property. Export it to extend or override.\n\n```ts\nimport { DEFAULT_MENTION_PALETTE } from '@cursortag/mention-kit';\n\n// Extend with your brand colors\nconst palette = [...DEFAULT_MENTION_PALETTE, '#f59e0b', '#ec4899'];\n\ncreateMentionEditor({ ..., palette });\n```\n\n---\n\n## Persistence\n\nMentions are stored as `@{userId}` tokens. Save the serialised string and re-render it later:\n\n```ts\nimport { serializeToMarkdown, renderCommentMessageToHTML } from '@cursortag/mention-kit';\n\n// 1. User submits a comment — store the markdown\nonSubmit={(text, { nodes }) => {\n  const stored = serializeToMarkdown(nodes);\n  // \"Great work @[Alice Johnson](u1), please check with @[Bob Smith](u2).\"\n  db.save(stored);\n}}\n\n// 2. Later, re-render the stored string to HTML\nconst html = renderCommentMessageToHTML(stored, users);\n```\n\n---\n\n## Keyboard shortcuts\n\n| Key             | Action                              |\n| --------------- | ----------------------------------- |\n| `@`             | Open mention dropdown               |\n| `↑` / `↓`       | Navigate dropdown                   |\n| `Enter` / `Tab` | Select highlighted user             |\n| `Escape`        | Close dropdown                      |\n| `Enter`         | Submit (calls `onSubmit`)           |\n| `Shift+Enter`   | Insert newline                      |\n| `Backspace`     | On chip: shrinks name, then removes |\n\n---\n\n## Custom palette\n\n```ts\nimport { DEFAULT_MENTION_PALETTE } from '@cursortag/mention-kit';\n\n// Custom palette\ncreateMentionEditor({ ..., palette: ['#e11d48', '#0ea5e9', '#16a34a'] });\n\n// Extend the default\ncreateMentionEditor({ ..., palette: [...DEFAULT_MENTION_PALETTE, '#f59e0b'] });\n\n// Per-user color (takes precedence over palette)\nconst users = [{ id: 'u1', name: 'Alice', color: '#7c3aed' }];\n```\n\n---\n\n## Multiple triggers, async & custom filter\n\nBy default the editor uses a single `@` trigger backed by `users`. Pass\n`triggers` to handle several — `@` people, `#` tags, `/` commands, `:` emoji —\neach with its own data source, colors, and matching. `triggers` fully replaces\nthe `users` shorthand.\n\n```ts\ncreateMentionEditor({\n  container,\n  get users() {\n    return [];\n  }, // ignored when `triggers` is set\n  triggers: [\n    { trigger: '@', items: people, color: '#7c3aed' },\n    { trigger: '#', items: tags, color: '#0891b2', label: 'Add a tag' },\n    {\n      // Async search — items is a function returning a Promise.\n      trigger: '/',\n      debounce: 200, // wait 200ms after typing stops\n      serverFiltered: true, // results are already filtered server-side\n      items: async (query) => {\n        const res = await fetch(`/api/commands?q=${query}`);\n        return res.json(); // MentionItem[]  ({ id, name, ... })\n      },\n    },\n  ],\n});\n```\n\nEach trigger accepts:\n\n| Field            | Type                                           | Default             | Description                               |\n| ---------------- | ---------------------------------------------- | ------------------- | ----------------------------------------- |\n| `trigger`        | `string`                                       | —                   | Single trigger char (`@`, `#`, `/`, `:`)  |\n| `items`          | `MentionItem[] \\| (query) => Items \\| Promise` | —                   | Static list or a (async) search function  |\n| `filter`         | `(item, query) => boolean`                     | `name.includes`     | Custom matcher                            |\n| `serverFiltered` | `boolean`                                      | `false`             | Skip local filtering (source pre-filters) |\n| `debounce`       | `number`                                       | `0`                 | ms to debounce async `items()`            |\n| `minChars`       | `number`                                       | `0`                 | Min query length before opening           |\n| `allowSpaces`    | `boolean`                                      | `false`             | Allow spaces inside the query             |\n| `maxSuggestions` | `number`                                       | top-level           | Max rows shown                            |\n| `color`          | `string`                                       | palette             | Default chip color for this trigger       |\n| `label`          | `string`                                       | `\"Mention someone\"` | Dropdown header                           |\n| `renderItem`     | `(item, selected) => HTMLElement`              | —                   | Custom row renderer                       |\n| `onSelect`       | `(item, ctx) => void`                          | —                   | Slash-command mode (see below)            |\n| `allowCreate`    | `boolean`                                      | `false`             | Offer a \"Create …\" row for new items      |\n| `onCreate`       | `(query) => MentionItem`                       | —                   | Build the created item (implies create)   |\n| `createLabel`    | `(query) => string`                            | `Create \"<q>\"`      | Label for the \"Create …\" row              |\n\n### Create new items (`allowCreate` / `onCreate`)\n\nSet `allowCreate` (or provide `onCreate`) and, when the query matches no existing\nitem, the dropdown offers a **\"Create …\"** row. Selecting it inserts a brand-new\nmention chip — perfect for letting users add a `#tag` that doesn't exist yet.\n\n```ts\n{\n  trigger: '#',\n  items: tags,\n  allowCreate: true,\n  // Optional — mint your own id/color (default is { id: query, name: query }):\n  onCreate: (query) => ({ id: `tag:${query}`, name: query, color: '#0891b2' }),\n}\n```\n\nThe created item is inserted like any other mention and persists as\n`#{tag:query}`. To re-render stored content containing created items, include\nthem in `triggerItems` (accumulate them from `onCreate`).\n\n### Slash commands (`onSelect`)\n\nGive a trigger an `onSelect` handler and selecting an item **runs the callback\ninstead of inserting a chip** — the typed trigger text is removed first. Use\n`ctx.insertText(text)` to insert content at the caret. Perfect for `/` commands:\n\n```ts\n{\n  trigger: '/',\n  items: [\n    { id: 'assign', name: 'assign', meta: 'Assign to a teammate' },\n    { id: 'date',   name: 'date',   meta: 'Insert today' },\n  ],\n  onSelect: (item, ctx) => {\n    if (item.id === 'date') ctx.insertText(new Date().toISOString().slice(0, 10));\n    else openAssignDialog();          // any side effect\n  },\n}\n```\n\nMentions remember their trigger, so they persist as `<trigger>{id}` (e.g.\n`#{t1}`) and round-trip. When re-rendering stored content that uses non-`@`\ntriggers, pass `triggerItems` so ids resolve to names:\n\n```ts\n// vanilla / Vue\nrenderCommentMessage(stored, people, palette, [{ trigger: '#', items: tags }]);\nparsePersist(stored, people, [{ trigger: '#', items: tags }]);\n\n// React\n<RenderedMessage message={stored} users={people} triggerItems={[{ trigger: '#', items: tags }]} />\n```\n\nReact & Vue `<MentionInput>` accept `triggers` as a prop.\n\n---\n\n## Controlled value\n\nDrive the editor from state with a `value` prop (a persisted `@{id}` string).\nPair it with `onChange` + `serializeToPersist`. The editor only re-seeds when\n`value` differs from its current content, so typing keeps its caret.\n\n```tsx\nimport { MentionInput, serializeToPersist } from '@cursortag/mention-kit/react';\n\nfunction Controlled() {\n  const [value, setValue] = useState('Hi @{u1}');\n  return (\n    <MentionInput\n      users={users}\n      value={value}\n      onChange={(_text, { nodes }) => setValue(serializeToPersist(nodes))}\n    />\n  );\n}\n```\n\n```vue\n<!-- Vue -->\n<MentionInput\n  :users=\"users\"\n  :value=\"value\"\n  @change=\"(_t, { nodes }) => (value = serializeToPersist(nodes))\"\n/>\n```\n\nWorks on the hook / composable too. Uncontrolled? Use `defaultValue` /\n`defaultNodes` instead.\n\n---\n\n## Accessibility\n\nThe editor follows the ARIA combobox pattern. The editable exposes\n`role=\"textbox\"`, `aria-multiline`, and `aria-autocomplete=\"list\"`, and while the\nsuggestion list is open it sets `aria-expanded`, `aria-controls` (the listbox\nid), and `aria-activedescendant` (the highlighted option id). The dropdown is a\n`role=\"listbox\"` with `role=\"option\"` rows. Keyboard: `↑↓` navigate, `Enter` /\n`Tab` select, `Escape` closes.\n\n---\n\n## Hover user-info cards\n\nReveal a rich profile card when a reader hovers a mention in a **rendered\nmessage** — avatar, meta, and any extra fields, each optionally copyable.\n\nGive users the info you want to surface:\n\n```ts\nconst users = [\n  {\n    id: 'u1',\n    name: 'Alice Johnson',\n    meta: 'Staff Engineer',\n    avatar: 'https://…/alice.png',\n    email: 'alice@acme.com', // shown as a copyable row\n    details: [\n      { label: 'Team', value: 'Platform' },\n      { label: 'Slack', value: '@alice', href: 'https://acme.slack.com/…' },\n    ],\n  },\n];\n```\n\n**React** — just add the `hovercard` prop to `<RenderedMessage />`:\n\n```tsx\nimport { RenderedMessage } from '@cursortag/mention-kit/react';\n\n<RenderedMessage message={stored} users={users} hovercard />\n\n// Configure copy behavior, delays, or a fully custom card body:\n<RenderedMessage\n  message={stored}\n  users={users}\n  hovercard={{ copyFields: true, copyUser: (u) => `${u.name} <${u.email}>` }}\n/>\n```\n\n**Vanilla / Vue** — render the message, then wire cards onto the container. It\nreturns a cleanup function; call it on unmount.\n\n```ts\nimport { renderCommentMessage, attachHovercards } from '@cursortag/mention-kit';\n\nrenderCommentMessage(stored, users).forEach((part) =>\n  container.append(\n    typeof part === 'string' ? document.createTextNode(part) : part,\n  ),\n);\n\nconst cleanup = attachHovercards(container, users, {\n  openDelay: 180, // ms before the card opens\n  closeDelay: 140, // ms before it closes\n  copyFields: true, // per-row copy buttons (default true)\n  copyUser: true, // \"copy user\" button (default true)\n});\n\n// later: cleanup();\n```\n\n`attachHovercards` works on the output of `renderCommentMessageToHTML` too — the\nmention spans carry `data-mention-id`, so you can inject the HTML and attach\ncards afterwards. Copy buttons use `navigator.clipboard` and no-op where it is\nunavailable.\n\n| Option       | Type                          | Default | Description                        |\n| ------------ | ----------------------------- | ------- | ---------------------------------- |\n| `openDelay`  | `number`                      | `180`   | ms before the card opens on hover  |\n| `closeDelay` | `number`                      | `140`   | ms before the card closes on leave |\n| `copyFields` | `boolean`                     | `true`  | Copy button on each field row      |\n| `copyUser`   | `boolean \\| (user) => string` | `true`  | \"Copy user\" button + its text      |\n| `render`     | `(user) => HTMLElement`       | —       | Replace the entire card body       |\n| `theme`      | `MentionTheme`                | —       | Theme applied to the card          |\n| `className`  | `string`                      | —       | Extra class appended to the card   |\n\n---\n\n## Theming\n\nChips and hovercards read their styling from `--mk-*` CSS custom properties. The\nlibrary's built-in look is the `var()` fallback, so the default appearance is\nunchanged and per-user colors still win — you only override what you want.\n\n**Option A — plain CSS.** Set the variables on any ancestor (chips) or on\n`.mk-hovercard` (the floating card):\n\n```css\n.comments {\n  --mk-chip-bg: #eef2ff;\n  --mk-chip-text: #4338ca;\n  --mk-chip-radius: 6px;\n}\n.mk-hovercard {\n  --mk-card-bg: #0b1220;\n  --mk-card-text: #e2e8f0;\n  --mk-card-border: #1e293b;\n  --mk-accent: #60a5fa;\n}\n```\n\n**Option B — a `theme` object** (React `<RenderedMessage>` / `<MentionInput>`,\nVue props, or `createMentionEditor`). A `light` / `dark` preset seeds the card;\nany explicit key overrides it:\n\n```tsx\n<RenderedMessage\n  message={stored}\n  users={users}\n  hovercard\n  theme={{ preset: 'dark' }}\n/>;\n\ncreateMentionEditor({\n  container,\n  users,\n  theme: { chipBg: '#eef2ff', chipRadius: 6 },\n});\n```\n\n| Theme key    | CSS variable       | Applies to           |\n| ------------ | ------------------ | -------------------- |\n| `preset`     | (seeds card vars)  | `'light'` / `'dark'` |\n| `chipBg`     | `--mk-chip-bg`     | chip background      |\n| `chipText`   | `--mk-chip-text`   | chip text            |\n| `chipRadius` | `--mk-chip-radius` | chip corners         |\n| `cardBg`     | `--mk-card-bg`     | card background      |\n| `cardText`   | `--mk-card-text`   | card text            |\n| `cardMuted`  | `--mk-card-muted`  | labels / meta        |\n| `cardBorder` | `--mk-card-border` | card border          |\n| `cardShadow` | `--mk-card-shadow` | card shadow          |\n| `cardRadius` | `--mk-card-radius` | card corners         |\n| `accent`     | `--mk-accent`      | copy buttons / links |\n\n`resolveThemeVars(theme)` returns the raw `{ '--mk-*': value }` map and\n`applyTheme(el, theme)` writes it onto an element, if you need to theme a\ncontainer yourself.\n\n---\n\n## API reference\n\n### Core (`@cursortag/mention-kit`)\n\n| Export                                                            | Description                                                        |\n| ----------------------------------------------------------------- | ------------------------------------------------------------------ |\n| `createMentionEditor(opts)`                                       | Creates a vanilla editor instance                                  |\n| `serializeToText(nodes)`                                          | Nodes to plain text string                                         |\n| `serializeToMarkdown(nodes)`                                      | Nodes to `@[name](id)` markdown string                             |\n| `renderCommentMessage(msg, users, palette?, triggerItems?)`       | Stored string to `(string \\| HTMLElement)[]`                       |\n| `renderCommentMessageToHTML(msg, users, palette?, triggerItems?)` | Stored string to HTML string                                       |\n| `parsePersist(raw, users, triggerItems?)`                         | Stored string to `EditorNode[]`                                    |\n| `attachHovercards(root, users, opts?)`                            | Wire hover user-info cards onto rendered mentions; returns cleanup |\n| `resolveThemeVars(theme)`                                         | Theme object to `{ '--mk-*': value }` map                          |\n| `applyTheme(el, theme)`                                           | Write theme vars onto an element                                   |\n| `DEFAULT_MENTION_PALETTE`                                         | Built-in color array                                               |\n\n### Types\n\n```ts\ninterface MentionUser {\n  id: string;\n  name: string;\n  avatar?: string; // URL — shown in chip avatar\n  meta?: string; // Subtitle shown in dropdown + hovercard\n  color?: string; // CSS color — overrides palette\n  email?: string; // Copyable row in the hovercard\n  details?: MentionUserDetail[]; // Extra hovercard rows\n  [key: string]: unknown;\n}\n\ninterface MentionUserDetail {\n  label: string;\n  value: string;\n  copyable?: boolean; // default true\n  href?: string; // renders value as a link (http(s)/mailto/tel)\n}\n\ntype MentionItem = MentionUser; // items a trigger can suggest\n\ninterface MentionTrigger {\n  trigger: string; // single char: '@', '#', '/', ':'\n  items:\n    | MentionItem[]\n    | ((query: string) => MentionItem[] | Promise<MentionItem[]>);\n  filter?: (item: MentionItem, query: string) => boolean;\n  serverFiltered?: boolean; // items() already filtered — skip local filter\n  debounce?: number; // ms, for async items() (default 0)\n  minChars?: number; // default 0\n  allowSpaces?: boolean; // default false\n  maxSuggestions?: number;\n  color?: string;\n  label?: string;\n  renderItem?: (item: MentionItem, selected: boolean) => HTMLElement;\n  onSelect?: (item: MentionItem, ctx: TriggerActionContext) => void; // slash-command mode\n  allowCreate?: boolean; // offer a \"Create …\" row for unmatched queries\n  onCreate?: (query: string) => MentionItem; // build the created item\n  createLabel?: (query: string) => string; // \"Create …\" row label\n}\n\ninterface TriggerActionContext {\n  trigger: string; // the trigger char that fired\n  insertText: (text: string) => void; // insert text at the caret\n}\n\n// Item lists per trigger char, for parsing/rendering stored multi-trigger content\ninterface TriggerItems {\n  trigger: string;\n  items: MentionItem[];\n}\n\ntype TextNode = { type: 'text'; text: string };\ntype MentionNode = {\n  type: 'mention';\n  user: MentionUser;\n  displayName: string;\n  trigger?: string; // absent means '@'\n};\ntype EditorNode = TextNode | MentionNode;\n\ninterface EditorCallbackMeta {\n  nodes: EditorNode[];\n  mentionedUsers: MentionUser[];\n}\n\ninterface MentionEditorInstance {\n  getNodes: () => EditorNode[];\n  setNodes: (nodes: EditorNode[], emit?: boolean) => void;\n  focus: () => void;\n  clear: () => void;\n  destroy: () => void;\n  setPlaceholder: (text: string) => void;\n}\n```\n\n---\n\n## Examples\n\nFull runnable examples live in [`examples/`](./examples):\n\n| File                                                                         | What it shows                                                                   |\n| ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |\n| [`examples/react/basic.tsx`](./examples/react/basic.tsx)                     | Drop-in `<MentionInput>`, submit text + mentionedUsers, clear                   |\n| [`examples/react/with-hook.tsx`](./examples/react/with-hook.tsx)             | `useMentionEditor` hook, custom container, toolbar, live text + mentioned users |\n| [`examples/react/with-mui.tsx`](./examples/react/with-mui.tsx)               | MUI `<Box>` shell, send button                                                  |\n| [`examples/react/with-hovercards.tsx`](./examples/react/with-hovercards.tsx) | `<RenderedMessage hovercard>`, copyable fields, light/dark `theme` toggle       |\n| [`examples/vue/basic.vue`](./examples/vue/basic.vue)                         | Drop-in `<MentionInput>`, `@submit`/`@change` emits                             |\n| [`examples/vue/with-composable.vue`](./examples/vue/with-composable.vue)     | `useMentionEditor`, reactive computed users, team filter                        |\n| [`examples/vue/with-hovercards.vue`](./examples/vue/with-hovercards.vue)     | `renderCommentMessage` + `attachHovercards`, theme + cleanup on unmount         |\n\n---\n\n## License\n\nMIT (c) [Amay Churi](https://github.com/amchuri)\n","readmeFilename":"README.md"}