{"_id":"@arcon.mobi/nuxt-cmdk","name":"@arcon.mobi/nuxt-cmdk","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@arcon.mobi/nuxt-cmdk","version":"0.1.0","description":"Command palette + keyboard shortcut registry for Nuxt — async actions, multi-step sequences (g d), fuzzy search, scoped CSS theming.","keywords":["nuxt","nuxt-module","vue","command-palette","cmdk","keyboard-shortcuts","hotkeys","fuzzy-search","fuse","reka-ui"],"homepage":"https://github.com/aj-abad/nuxt-cmdk#readme","repository":{"type":"git","url":"git+https://github.com/aj-abad/nuxt-cmdk.git"},"bugs":{"url":"https://github.com/aj-abad/nuxt-cmdk/issues"},"author":{"name":"AJ","email":"dev@ajabad.com"},"license":"MIT","type":"module","exports":{".":{"types":"./dist/types.d.mts","import":"./dist/module.mjs"}},"main":"./dist/module.mjs","typesVersions":{"*":{".":["./dist/types.d.mts"]}},"engines":{"node":">=18.0.0"},"publishConfig":{"access":"public"},"dependencies":{"@nuxt/kit":"^3.15.0","fuse.js":"^7.0.0"},"peerDependencies":{"reka-ui":">=2.0.0","vue":"^3.5.0"},"devDependencies":{"@nuxt/module-builder":"^1.0.1","@nuxt/schema":"^4.3.0","nuxt":"^4.3.0","reka-ui":"^2.9.1","typescript":"^5.7.0","vue":"^3.5.30","vue-tsc":"^3.2.7"},"scripts":{"dev":"nuxt-module-build build --stub && nuxt-module-build prepare && nuxi dev playground","dev:build":"nuxi build playground","dev:prepare":"nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground","release":"pnpm prepack && pnpm publish"},"_id":"@arcon.mobi/nuxt-cmdk@0.1.0","_integrity":"sha512-DWmL8mE7wkzd3nqnFleAgtlmVA4A/0HlMyD0OWkvpXW/JcOw4NzUfloWccekFVNHiHthfT/idrDwuBDCJW3pCg==","_resolved":"/private/var/folders/fy/xjr43t910sbcy1m0yysvzh700000gn/T/3db96d1f2790bbee09237fcf3e4490bd/arcon.mobi-nuxt-cmdk-0.1.0.tgz","_from":"file:arcon.mobi-nuxt-cmdk-0.1.0.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-DWmL8mE7wkzd3nqnFleAgtlmVA4A/0HlMyD0OWkvpXW/JcOw4NzUfloWccekFVNHiHthfT/idrDwuBDCJW3pCg==","shasum":"74f661e5dd97a3be9fac841220cbca1251d466b3","tarball":"https://registry.npmjs.org/@arcon.mobi/nuxt-cmdk/-/nuxt-cmdk-0.1.0.tgz","fileCount":29,"unpackedSize":58644,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGUzIJMoamKogvE5EaOcFSfAzqyaWuvxpHduYaGQiVJNAiAvrbMp2uQGFsn3zrEsG75G869JyBvj6IlasC5reMurDQ=="}]},"_npmUser":{"name":"aj-abad","email":"ajabad.dev@gmail.com"},"directories":{},"maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nuxt-cmdk_0.1.0_1777201625791_0.42897396170595203"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-26T11:07:05.724Z","0.1.0":"2026-04-26T11:07:05.922Z","modified":"2026-04-26T11:07:06.113Z"},"maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"description":"Command palette + keyboard shortcut registry for Nuxt — async actions, multi-step sequences (g d), fuzzy search, scoped CSS theming.","homepage":"https://github.com/aj-abad/nuxt-cmdk#readme","keywords":["nuxt","nuxt-module","vue","command-palette","cmdk","keyboard-shortcuts","hotkeys","fuzzy-search","fuse","reka-ui"],"repository":{"type":"git","url":"git+https://github.com/aj-abad/nuxt-cmdk.git"},"author":{"name":"AJ","email":"dev@ajabad.com"},"bugs":{"url":"https://github.com/aj-abad/nuxt-cmdk/issues"},"license":"MIT","readme":"# nuxt-cmdk\n\nLinear-style command palette + keyboard shortcut registry for Nuxt. Composable-first, headless, themable via CSS variables.\n\n## Features\n\n- **Multi-step sequences** — `g d` to navigate, like Linear/Vercel\n- **OS-aware modifiers** — `mod+k` resolves to `⌘K` on Mac, `Ctrl+K` elsewhere\n- **Async actions** — `action: () => Promise<void>` with built-in loading state\n- **Fuzzy search** — Fuse.js, with substring fallback\n- **Scoped commands** — register per-component, auto-cleanup on unmount\n- **Scoped CSS + CSS variables** — themable, no Tailwind dependency\n- **Reka UI Dialog** — accessible, keyboard-driven\n- **Overlay-aware** — `useShortcutBlocker` pauses shortcuts under dropdowns/menus\n- **Error hooks** — `cmdk:error` and `cmdk:executed` for toast/log integration\n\n## Install\n\n```bash\npnpm add @arcon.mobi/nuxt-cmdk reka-ui\n```\n\n```ts\n// nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: ['@arcon.mobi/nuxt-cmdk'],\n  cmdk: {\n    paletteShortcut: 'mod+k',  // default\n    search: 'fuzzy',           // 'fuzzy' | 'substring'\n    sequenceTimeoutMs: 1500,\n    prefix: 'Cmdk',            // component prefix\n  },\n})\n```\n\nMount the palette and sequence indicator in your root layout:\n\n```vue\n<!-- app.vue or layouts/default.vue -->\n<template>\n  <NuxtPage />\n  <CmdkPalette />\n  <CmdkSequenceIndicator />\n</template>\n```\n\n## Usage\n\n### Register commands\n\n```vue\n<script setup lang=\"ts\">\nuseCommands([\n  {\n    id: 'go-customers',\n    name: 'Go to Customers',\n    group: 'Navigation',\n    shortcut: 'g c',\n    action: () => navigateTo('/customers'),\n  },\n  {\n    id: 'save-document',\n    name: 'Save Document',\n    shortcut: 'mod+s',\n    keywords: ['write', 'persist'],\n    action: async () => {\n      await saveDocument()\n    },\n  },\n])\n</script>\n```\n\nCommands registered via `useCommands` are auto-unregistered on unmount.\n\n### Hidden shortcuts\n\nSet `hidden: true` to make a command shortcut-only — it won't show in the palette but the shortcut still fires:\n\n```ts\nuseCommands([\n  {\n    id: 'select-all',\n    name: 'Select All',\n    shortcut: 'mod+a',\n    hidden: true,\n    action: selectAll,\n  },\n])\n```\n\n### Reactive command sets\n\nPass a `ref` or `computed` to enable/disable commands based on state:\n\n```ts\nconst isDirty = ref(false)\nconst cmds = computed(() => isDirty.value ? [{\n  id: 'save',\n  name: 'Save Changes',\n  shortcut: 'mod+s',\n  action: save,\n}] : [])\n\nuseCommands(cmds)\n```\n\n### Palette control\n\n```ts\nconst { isOpen, open, close, toggle } = useCommandPalette()\n```\n\n### Block shortcuts under overlays\n\nIf you have a custom dropdown/menu/modal that doesn't already block shortcuts, use `useShortcutBlocker`:\n\n```vue\n<script setup lang=\"ts\">\nconst menuOpen = ref(false)\nuseShortcutBlocker(menuOpen)\n</script>\n```\n\nWhile `menuOpen` is true, all sequence shortcuts are paused (modifier shortcuts like `Cmd+K` still work via the palette's own listener).\n\n### Listen to errors\n\n```ts\nconst nuxtApp = useNuxtApp()\nnuxtApp.hook('cmdk:error', (err, cmd) => {\n  toast.error(`\"${cmd.name}\" failed: ${(err as Error).message}`)\n})\nnuxtApp.hook('cmdk:executed', (cmd) => {\n  console.log(`ran ${cmd.id}`)\n})\n```\n\n## Shortcut syntax\n\n| Token | Meaning |\n|---|---|\n| `mod` | `Cmd` on Mac, `Ctrl` elsewhere |\n| `cmd`, `ctrl` | Same as `mod` |\n| `shift`, `alt`, `option` | Modifiers |\n| `+` | Joins modifiers in a step (`mod+shift+s`) |\n| ` ` (space) | Separates steps in a sequence (`g d`) |\n\nExamples: `mod+k`, `mod+shift+p`, `g i`, `g g`, `escape`, `?`\n\n## API\n\n### `useCommands(commands)`\n\nRegisters a list of commands scoped to the current component. Accepts a static array or a `ref`/`computed` for reactive sets.\n\n### `useCommandPalette()`\n\nReturns `{ isOpen, open, close, toggle, restoreFocus }`.\n\n### `useShortcutBlocker(isOpen)`\n\nPauses sequence shortcuts while the given ref is `true`. Auto-cleans on unmount.\n\n### `defineCommand(cmd)`\n\nType-safe helper for authoring commands inline.\n\n### `Command` type\n\n```ts\ninterface Command {\n  id: string\n  name: string\n  group?: string\n  shortcut?: string\n  keywords?: string[]\n  action: () => void | Promise<void>\n  priority?: number\n  hidden?: boolean\n}\n```\n\n## Theming\n\nAll visuals use CSS variables. Override at any level:\n\n```css\n:root {\n  --cmdk-bg: #1a1a1a;\n  --cmdk-fg: rgb(255 255 255 / 0.9);\n  --cmdk-border: rgb(255 255 255 / 0.1);\n  --cmdk-border-subtle: rgb(255 255 255 / 0.05);\n  --cmdk-overlay-bg: rgb(0 0 0 / 0.5);\n  --cmdk-active-bg: rgb(255 255 255 / 0.08);\n  --cmdk-active-fg: #fff;\n  --cmdk-muted-fg: rgb(255 255 255 / 0.5);\n  --cmdk-placeholder: rgb(255 255 255 / 0.4);\n  --cmdk-kbd-bg: rgb(255 255 255 / 0.1);\n  --cmdk-radius: 0.75rem;\n  --cmdk-max-width: 36rem;\n  --cmdk-z-index: 300;\n  --cmdk-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.5);\n}\n```\n\n## Animations\n\nThe palette ships with **no animations by default** — that's a deliberate choice so you can match your app's motion language and decide how to handle `prefers-reduced-motion` yourself.\n\n### Open / close\n\n`<CmdkPalette />` is built on Reka UI's Dialog, which sets `data-state=\"open\"` and `data-state=\"closed\"` on the overlay and content. Reka waits for any matching CSS animation (or transition) to finish before unmounting, so you only need CSS:\n\n```css\n.cmdk-overlay[data-state='open']  { animation: my-fade-in 150ms ease-out; }\n.cmdk-overlay[data-state='closed'] { animation: my-fade-out 100ms ease-in; }\n\n.cmdk-content[data-state='open']  { animation: my-scale-in 150ms ease-out; }\n.cmdk-content[data-state='closed'] { animation: my-scale-out 100ms ease-in; }\n\n@keyframes my-fade-in   { from { opacity: 0 } }\n@keyframes my-fade-out  { to   { opacity: 0 } }\n@keyframes my-scale-in  { from { opacity: 0; transform: translateX(-50%) scale(0.98) } }\n@keyframes my-scale-out { to   { opacity: 0; transform: translateX(-50%) scale(0.98) } }\n```\n\n### Result list resize\n\nWhen search filters the result list, the wrapper resizes instantly. To smooth it:\n\n```css\n.cmdk-list-wrap { transition: height 200ms ease; }\n```\n\n### Sequence indicator\n\n`<CmdkSequenceIndicator />` is wrapped in `<Transition name=\"cmdk-sequence\">`. Drop in your own classes:\n\n```css\n.cmdk-sequence-enter-from,\n.cmdk-sequence-leave-to    { opacity: 0; transform: translateY(0.5rem); }\n.cmdk-sequence-enter-active,\n.cmdk-sequence-leave-active { transition: opacity 150ms ease, transform 150ms ease; }\n```\n\n### Loading indicator (per-command)\n\nWhile an async command's promise is pending, `<CmdkPalette />` renders a small SVG spinner. The spinner uses SMIL and animates regardless of `prefers-reduced-motion`. To replace it (or remove it), use the `running` slot:\n\n```vue\n<CmdkPalette>\n  <template #running=\"{ command }\">\n    <span class=\"my-loader\" :aria-label=\"`Running ${command.name}`\" />\n  </template>\n</CmdkPalette>\n```\n\nThe slot only renders for commands that are currently executing.\n\n## Module options\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `prefix` | `string` | `\"Cmdk\"` | Component prefix (`<CmdkPalette />`) |\n| `search` | `'fuzzy' \\| 'substring'` | `'fuzzy'` | Search algorithm |\n| `paletteShortcut` | `string \\| false` | `'mod+k'` | Open shortcut, or `false` to disable |\n| `sequenceTimeoutMs` | `number` | `1500` | Time before partial sequences cancel |\n\n## Development\n\n```bash\npnpm install\npnpm dev:prepare   # generates .nuxt for typing\npnpm dev           # runs the playground\n```\n\n## Using with Claude Code (and other AI agents)\n\nThis package ships an [`AGENTS.md`](./AGENTS.md) at its root with a dense, agent-friendly API summary — including behaviors that are easy to miss when scanning the source (e.g. `action` is excluded from structural diff, the `cmdk:toggle` id is reserved, exact-shortcut beats longer-sequence). Agents can read `node_modules/@arcon.mobi/nuxt-cmdk/AGENTS.md` to load the API in one shot.\n\nIf you'd like Claude Code to use the palette pattern by default in your project, drop something like this into your `CLAUDE.md`:\n\n```md\n## Command palette and shortcuts\n\nThis project uses [@arcon.mobi/nuxt-cmdk](https://www.npmjs.com/package/@arcon.mobi/nuxt-cmdk).\n- Register commands with `useCommands([...])` in the component that owns them — do not maintain a central registry.\n- Always set an explicit `id` on each command.\n- Read reactive state inside the `action` body, not by swapping the function reference.\n- See `node_modules/@arcon.mobi/nuxt-cmdk/AGENTS.md` for the full API.\n```\n\n## Credits\n\nPattern adapted from [arcon-cpo](https://github.com/Arcon/arcon-cpo)'s internal command system. Multi-step sequence semantics inspired by Linear.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-04df5bda00c051f373a9557b45f8b9b9"}