{"_id":"@cujuju/solidjs-context-menu","_rev":"4-0eca286cfe87e14da86af5b9f5a4f71f","name":"@cujuju/solidjs-context-menu","dist-tags":{"latest":"0.2.2"},"versions":{"0.1.0":{"name":"@cujuju/solidjs-context-menu","version":"0.1.0","keywords":["solidjs","context-menu","menu","submenu","popover","flyout","glassmorphism"],"author":{"name":"Cujuju"},"license":"MIT","_id":"@cujuju/solidjs-context-menu@0.1.0","maintainers":[{"name":"cujuju","email":"cujuju@pm.me"}],"homepage":"https://github.com/Cujuju/solidjs-toolkit/tree/main/packages/context-menu","bugs":{"url":"https://github.com/Cujuju/solidjs-toolkit/issues"},"dist":{"shasum":"470b63c56d8523c58fdcc8a6c3ebd85058556bc7","tarball":"https://registry.npmjs.org/@cujuju/solidjs-context-menu/-/solidjs-context-menu-0.1.0.tgz","fileCount":23,"integrity":"sha512-fjzwvXoGyytzI6tpHwPtl3BC/5PntxjIju5GpoTduxe3RV02kfxqW+CSaH0mZWMT2GhmjStyFRX9suZTLTJEwQ==","signatures":[{"sig":"MEQCIH3MiOVtwFUR+qh02F55eJNCqLBCl6s/C3hJEFR+X/4+AiAMQgr/fgVCvhsV61SIfkcpWp83F0uxcMoRTbcmuFZc8A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":121470},"main":"./dist/index.js","type":"module","_from":"file:cujuju-solidjs-context-menu-0.1.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"solid":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./styles.css":"./src/context-menu.css"},"scripts":{"test":"vitest run","build":"vite build","test:watch":"vitest"},"_npmUser":{"name":"cujuju","email":"cujuju@pm.me"},"_resolved":"C:\\Users\\shawn\\AppData\\Local\\Temp\\1b3d514c59aef61e6c67fb14c5fc96bc\\cujuju-solidjs-context-menu-0.1.0.tgz","_integrity":"sha512-fjzwvXoGyytzI6tpHwPtl3BC/5PntxjIju5GpoTduxe3RV02kfxqW+CSaH0mZWMT2GhmjStyFRX9suZTLTJEwQ==","repository":{"url":"git+https://github.com/Cujuju/solidjs-toolkit.git","type":"git","directory":"packages/context-menu"},"_npmVersion":"11.12.1","description":"Cursor-positioned context menu for SolidJS — nested submenus, slider / button-row / checkbox entries, viewport clamping, top-layer popover, styled with the .glass-menu surface.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"25.8.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^24.0.0","vitest":"^3.2.4","vite-plugin-solid":"^2.11.12","@cujuju/solidjs-hooks":"2.0.0","@solidjs/testing-library":"^0.8.0","@testing-library/jest-dom":"^6.9.1","@cujuju/solidjs-glass-menu":"0.1.0"},"peerDependencies":{"solid-js":">=1.7.0","@cujuju/solidjs-hooks":"2.0.0","@cujuju/solidjs-glass-menu":"0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/solidjs-context-menu_0.1.0_1779039609422_0.7862616589963656","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@cujuju/solidjs-context-menu","version":"0.2.0","keywords":["solidjs","context-menu","menu","submenu","popover","flyout","glassmorphism"],"author":{"name":"Cujuju"},"license":"MIT","_id":"@cujuju/solidjs-context-menu@0.2.0","maintainers":[{"name":"cujuju","email":"cujuju@pm.me"}],"homepage":"https://github.com/Cujuju/solidjs-toolkit/tree/main/packages/context-menu","bugs":{"url":"https://github.com/Cujuju/solidjs-toolkit/issues"},"dist":{"shasum":"39c30b60063620fbe9f1cbdc4b4c650badb88db0","tarball":"https://registry.npmjs.org/@cujuju/solidjs-context-menu/-/solidjs-context-menu-0.2.0.tgz","fileCount":23,"integrity":"sha512-4+esmuftwB763MSQFG8WCipbpDHs23hKoFdYlChGHX0BtMPx7KPRTxlpX++TFULm8qnazWo8g/xpvPYlxOL4kg==","signatures":[{"sig":"MEUCIHgHzKB3ZBs9I1nZ6WecI0/uC4i8+WBb1HrDoIH3ZkyuAiEAjRubLTqfIzsl8N6qcZ2xL73UK7iaxiq+AJpieYKn6D4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":142361},"main":"./dist/index.js","type":"module","_from":"file:cujuju-solidjs-context-menu-0.2.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"solid":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./styles.css":"./src/context-menu.css"},"scripts":{"test":"vitest run","build":"vite build","test:watch":"vitest"},"_npmUser":{"name":"cujuju","email":"cujuju@pm.me"},"_resolved":"C:\\Users\\shawn\\AppData\\Local\\Temp\\f556f44f744b1e0b7d40afc60f0ee3b2\\cujuju-solidjs-context-menu-0.2.0.tgz","_integrity":"sha512-4+esmuftwB763MSQFG8WCipbpDHs23hKoFdYlChGHX0BtMPx7KPRTxlpX++TFULm8qnazWo8g/xpvPYlxOL4kg==","repository":{"url":"git+https://github.com/Cujuju/solidjs-toolkit.git","type":"git","directory":"packages/context-menu"},"_npmVersion":"11.12.1","description":"Cursor-positioned context menu for SolidJS — nested submenus, slider / button-row / checkbox entries, viewport clamping, top-layer popover, styled with the .glass-menu surface.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"25.8.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^24.0.0","vitest":"^3.2.4","vite-plugin-solid":"^2.11.12","@cujuju/solidjs-hooks":"2.0.0","@solidjs/testing-library":"^0.8.0","@testing-library/jest-dom":"^6.9.1","@cujuju/solidjs-glass-menu":"0.1.0"},"peerDependencies":{"solid-js":">=1.7.0","@cujuju/solidjs-hooks":"2.0.0","@cujuju/solidjs-glass-menu":"0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/solidjs-context-menu_0.2.0_1782486783348_0.3667759694063002","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@cujuju/solidjs-context-menu","version":"0.2.1","keywords":["solidjs","context-menu","menu","submenu","popover","flyout","glassmorphism"],"author":{"name":"Cujuju"},"license":"MIT","_id":"@cujuju/solidjs-context-menu@0.2.1","maintainers":[{"name":"cujuju","email":"cujuju@pm.me"}],"homepage":"https://github.com/Cujuju/solidjs-toolkit/tree/main/packages/context-menu","bugs":{"url":"https://github.com/Cujuju/solidjs-toolkit/issues"},"dist":{"shasum":"c63b5b9f6b3c7d8d0391a64c7d06b72fb9b692c5","tarball":"https://registry.npmjs.org/@cujuju/solidjs-context-menu/-/solidjs-context-menu-0.2.1.tgz","fileCount":23,"integrity":"sha512-xSG511WnU3+BifZltR+sP82r2nXXrofySiqbWYJ734VjWyfPDOMcxhiSQyYBYlJhUHuqxgkHE7s6/6ms1z2K+g==","signatures":[{"sig":"MEYCIQD0Lpyl3scPYiQ1GKyIlTpeGKlL7GQYM86mZ3kzks6j9AIhALZgf9k+Fz9xkhvq3g1fvPzcf+gzLzkCJbZPjHiMq9nj","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":145189},"main":"./dist/index.js","type":"module","_from":"file:cujuju-solidjs-context-menu-0.2.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"solid":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./styles.css":"./src/context-menu.css"},"scripts":{"test":"vitest run","build":"vite build","test:watch":"vitest"},"_npmUser":{"name":"cujuju","email":"cujuju@pm.me"},"_resolved":"C:\\Users\\shawn\\AppData\\Local\\Temp\\00d4e76d3591e064ff6de63b0431a6a4\\cujuju-solidjs-context-menu-0.2.1.tgz","_integrity":"sha512-xSG511WnU3+BifZltR+sP82r2nXXrofySiqbWYJ734VjWyfPDOMcxhiSQyYBYlJhUHuqxgkHE7s6/6ms1z2K+g==","repository":{"url":"git+https://github.com/Cujuju/solidjs-toolkit.git","type":"git","directory":"packages/context-menu"},"_npmVersion":"11.12.1","description":"Cursor-positioned context menu for SolidJS — nested submenus, slider / button-row / checkbox entries, viewport clamping, top-layer popover, styled with the .glass-menu surface.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"25.8.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^24.0.0","vitest":"^3.2.4","vite-plugin-solid":"^2.11.12","@cujuju/solidjs-hooks":"2.0.0","@solidjs/testing-library":"^0.8.0","@testing-library/jest-dom":"^6.9.1","@cujuju/solidjs-glass-menu":"0.1.0"},"peerDependencies":{"solid-js":">=1.7.0","@cujuju/solidjs-hooks":"2.0.0","@cujuju/solidjs-glass-menu":"0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/solidjs-context-menu_0.2.1_1782493071431_0.005042647001472389","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@cujuju/solidjs-context-menu","version":"0.2.2","description":"Cursor-positioned context menu for SolidJS — nested submenus, slider / button-row / checkbox entries, viewport clamping, top-layer popover, styled with the .glass-menu surface.","type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","solid":"./src/index.ts","import":"./dist/index.js"},"./styles.css":"./src/context-menu.css"},"sideEffects":["**/*.css"],"license":"MIT","author":{"name":"Cujuju"},"repository":{"type":"git","url":"git+https://github.com/Cujuju/solidjs-toolkit.git","directory":"packages/context-menu"},"homepage":"https://github.com/Cujuju/solidjs-toolkit/tree/main/packages/context-menu","bugs":{"url":"https://github.com/Cujuju/solidjs-toolkit/issues"},"keywords":["solidjs","context-menu","menu","submenu","popover","flyout","glassmorphism"],"peerDependencies":{"solid-js":">=1.7.0","@cujuju/solidjs-glass-menu":"^0.2.1","@cujuju/solidjs-hooks":"^2.0.0"},"devDependencies":{"@solidjs/testing-library":"^0.8.0","@testing-library/jest-dom":"^6.9.1","jsdom":"^24.0.0","vite-plugin-solid":"^2.11.12","vitest":"^3.2.4","@cujuju/solidjs-glass-menu":"^0.2.1","@cujuju/solidjs-hooks":"^2.0.0"},"publishConfig":{"access":"public"},"scripts":{"test":"vitest run","test:watch":"vitest","build":"vite build"},"_id":"@cujuju/solidjs-context-menu@0.2.2","_integrity":"sha512-GyTYhOuXn1U0n3cioEp74qgqUCNTlBTwxlOqjTkXdf6fJCBuPsSp2sMOnVo5hiwwn6EVcP6uaNvlwiBq4QrdhA==","_resolved":"/tmp/a4b41669f336289f04f9341b25ec6b6f/cujuju-solidjs-context-menu-0.2.2.tgz","_from":"file:cujuju-solidjs-context-menu-0.2.2.tgz","_nodeVersion":"24.18.0","_npmVersion":"12.0.1","dist":{"integrity":"sha512-GyTYhOuXn1U0n3cioEp74qgqUCNTlBTwxlOqjTkXdf6fJCBuPsSp2sMOnVo5hiwwn6EVcP6uaNvlwiBq4QrdhA==","shasum":"b895002bf2628e267023a6605bc9a3821965bdc7","tarball":"https://registry.npmjs.org/@cujuju/solidjs-context-menu/-/solidjs-context-menu-0.2.2.tgz","fileCount":23,"unpackedSize":145193,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCfR+FnrdxycHr1I1NTXstVPcV4Sg7vrTFZxBzX3xiJxAIgNa2Ur8K7mS5R3p4mXVOhlfX7ktDaM1nzVTqeEGiv5gY="}]},"_npmUser":{"name":"cujuju","email":"cujuju@pm.me"},"directories":{},"maintainers":[{"name":"cujuju","email":"cujuju@pm.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/solidjs-context-menu_0.2.2_1784888186089_0.7293014261620023"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-17T17:40:09.339Z","modified":"2026-07-24T10:16:26.388Z","0.1.0":"2026-05-17T17:40:09.564Z","0.2.0":"2026-06-26T15:13:03.469Z","0.2.1":"2026-06-26T16:57:51.616Z","0.2.2":"2026-07-24T10:16:26.220Z"},"bugs":{"url":"https://github.com/Cujuju/solidjs-toolkit/issues"},"author":{"name":"Cujuju"},"license":"MIT","homepage":"https://github.com/Cujuju/solidjs-toolkit/tree/main/packages/context-menu","keywords":["solidjs","context-menu","menu","submenu","popover","flyout","glassmorphism"],"repository":{"type":"git","url":"git+https://github.com/Cujuju/solidjs-toolkit.git","directory":"packages/context-menu"},"description":"Cursor-positioned context menu for SolidJS — nested submenus, slider / button-row / checkbox entries, viewport clamping, top-layer popover, styled with the .glass-menu surface.","maintainers":[{"name":"cujuju","email":"cujuju@pm.me"}],"readme":"# @cujuju/solidjs-context-menu\n\nA cursor-positioned **context menu** for SolidJS — nested submenus,\nslider / button-row / checkbox entries, viewport clamping, and\ntop-layer rendering. The panel is painted with the `.glass-menu`\nsurface from [`@cujuju/solidjs-glass`](../glass) (via\n[`@cujuju/solidjs-glass-menu`](../glass-menu)).\n\n`ContextMenu` is **caller-driven**: it does not own its open state.\nYou render `<ContextMenu>` while the menu should be visible — typically\nfrom a `contextmenu` handler that captured the click point — and stop\nrendering it inside `onClose`. The menu owns its own positioning,\ntop-layer promotion, and dismiss (outside click + Escape).\n\n## Install\n\n```sh\npnpm add @cujuju/solidjs-context-menu @cujuju/solidjs-glass-menu @cujuju/solidjs-glass @cujuju/solidjs-hooks\n```\n\n`@cujuju/solidjs-glass-menu` and `@cujuju/solidjs-hooks` are peer\ndependencies; `glass-menu` in turn needs `@cujuju/solidjs-glass`.\n`solid-js >=1.7.0` is also a peer dependency.\n\n## Quick start\n\n```tsx\nimport { createSignal, Show } from 'solid-js';\nimport { ContextMenu } from '@cujuju/solidjs-context-menu';\n\nfunction Example() {\n  const [menu, setMenu] = createSignal<{ x: number; y: number } | null>(null);\n\n  return (\n    <>\n      <div onContextMenu={(e) => { e.preventDefault(); setMenu({ x: e.clientX, y: e.clientY }); }}>\n        right-click me\n      </div>\n      <Show when={menu()}>\n        {(at) => (\n          <ContextMenu\n            x={at().x}\n            y={at().y}\n            onClose={() => setMenu(null)}\n            items={[\n              { label: 'Copy', onClick: doCopy },\n              { label: 'Paste', onClick: doPaste, disabled: !canPaste() },\n              { divider: true },\n              { label: 'Delete', onClick: doDelete, danger: true },\n            ]}\n          />\n        )}\n      </Show>\n    </>\n  );\n}\n```\n\nStylesheets register themselves on import — nothing to import manually.\n\n## Props — `ContextMenuProps`\n\n| Prop | Type | Notes |\n|------|------|-------|\n| `items` | `ContextMenuEntry[]` | The entries to render — see [Entry types](#entry-types). |\n| `x` | `number` | Viewport x of the requested open point (e.g. `event.clientX`). |\n| `y` | `number` | Viewport y of the requested open point. |\n| `onClose` | `() => void` | Called when the menu should close — outside click, Escape, or a non-`keepOpen` item activation. The caller owns open state. |\n\nThe open point is clamped into the viewport after the menu measures\nitself, so a near-edge `x`/`y` still renders fully on-screen.\n\n## Entry types\n\n`ContextMenuEntry` is a union; each entry is discriminated by a marker\nkey (`divider` / `slider` / `submenu` / `row`) or is a plain item.\n\n### `ContextMenuItem` — a plain action row\n\n| Field | Type | Notes |\n|-------|------|-------|\n| `label` | `string \\| JSX.Element` | Row label. |\n| `onClick` | `() => void` | Runs on activation. |\n| `danger` | `boolean?` | Render the label in the danger color. |\n| `disabled` | `boolean?` | |\n| `icon` | `JSX.Element \\| (() => JSX.Element \\| undefined)` | Leading icon; a function form is re-evaluated each render. |\n| `keepOpen` | `boolean?` | Keep the menu open after the click instead of closing. |\n| `when` | `() => boolean` | When it returns false, the row is not rendered. |\n| `checked` | `boolean?` | When defined, renders a right-aligned checkbox indicator — a check when `true`, a reserved blank when `false` (so adjacent toggle rows align). Undefined = no indicator. |\n\n### `ContextMenuDivider` — `{ divider: true }`\n\nA horizontal rule between entries.\n\n### `ContextMenuSlider` — `{ slider: true, … }`\n\nA labelled range slider embedded as a row: `label`, `min`, `max`,\n`step?`, `value: () => number`, `onChange: (n) => void`, `unit?`,\n`when?`. The slider focuses on hover so arrow keys adjust it.\n\n### `ContextMenuSubmenu` — `{ submenu: true, … }`\n\nA row that opens a nested submenu on hover: `label`, `icon?`,\n`children: ContextMenuEntry[]`, `scrollable?`. A `scrollable` submenu\ncaps its height and shows a search field that filters its children by\nlabel. Submenus nest arbitrarily deep.\n\n### `ContextMenuButtonRow` — `{ row: true, buttons: [...] }`\n\nA row of compact side-by-side buttons (e.g. a chapter-nav cluster).\nEach button: `{ label, onClick, disabled?, icon? }`.\n\n## Anatomy\n\n`ContextMenu` renders a `GlassMenu` surface (the root) holding the\nentry rows. Stable global classes (prefixed `cujuju-context-menu*`):\n\n| Class | Element |\n|-------|---------|\n| `cujuju-context-menu` | the menu root (also a `GlassMenu`, also `[popover]`) |\n| `cujuju-context-menu-item` | a plain action / submenu-trigger row |\n| `cujuju-context-menu-item-danger` | a `danger` item |\n| `cujuju-context-menu-icon` | leading icon slot |\n| `cujuju-context-menu-label` | row label (truncates) |\n| `cujuju-context-menu-check` | the `checked` indicator slot |\n| `cujuju-context-menu-divider` | the `<hr>` divider |\n| `cujuju-context-menu-submenu-wrapper` / `-chevron` | submenu trigger row |\n| `cujuju-context-menu-flyout` / `-flyout-search` | a Portal'd submenu panel + its search field |\n| `cujuju-context-menu-button-row` / `-row-btn` | a button row |\n| `cujuju-context-menu-slider-row` / `-slider*` | a slider row |\n\nEach Portal'd submenu also carries `data-popover-stack` — see\n[Positioning & dismiss](#positioning--dismiss).\n\n## Positioning & dismiss\n\n- **Top layer.** The menu and every submenu are `popover=\"manual\"`\n  elements promoted with `showPopover()`, so they paint above every\n  normal stacking context — including other top-layer popovers. When a\n  submenu opens, its parent is re-promoted so the parent paints above\n  it, and the submenu's leading edge tucks a few pixels under the\n  parent.\n- **Submenus are Portal'd to `<body>`** to escape any `backdrop-filter`\n  / `transform` ancestor that would otherwise re-anchor their\n  `position: fixed`. Each Portal'd submenu carries the\n  `data-popover-stack` attribute.\n- **Dismiss.** The menu closes on outside `mousedown` and on `Escape`.\n  A click inside any element matching `[data-popover-stack]` counts as\n  inside — so submenu clicks never dismiss the menu. If your app has\n  its own popover machinery (e.g. an anchored-popover dismiss-skip\n  predicate), make it honor the same `data-popover-stack` attribute so\n  ContextMenu submenus opened above your popover don't dismiss it.\n\n## What ContextMenu does NOT do\n\n- **Open state** — there is no `open` prop. Render `<ContextMenu>` while\n  open; stop rendering it inside `onClose`.\n- **The trigger** — wire your own `contextmenu` (or click) handler to\n  capture `clientX`/`clientY` and set the open state.\n- **Focus management** — there is no focus trap or roving focus; the\n  menu is pointer-driven (submenus open on hover).\n\n## Styling\n\n`ContextMenu` registers its stylesheet (`context-menu.css`) and, via\n`GlassMenu`, the `.glass-menu` surface from `@cujuju/solidjs-glass` — as\nimport side effects. Nothing to import manually. The raw stylesheet is\nalso exported at `@cujuju/solidjs-context-menu/styles.css`.\n\nHost theme tokens are referenced with inline fallbacks, so the menu\nrenders standalone over a dark backdrop and themes when a host provides\nthem: `--z-top`, `--radius-sm`, `--color-text`,\n`--color-text-secondary`, `--color-primary`, `--color-surface`,\n`--color-surface-hover`, `--color-danger`, `--color-danger-alpha-10`,\n`--color-white-alpha-{8,10,15,20}`, `--font-size-base`,\n`--font-size-sm`. The `.glass-menu` surface itself is themed through\n`@cujuju/solidjs-glass` (see that package's menu-tint engine).\n\n## License\n\nMIT\n","readmeFilename":"README.md"}