{"_id":"@andrylavr/vue-context-menu","name":"@andrylavr/vue-context-menu","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@andrylavr/vue-context-menu","version":"0.1.0","description":"A lightweight Vue 3 context menu component and directive with nested menus, keyboard navigation, and async items.","author":{"name":"andrylavr"},"repository":{"type":"git","url":"git+https://github.com/andrylavr/vue-context-menu.git"},"bugs":{"url":"https://github.com/andrylavr/vue-context-menu/issues"},"homepage":"https://github.com/andrylavr/vue-context-menu#readme","type":"module","publishConfig":{"access":"public"},"main":"./dist/vue-context-menu.cjs","module":"./dist/vue-context-menu.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/vue-context-menu.js","require":"./dist/vue-context-menu.cjs"},"./style.css":"./dist/style.css"},"scripts":{"dev":"vite --host 127.0.0.1","build":"vite build && vue-tsc --declaration --emitDeclarationOnly","build:pages":"vite build --config vite.pages.config.ts","prepack":"npm run build","test":"vitest run","typecheck":"vue-tsc --noEmit"},"peerDependencies":{"vue":"^3.3.0"},"devDependencies":{"@vitejs/plugin-vue":"^5.0.0","@vue/test-utils":"^2.4.11","jsdom":"^29.1.1","typescript":"^5.0.0","vite":"^5.0.0","vitest":"^4.1.8","vue":"^3.3.0","vue-tsc":"^2.0.0"},"license":"MIT","_id":"@andrylavr/vue-context-menu@0.1.0","gitHead":"0b45427cf13a417b8333e6a0067f9873f70690af","_nodeVersion":"22.17.1","_npmVersion":"10.9.2","dist":{"integrity":"sha512-i24DPqq35hSRmQ0QK5zTe48Tb+vtlMsrJyyql4gpSNsdY1J/uiSvrERgR4EAxsOlrI/KmLB3mhUEz+7A1ZwBKg==","shasum":"e4f3b121f7ea8840ca54299f6203b7f1a20a45c5","tarball":"https://registry.npmjs.org/@andrylavr/vue-context-menu/-/vue-context-menu-0.1.0.tgz","fileCount":13,"unpackedSize":56588,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFqztaw2squw1EBJbKzg1UeLYM6DRUZTHoUBXM7TbnlUAiEA/dawbvZ46sksyBlQ+oIeopkIZOUWRB7ccFCL6CUGzAM="}]},"_npmUser":{"name":"andrylavr","email":"andrylavr@gmail.com"},"directories":{},"maintainers":[{"name":"andrylavr","email":"andrylavr@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/vue-context-menu_0.1.0_1780917922807_0.17931968017712197"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-08T11:25:22.630Z","0.1.0":"2026-06-08T11:25:23.019Z","modified":"2026-06-08T11:25:23.224Z"},"maintainers":[{"name":"andrylavr","email":"andrylavr@gmail.com"}],"description":"A lightweight Vue 3 context menu component and directive with nested menus, keyboard navigation, and async items.","homepage":"https://github.com/andrylavr/vue-context-menu#readme","repository":{"type":"git","url":"git+https://github.com/andrylavr/vue-context-menu.git"},"author":{"name":"andrylavr"},"bugs":{"url":"https://github.com/andrylavr/vue-context-menu/issues"},"license":"MIT","readme":"# @andrylavr/vue-context-menu\n\nA lightweight Vue 3 context menu component and directive with nested menus, keyboard navigation, and async items.\n\n## Install\n\n```bash\nnpm install @andrylavr/vue-context-menu\n```\n\n## Quick Start\n\nRegister the plugin and CSS once in your app entry:\n\n```ts\nimport { createApp } from 'vue';\nimport VueContextMenu from '@andrylavr/vue-context-menu';\nimport '@andrylavr/vue-context-menu/style.css';\n\ncreateApp(App).use(VueContextMenu).mount('#app');\n```\n\nRender one menu host near the root of the app, then attach `v-context-menu` to any target:\n\n`items` is an ordered array. Command items use a required `key`; string values render separators.\n\n```vue\n<template>\n  <ContextMenu />\n  <button v-context-menu=\"{ items }\">Open menu</button>\n</template>\n\n<script setup>\nconst items = [\n  {\n    key: 'edit',\n    label: 'Edit',\n    callback: (key, context) => console.log(key, context.triggerElement)\n  },\n  '---------',\n  {\n    key: 'delete',\n    label: 'Delete',\n    disabled: true\n  },\n  {\n    key: 'more',\n    label: 'More',\n    items: [\n      { key: 'copy', label: 'Copy' },\n      { key: 'paste', label: 'Paste' }\n    ]\n  }\n];\n</script>\n```\n\nSee [examples/quickstart/QuickStart.vue](examples/quickstart/QuickStart.vue) for a complete copyable example with callbacks, a checkbox item, a submenu, and manual opening.\n\nRun the examples locally:\n\n```bash\nnpm run dev\n```\n\nOpen:\n\n- `http://127.0.0.1:5173/quick-start.html` for the shortest integration path.\n- `http://127.0.0.1:5173/basic.html` for a small directive-only example.\n- `http://127.0.0.1:5173/` for the full demo.\n\n## Usage Details\n\nUse `menuClass` when one menu needs different sizing or theme variables:\n\n```vue\n<button v-context-menu=\"{ items, menuClass: 'compact-menu' }\">\n  Compact menu\n</button>\n```\n\n```css\n.compact-menu {\n  --v-context-menu-min-width: 118px;\n  --v-context-menu-item-min-height: 22px;\n  --v-context-menu-item-padding-left: 5px;\n  --v-context-menu-item-padding-right: 20px;\n}\n```\n\nOr open manually:\n\n```ts\nimport { useContextMenu } from '@andrylavr/vue-context-menu';\n\nconst contextMenu = useContextMenu();\n\nfunction open(event: MouseEvent) {\n  contextMenu.show({\n    event,\n    items: [\n      { key: 'refresh', label: 'Refresh' }\n    ]\n  });\n}\n```\n\n## Supported now\n\n- Right click, left click, hover and manual opening.\n- Keyboard opening with the Context Menu key or Shift+F10.\n- Separators using string values.\n- Nested submenus.\n- Async submenu item loaders with an in-menu spinner.\n- `disabled` and `visible` booleans or callbacks.\n- Item callbacks and a default callback.\n- Basic keyboard navigation.\n- `text`, `textarea`, `checkbox`, `radio`, `select` and `html` item types.\n- Viewport-aware positioning without `@floating-ui`.\n- Item rendering slots: `item`, `icon`, `label`, `extra` and `separator`.\n- Per-menu classes with CSS variables for compact or custom sizing.\n\n## Slots\n\nThe menu keeps the interactive `li`, focus handling and keyboard behavior. Slots customize the content inside each item.\n\n```vue\n<ContextMenu>\n  <template #extra=\"{ item }\">\n    <kbd v-if=\"item.shortcut\">{{ item.shortcut }}</kbd>\n  </template>\n\n  <template #icon=\"{ item }\">\n    <MyIcon v-if=\"item.icon\" :name=\"item.icon\" />\n  </template>\n</ContextMenu>\n```\n\n## Async Submenus\n\nAn item can provide `items` as an async function. The submenu opens immediately and shows a loading spinner until the items resolve.\n\n```ts\nconst items = [\n  {\n    key: 'users',\n    label: 'Users',\n    items: async () => {\n      const users = await fetch('/api/users').then((response) => response.json());\n\n      return users.map((user) => ({\n        key: user.id,\n        label: user.name\n      }));\n    }\n  }\n];\n```\n\n## Scope\n\nThis is a standalone Vue package, not a jQuery wrapper or compatibility port.\n\n## GitHub Pages Demo\n\nThe demo is published as a static Vite build from `docs/`, so it works on GitHub Pages without GitHub Actions.\n\nLocal demo build:\n\n```bash\nnpm run build:pages\n```\n\nThe Pages build writes `index.html`, `basic.html`, `quick-start.html`, and static assets to `docs/`. In the GitHub repository settings, set Pages to deploy from the `main` branch and the `/docs` folder.\n","readmeFilename":"README.md","_rev":"1-d49c98e9cc3c25d978e479602ae34eb3"}