Repository files navigation

Context Menu TS (Vanilla/Vue3)

NPM VersionLicenseGitHubTypeScriptCoverage

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription). The library is lightweight, has no required dependencies (Vue 3 is optional), and can be easily integrated into existing projects.

slider

View Live Demo

✨ Features

🎨 Customizable appearance (colors, radii, opacity)
🖼️ SVG icon support via sprites
💬 Hints with optional background
🖱️ Hover and wheel animations
🧩 Optional central button
📦 Two usage modes: vanilla JS and Vue 3 component
⚡ Full TypeScript support (types included)

📦 Installation

npm install @alekstar79/context-menu

The library has an optional peer dependency on vue. If you are using the Vue component, install Vue 3 as well:

npm install vue@^3

🚀 Usage

  1. Vanilla JS / TypeScript
import{defineConfig,Manager}from'@alekstar79/context-menu'constconfig=defineConfig({sprite: '/path/to/icons.svg',// path to SVG spriteinnerRadius: 50,outerRadius: 150,opacity: 0.7,color: '#1976D2',sectors: [{icon: 'new',hint: 'New'},{icon: 'open',hint: 'Open'},{icon: 'save',hint: 'Save'}],centralButton: {icon: 'home',hint: 'Home',hintPosition: 'top'}})// container element where the menu will be placedconstcontainer=document.getElementById('menu-container')constmenu=newManager(container,config)// subscribe to eventsmenu.on('click',(data)=>{console.log(`Selected: ${data.hint}`)})// show menu at cursor position (e.g., on contextmenu)window.addEventListener('contextmenu',(e)=>{e.preventDefault()menu.show(e)})
  1. Vue Component
<template>
<CircularMenu
ref="menuRef"
:sprite="sprite"
:inner-radius="75"
:outer-radius="150"
:sectors="sectors"
:central-button="centralButton"
color="#42B883"
@click="onMenuItemClick"
/>
</template>
<script setup lang="ts">import { ref } from'vue'importtype { ISector } from'@alekstar79/context-menu/context-menu'importContextMenufrom'@alekstar79/context-menu/context-menu/vue'const sprite ='/icons.svg'const sectors:ISector[] = [ { icon: 'new', hint: 'New' }, { icon: 'open', hint: 'Open' }, { icon: 'save', hint: 'Save' }];const centralButton = { icon: 'home', hint: 'Home', hintPosition: 'bottom'}const menuRef =ref()const onMenuItemClick = (data: { icon:string; hint:string }) => {console.log('Selected:', data.hint)}// Example of manually showing the menuconst showMenu = (e:PointerEvent) => {menuRef.value?.show(e)}</script>

⚙️ Configuration

defineConfig(options: Partial<IConfig>): IConfig

Creates a configuration object with default values.

IConfig interface

PropertyTypeDefaultDescription
spritestring../icons.svgPath to the SVG sprite containing icons
innerRadiusnumberInner radius of sectors (the smaller ring radius)
outerRadiusnumberOuter radius of sectors
opacitynumber0.7Opacity of sectors and hint backgrounds (if any)
colorstringMain color for sectors and hint backgrounds (default '#1976D2' if omitted)
hintPaddingnumberPadding around the hint text (pixels). If not set, the hint is rendered without a background
iconScalenumberGlobal scale factor for all icons (can be overridden per sector)
iconRadiusnumberGlobal radius at which icons are placed (can be overridden per sector)
sectorsISector[][]Array of menu sectors
centralButtonICentralButtonConfiguration for the central button
autoBindContextMenubooleantrueAutomatically bind the contextmenu event listener to window

ISector interface

PropertyTypeDefaultDescription
iconstringIcon identifier (without #)
hintstringHint text
onclick() => voidClick handler for the sector
rotatenumber0Additional rotation of the icon (degrees)
iconScalenumberglobalIcon scale for this specific sector
iconRadiusnumberglobalIcon placement radius for this sector
hintPaddingnumberglobalHint padding for this sector

ICentralButton interface

PropertyTypeDefaultDescription
iconstringIcon identifier
hintstringHint text
onclick() => voidClick handler
iconScalenumberglobalIcon scale
iconRadiusnumberglobalIcon radius (effectively the button size)
hintPositiontop | bottomtopPosition of the hint relative to the button
hintSpannumber180Angular span of the hint arc (degrees)
hintDistancenumber8Distance from button edge to the hint text (when no background)
hintOffsetnumberAbsolute offset of the hint (overrides hintDistance)
hintPaddingnumberglobalHint padding for the central button
hintStartAnglenumberStart angle of the arc (must be set together with hintEndAngle)
hintEndAnglenumberEnd angle of the arc

🧠 API

Manager class (vanilla)

constmenu=newManager(container: HTMLElement,config: IConfig)

Methods

  • show(event: MouseEvent | PointerEvent) – Shows the menu at the cursor position.
  • hide() – Hides the menu.
  • on(event: string, callback: Function) – Subscribes to events.

Events

  • click – Emitted when a sector or the central button is clicked. The callback receives { icon: string; hint: string }.

Vue component CircularMenu

Props

All properties from IConfig except sectors and centralButton (they are passed separately).
Additional props:

  • autoBindContextMenu – Automatically bind contextmenu to window (default true).

Events

  • click – Same as the vanilla click event.

Exposed methods (via ref)

  • show(event: PointerEvent) – Shows the menu.
  • hide() – Hides the menu.

💅 Styling

The library comes with basic styles that are automatically included. You can override them using the following CSS classes:

  • .context – Root menu container.
  • .radial-menu-svg – The SVG element.
  • .radial-sector – A sector.
  • .radial-icon – An icon.
  • .radial-hint – Hint text.
  • .radial-hint-bg – Hint background.
  • .central-sector, .central-icon, .central-hint – Central button elements.
  • .active – Class added to hints on hover.

Example of customization:

.radial-hint {
font-size: 14px;
font-weight: 600;
fill: #000;
}

🛠️ Development

git clone <repo>cd context-menu
npm install

Scripts

  • npm run dev – Start dev server with demo.
  • npm run build – Build the library.
  • npm run build:demo – Build the demo app.
  • npm run test – Run tests.
  • npm run test:ui – Run tests with UI.
  • npm run test:coverage – Run tests with coverage.

Project structure:

  • src/ – Source code.
  • src/menu/ – Core menu implementation.
  • src/components/ – Vue component.
  • src/core/ – Utilities and SVG wrapper.
  • public/ – Static assets for the demo.

📄 License

MIT © alekstar79

For more examples and a live demo, visit the repository. Feel free to open issues for questions or suggestions.

About

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Context Menu TS (Vanilla/Vue3)

NPM VersionLicenseGitHubTypeScriptCoverage

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription). The library is lightweight, has no required dependencies (Vue 3 is optional), and can be easily integrated into existing projects.

slider

View Live Demo

✨ Features

🎨 Customizable appearance (colors, radii, opacity)
🖼️ SVG icon support via sprites
💬 Hints with optional background
🖱️ Hover and wheel animations
🧩 Optional central button
📦 Two usage modes: vanilla JS and Vue 3 component
⚡ Full TypeScript support (types included)

📦 Installation

npm install @alekstar79/context-menu

The library has an optional peer dependency on vue. If you are using the Vue component, install Vue 3 as well:

npm install vue@^3

🚀 Usage

  1. Vanilla JS / TypeScript
import{defineConfig,Manager}from'@alekstar79/context-menu'constconfig=defineConfig({sprite: '/path/to/icons.svg',// path to SVG spriteinnerRadius: 50,outerRadius: 150,opacity: 0.7,color: '#1976D2',sectors: [{icon: 'new',hint: 'New'},{icon: 'open',hint: 'Open'},{icon: 'save',hint: 'Save'}],centralButton: {icon: 'home',hint: 'Home',hintPosition: 'top'}})// container element where the menu will be placedconstcontainer=document.getElementById('menu-container')constmenu=newManager(container,config)// subscribe to eventsmenu.on('click',(data)=>{console.log(`Selected: ${data.hint}`)})// show menu at cursor position (e.g., on contextmenu)window.addEventListener('contextmenu',(e)=>{e.preventDefault()menu.show(e)})
  1. Vue Component
<template>
<CircularMenu
ref="menuRef"
:sprite="sprite"
:inner-radius="75"
:outer-radius="150"
:sectors="sectors"
:central-button="centralButton"
color="#42B883"
@click="onMenuItemClick"
/>
</template>
<script setup lang="ts">import { ref } from'vue'importtype { ISector } from'@alekstar79/context-menu/context-menu'importContextMenufrom'@alekstar79/context-menu/context-menu/vue'const sprite ='/icons.svg'const sectors:ISector[] = [ { icon: 'new', hint: 'New' }, { icon: 'open', hint: 'Open' }, { icon: 'save', hint: 'Save' }];const centralButton = { icon: 'home', hint: 'Home', hintPosition: 'bottom'}const menuRef =ref()const onMenuItemClick = (data: { icon:string; hint:string }) => {console.log('Selected:', data.hint)}// Example of manually showing the menuconst showMenu = (e:PointerEvent) => {menuRef.value?.show(e)}</script>

⚙️ Configuration

defineConfig(options: Partial<IConfig>): IConfig

Creates a configuration object with default values.

IConfig interface

PropertyTypeDefaultDescription
spritestring../icons.svgPath to the SVG sprite containing icons
innerRadiusnumberInner radius of sectors (the smaller ring radius)
outerRadiusnumberOuter radius of sectors
opacitynumber0.7Opacity of sectors and hint backgrounds (if any)
colorstringMain color for sectors and hint backgrounds (default '#1976D2' if omitted)
hintPaddingnumberPadding around the hint text (pixels). If not set, the hint is rendered without a background
iconScalenumberGlobal scale factor for all icons (can be overridden per sector)
iconRadiusnumberGlobal radius at which icons are placed (can be overridden per sector)
sectorsISector[][]Array of menu sectors
centralButtonICentralButtonConfiguration for the central button
autoBindContextMenubooleantrueAutomatically bind the contextmenu event listener to window

ISector interface

PropertyTypeDefaultDescription
iconstringIcon identifier (without #)
hintstringHint text
onclick() => voidClick handler for the sector
rotatenumber0Additional rotation of the icon (degrees)
iconScalenumberglobalIcon scale for this specific sector
iconRadiusnumberglobalIcon placement radius for this sector
hintPaddingnumberglobalHint padding for this sector

ICentralButton interface

PropertyTypeDefaultDescription
iconstringIcon identifier
hintstringHint text
onclick() => voidClick handler
iconScalenumberglobalIcon scale
iconRadiusnumberglobalIcon radius (effectively the button size)
hintPositiontop | bottomtopPosition of the hint relative to the button
hintSpannumber180Angular span of the hint arc (degrees)
hintDistancenumber8Distance from button edge to the hint text (when no background)
hintOffsetnumberAbsolute offset of the hint (overrides hintDistance)
hintPaddingnumberglobalHint padding for the central button
hintStartAnglenumberStart angle of the arc (must be set together with hintEndAngle)
hintEndAnglenumberEnd angle of the arc

🧠 API

Manager class (vanilla)

constmenu=newManager(container: HTMLElement,config: IConfig)

Methods

  • show(event: MouseEvent | PointerEvent) – Shows the menu at the cursor position.
  • hide() – Hides the menu.
  • on(event: string, callback: Function) – Subscribes to events.

Events

  • click – Emitted when a sector or the central button is clicked. The callback receives { icon: string; hint: string }.

Vue component CircularMenu

Props

All properties from IConfig except sectors and centralButton (they are passed separately).
Additional props:

  • autoBindContextMenu – Automatically bind contextmenu to window (default true).

Events

  • click – Same as the vanilla click event.

Exposed methods (via ref)

  • show(event: PointerEvent) – Shows the menu.
  • hide() – Hides the menu.

💅 Styling

The library comes with basic styles that are automatically included. You can override them using the following CSS classes:

  • .context – Root menu container.
  • .radial-menu-svg – The SVG element.
  • .radial-sector – A sector.
  • .radial-icon – An icon.
  • .radial-hint – Hint text.
  • .radial-hint-bg – Hint background.
  • .central-sector, .central-icon, .central-hint – Central button elements.
  • .active – Class added to hints on hover.

Example of customization:

.radial-hint {
font-size: 14px;
font-weight: 600;
fill: #000;
}

🛠️ Development

git clone <repo>cd context-menu
npm install

Scripts

  • npm run dev – Start dev server with demo.
  • npm run build – Build the library.
  • npm run build:demo – Build the demo app.
  • npm run test – Run tests.
  • npm run test:ui – Run tests with UI.
  • npm run test:coverage – Run tests with coverage.

Project structure:

  • src/ – Source code.
  • src/menu/ – Core menu implementation.
  • src/components/ – Vue component.
  • src/core/ – Utilities and SVG wrapper.
  • public/ – Static assets for the demo.

📄 License

MIT © alekstar79

For more examples and a live demo, visit the repository. Feel free to open issues for questions or suggestions.

About

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Context Menu TS (Vanilla/Vue3)

NPM VersionLicenseGitHubTypeScriptCoverage

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription). The library is lightweight, has no required dependencies (Vue 3 is optional), and can be easily integrated into existing projects.

slider

View Live Demo

✨ Features

🎨 Customizable appearance (colors, radii, opacity)
🖼️ SVG icon support via sprites
💬 Hints with optional background
🖱️ Hover and wheel animations
🧩 Optional central button
📦 Two usage modes: vanilla JS and Vue 3 component
⚡ Full TypeScript support (types included)

📦 Installation

npm install @alekstar79/context-menu

The library has an optional peer dependency on vue. If you are using the Vue component, install Vue 3 as well:

npm install vue@^3

🚀 Usage

  1. Vanilla JS / TypeScript
import{defineConfig,Manager}from'@alekstar79/context-menu'constconfig=defineConfig({sprite: '/path/to/icons.svg',// path to SVG spriteinnerRadius: 50,outerRadius: 150,opacity: 0.7,color: '#1976D2',sectors: [{icon: 'new',hint: 'New'},{icon: 'open',hint: 'Open'},{icon: 'save',hint: 'Save'}],centralButton: {icon: 'home',hint: 'Home',hintPosition: 'top'}})// container element where the menu will be placedconstcontainer=document.getElementById('menu-container')constmenu=newManager(container,config)// subscribe to eventsmenu.on('click',(data)=>{console.log(`Selected: ${data.hint}`)})// show menu at cursor position (e.g., on contextmenu)window.addEventListener('contextmenu',(e)=>{e.preventDefault()menu.show(e)})
  1. Vue Component
<template>
<CircularMenu
ref="menuRef"
:sprite="sprite"
:inner-radius="75"
:outer-radius="150"
:sectors="sectors"
:central-button="centralButton"
color="#42B883"
@click="onMenuItemClick"
/>
</template>
<script setup lang="ts">import { ref } from'vue'importtype { ISector } from'@alekstar79/context-menu/context-menu'importContextMenufrom'@alekstar79/context-menu/context-menu/vue'const sprite ='/icons.svg'const sectors:ISector[] = [ { icon: 'new', hint: 'New' }, { icon: 'open', hint: 'Open' }, { icon: 'save', hint: 'Save' }];const centralButton = { icon: 'home', hint: 'Home', hintPosition: 'bottom'}const menuRef =ref()const onMenuItemClick = (data: { icon:string; hint:string }) => {console.log('Selected:', data.hint)}// Example of manually showing the menuconst showMenu = (e:PointerEvent) => {menuRef.value?.show(e)}</script>

⚙️ Configuration

defineConfig(options: Partial<IConfig>): IConfig

Creates a configuration object with default values.

IConfig interface

PropertyTypeDefaultDescription
spritestring../icons.svgPath to the SVG sprite containing icons
innerRadiusnumberInner radius of sectors (the smaller ring radius)
outerRadiusnumberOuter radius of sectors
opacitynumber0.7Opacity of sectors and hint backgrounds (if any)
colorstringMain color for sectors and hint backgrounds (default '#1976D2' if omitted)
hintPaddingnumberPadding around the hint text (pixels). If not set, the hint is rendered without a background
iconScalenumberGlobal scale factor for all icons (can be overridden per sector)
iconRadiusnumberGlobal radius at which icons are placed (can be overridden per sector)
sectorsISector[][]Array of menu sectors
centralButtonICentralButtonConfiguration for the central button
autoBindContextMenubooleantrueAutomatically bind the contextmenu event listener to window

ISector interface

PropertyTypeDefaultDescription
iconstringIcon identifier (without #)
hintstringHint text
onclick() => voidClick handler for the sector
rotatenumber0Additional rotation of the icon (degrees)
iconScalenumberglobalIcon scale for this specific sector
iconRadiusnumberglobalIcon placement radius for this sector
hintPaddingnumberglobalHint padding for this sector

ICentralButton interface

PropertyTypeDefaultDescription
iconstringIcon identifier
hintstringHint text
onclick() => voidClick handler
iconScalenumberglobalIcon scale
iconRadiusnumberglobalIcon radius (effectively the button size)
hintPositiontop | bottomtopPosition of the hint relative to the button
hintSpannumber180Angular span of the hint arc (degrees)
hintDistancenumber8Distance from button edge to the hint text (when no background)
hintOffsetnumberAbsolute offset of the hint (overrides hintDistance)
hintPaddingnumberglobalHint padding for the central button
hintStartAnglenumberStart angle of the arc (must be set together with hintEndAngle)
hintEndAnglenumberEnd angle of the arc

🧠 API

Manager class (vanilla)

constmenu=newManager(container: HTMLElement,config: IConfig)

Methods

  • show(event: MouseEvent | PointerEvent) – Shows the menu at the cursor position.
  • hide() – Hides the menu.
  • on(event: string, callback: Function) – Subscribes to events.

Events

  • click – Emitted when a sector or the central button is clicked. The callback receives { icon: string; hint: string }.

Vue component CircularMenu

Props

All properties from IConfig except sectors and centralButton (they are passed separately).
Additional props:

  • autoBindContextMenu – Automatically bind contextmenu to window (default true).

Events

  • click – Same as the vanilla click event.

Exposed methods (via ref)

  • show(event: PointerEvent) – Shows the menu.
  • hide() – Hides the menu.

💅 Styling

The library comes with basic styles that are automatically included. You can override them using the following CSS classes:

  • .context – Root menu container.
  • .radial-menu-svg – The SVG element.
  • .radial-sector – A sector.
  • .radial-icon – An icon.
  • .radial-hint – Hint text.
  • .radial-hint-bg – Hint background.
  • .central-sector, .central-icon, .central-hint – Central button elements.
  • .active – Class added to hints on hover.

Example of customization:

.radial-hint {
font-size: 14px;
font-weight: 600;
fill: #000;
}

🛠️ Development

git clone <repo>cd context-menu
npm install

Scripts

  • npm run dev – Start dev server with demo.
  • npm run build – Build the library.
  • npm run build:demo – Build the demo app.
  • npm run test – Run tests.
  • npm run test:ui – Run tests with UI.
  • npm run test:coverage – Run tests with coverage.

Project structure:

  • src/ – Source code.
  • src/menu/ – Core menu implementation.
  • src/components/ – Vue component.
  • src/core/ – Utilities and SVG wrapper.
  • public/ – Static assets for the demo.

📄 License

MIT © alekstar79

For more examples and a live demo, visit the repository. Feel free to open issues for questions or suggestions.

About

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Context Menu TS (Vanilla/Vue3)

NPM VersionLicenseGitHubTypeScriptCoverage

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription). The library is lightweight, has no required dependencies (Vue 3 is optional), and can be easily integrated into existing projects.

slider

View Live Demo

✨ Features

🎨 Customizable appearance (colors, radii, opacity)
🖼️ SVG icon support via sprites
💬 Hints with optional background
🖱️ Hover and wheel animations
🧩 Optional central button
📦 Two usage modes: vanilla JS and Vue 3 component
⚡ Full TypeScript support (types included)

📦 Installation

npm install @alekstar79/context-menu

The library has an optional peer dependency on vue. If you are using the Vue component, install Vue 3 as well:

npm install vue@^3

🚀 Usage

  1. Vanilla JS / TypeScript
import{defineConfig,Manager}from'@alekstar79/context-menu'constconfig=defineConfig({sprite: '/path/to/icons.svg',// path to SVG spriteinnerRadius: 50,outerRadius: 150,opacity: 0.7,color: '#1976D2',sectors: [{icon: 'new',hint: 'New'},{icon: 'open',hint: 'Open'},{icon: 'save',hint: 'Save'}],centralButton: {icon: 'home',hint: 'Home',hintPosition: 'top'}})// container element where the menu will be placedconstcontainer=document.getElementById('menu-container')constmenu=newManager(container,config)// subscribe to eventsmenu.on('click',(data)=>{console.log(`Selected: ${data.hint}`)})// show menu at cursor position (e.g., on contextmenu)window.addEventListener('contextmenu',(e)=>{e.preventDefault()menu.show(e)})
  1. Vue Component
<template>
<CircularMenu
ref="menuRef"
:sprite="sprite"
:inner-radius="75"
:outer-radius="150"
:sectors="sectors"
:central-button="centralButton"
color="#42B883"
@click="onMenuItemClick"
/>
</template>
<script setup lang="ts">import { ref } from'vue'importtype { ISector } from'@alekstar79/context-menu/context-menu'importContextMenufrom'@alekstar79/context-menu/context-menu/vue'const sprite ='/icons.svg'const sectors:ISector[] = [ { icon: 'new', hint: 'New' }, { icon: 'open', hint: 'Open' }, { icon: 'save', hint: 'Save' }];const centralButton = { icon: 'home', hint: 'Home', hintPosition: 'bottom'}const menuRef =ref()const onMenuItemClick = (data: { icon:string; hint:string }) => {console.log('Selected:', data.hint)}// Example of manually showing the menuconst showMenu = (e:PointerEvent) => {menuRef.value?.show(e)}</script>

⚙️ Configuration

defineConfig(options: Partial<IConfig>): IConfig

Creates a configuration object with default values.

IConfig interface

PropertyTypeDefaultDescription
spritestring../icons.svgPath to the SVG sprite containing icons
innerRadiusnumberInner radius of sectors (the smaller ring radius)
outerRadiusnumberOuter radius of sectors
opacitynumber0.7Opacity of sectors and hint backgrounds (if any)
colorstringMain color for sectors and hint backgrounds (default '#1976D2' if omitted)
hintPaddingnumberPadding around the hint text (pixels). If not set, the hint is rendered without a background
iconScalenumberGlobal scale factor for all icons (can be overridden per sector)
iconRadiusnumberGlobal radius at which icons are placed (can be overridden per sector)
sectorsISector[][]Array of menu sectors
centralButtonICentralButtonConfiguration for the central button
autoBindContextMenubooleantrueAutomatically bind the contextmenu event listener to window

ISector interface

PropertyTypeDefaultDescription
iconstringIcon identifier (without #)
hintstringHint text
onclick() => voidClick handler for the sector
rotatenumber0Additional rotation of the icon (degrees)
iconScalenumberglobalIcon scale for this specific sector
iconRadiusnumberglobalIcon placement radius for this sector
hintPaddingnumberglobalHint padding for this sector

ICentralButton interface

PropertyTypeDefaultDescription
iconstringIcon identifier
hintstringHint text
onclick() => voidClick handler
iconScalenumberglobalIcon scale
iconRadiusnumberglobalIcon radius (effectively the button size)
hintPositiontop | bottomtopPosition of the hint relative to the button
hintSpannumber180Angular span of the hint arc (degrees)
hintDistancenumber8Distance from button edge to the hint text (when no background)
hintOffsetnumberAbsolute offset of the hint (overrides hintDistance)
hintPaddingnumberglobalHint padding for the central button
hintStartAnglenumberStart angle of the arc (must be set together with hintEndAngle)
hintEndAnglenumberEnd angle of the arc

🧠 API

Manager class (vanilla)

constmenu=newManager(container: HTMLElement,config: IConfig)

Methods

  • show(event: MouseEvent | PointerEvent) – Shows the menu at the cursor position.
  • hide() – Hides the menu.
  • on(event: string, callback: Function) – Subscribes to events.

Events

  • click – Emitted when a sector or the central button is clicked. The callback receives { icon: string; hint: string }.

Vue component CircularMenu

Props

All properties from IConfig except sectors and centralButton (they are passed separately).
Additional props:

  • autoBindContextMenu – Automatically bind contextmenu to window (default true).

Events

  • click – Same as the vanilla click event.

Exposed methods (via ref)

  • show(event: PointerEvent) – Shows the menu.
  • hide() – Hides the menu.

💅 Styling

The library comes with basic styles that are automatically included. You can override them using the following CSS classes:

  • .context – Root menu container.
  • .radial-menu-svg – The SVG element.
  • .radial-sector – A sector.
  • .radial-icon – An icon.
  • .radial-hint – Hint text.
  • .radial-hint-bg – Hint background.
  • .central-sector, .central-icon, .central-hint – Central button elements.
  • .active – Class added to hints on hover.

Example of customization:

.radial-hint {
font-size: 14px;
font-weight: 600;
fill: #000;
}

🛠️ Development

git clone <repo>cd context-menu
npm install

Scripts

  • npm run dev – Start dev server with demo.
  • npm run build – Build the library.
  • npm run build:demo – Build the demo app.
  • npm run test – Run tests.
  • npm run test:ui – Run tests with UI.
  • npm run test:coverage – Run tests with coverage.

Project structure:

  • src/ – Source code.
  • src/menu/ – Core menu implementation.
  • src/components/ – Vue component.
  • src/core/ – Utilities and SVG wrapper.
  • public/ – Static assets for the demo.

📄 License

MIT © alekstar79

For more examples and a live demo, visit the repository. Feel free to open issues for questions or suggestions.

About

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Context Menu TS (Vanilla/Vue3)

NPM VersionLicenseGitHubTypeScriptCoverage

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription). The library is lightweight, has no required dependencies (Vue 3 is optional), and can be easily integrated into existing projects.

slider

View Live Demo

✨ Features

🎨 Customizable appearance (colors, radii, opacity)
🖼️ SVG icon support via sprites
💬 Hints with optional background
🖱️ Hover and wheel animations
🧩 Optional central button
📦 Two usage modes: vanilla JS and Vue 3 component
⚡ Full TypeScript support (types included)

📦 Installation

npm install @alekstar79/context-menu

The library has an optional peer dependency on vue. If you are using the Vue component, install Vue 3 as well:

npm install vue@^3

🚀 Usage

  1. Vanilla JS / TypeScript
import{defineConfig,Manager}from'@alekstar79/context-menu'constconfig=defineConfig({sprite: '/path/to/icons.svg',// path to SVG spriteinnerRadius: 50,outerRadius: 150,opacity: 0.7,color: '#1976D2',sectors: [{icon: 'new',hint: 'New'},{icon: 'open',hint: 'Open'},{icon: 'save',hint: 'Save'}],centralButton: {icon: 'home',hint: 'Home',hintPosition: 'top'}})// container element where the menu will be placedconstcontainer=document.getElementById('menu-container')constmenu=newManager(container,config)// subscribe to eventsmenu.on('click',(data)=>{console.log(`Selected: ${data.hint}`)})// show menu at cursor position (e.g., on contextmenu)window.addEventListener('contextmenu',(e)=>{e.preventDefault()menu.show(e)})
  1. Vue Component
<template>
<CircularMenu
ref="menuRef"
:sprite="sprite"
:inner-radius="75"
:outer-radius="150"
:sectors="sectors"
:central-button="centralButton"
color="#42B883"
@click="onMenuItemClick"
/>
</template>
<script setup lang="ts">import { ref } from'vue'importtype { ISector } from'@alekstar79/context-menu/context-menu'importContextMenufrom'@alekstar79/context-menu/context-menu/vue'const sprite ='/icons.svg'const sectors:ISector[] = [ { icon: 'new', hint: 'New' }, { icon: 'open', hint: 'Open' }, { icon: 'save', hint: 'Save' }];const centralButton = { icon: 'home', hint: 'Home', hintPosition: 'bottom'}const menuRef =ref()const onMenuItemClick = (data: { icon:string; hint:string }) => {console.log('Selected:', data.hint)}// Example of manually showing the menuconst showMenu = (e:PointerEvent) => {menuRef.value?.show(e)}</script>

⚙️ Configuration

defineConfig(options: Partial<IConfig>): IConfig

Creates a configuration object with default values.

IConfig interface

PropertyTypeDefaultDescription
spritestring../icons.svgPath to the SVG sprite containing icons
innerRadiusnumberInner radius of sectors (the smaller ring radius)
outerRadiusnumberOuter radius of sectors
opacitynumber0.7Opacity of sectors and hint backgrounds (if any)
colorstringMain color for sectors and hint backgrounds (default '#1976D2' if omitted)
hintPaddingnumberPadding around the hint text (pixels). If not set, the hint is rendered without a background
iconScalenumberGlobal scale factor for all icons (can be overridden per sector)
iconRadiusnumberGlobal radius at which icons are placed (can be overridden per sector)
sectorsISector[][]Array of menu sectors
centralButtonICentralButtonConfiguration for the central button
autoBindContextMenubooleantrueAutomatically bind the contextmenu event listener to window

ISector interface

PropertyTypeDefaultDescription
iconstringIcon identifier (without #)
hintstringHint text
onclick() => voidClick handler for the sector
rotatenumber0Additional rotation of the icon (degrees)
iconScalenumberglobalIcon scale for this specific sector
iconRadiusnumberglobalIcon placement radius for this sector
hintPaddingnumberglobalHint padding for this sector

ICentralButton interface

PropertyTypeDefaultDescription
iconstringIcon identifier
hintstringHint text
onclick() => voidClick handler
iconScalenumberglobalIcon scale
iconRadiusnumberglobalIcon radius (effectively the button size)
hintPositiontop | bottomtopPosition of the hint relative to the button
hintSpannumber180Angular span of the hint arc (degrees)
hintDistancenumber8Distance from button edge to the hint text (when no background)
hintOffsetnumberAbsolute offset of the hint (overrides hintDistance)
hintPaddingnumberglobalHint padding for the central button
hintStartAnglenumberStart angle of the arc (must be set together with hintEndAngle)
hintEndAnglenumberEnd angle of the arc

🧠 API

Manager class (vanilla)

constmenu=newManager(container: HTMLElement,config: IConfig)

Methods

  • show(event: MouseEvent | PointerEvent) – Shows the menu at the cursor position.
  • hide() – Hides the menu.
  • on(event: string, callback: Function) – Subscribes to events.

Events

  • click – Emitted when a sector or the central button is clicked. The callback receives { icon: string; hint: string }.

Vue component CircularMenu

Props

All properties from IConfig except sectors and centralButton (they are passed separately).
Additional props:

  • autoBindContextMenu – Automatically bind contextmenu to window (default true).

Events

  • click – Same as the vanilla click event.

Exposed methods (via ref)

  • show(event: PointerEvent) – Shows the menu.
  • hide() – Hides the menu.

💅 Styling

The library comes with basic styles that are automatically included. You can override them using the following CSS classes:

  • .context – Root menu container.
  • .radial-menu-svg – The SVG element.
  • .radial-sector – A sector.
  • .radial-icon – An icon.
  • .radial-hint – Hint text.
  • .radial-hint-bg – Hint background.
  • .central-sector, .central-icon, .central-hint – Central button elements.
  • .active – Class added to hints on hover.

Example of customization:

.radial-hint {
font-size: 14px;
font-weight: 600;
fill: #000;
}

🛠️ Development

git clone <repo>cd context-menu
npm install

Scripts

  • npm run dev – Start dev server with demo.
  • npm run build – Build the library.
  • npm run build:demo – Build the demo app.
  • npm run test – Run tests.
  • npm run test:ui – Run tests with UI.
  • npm run test:coverage – Run tests with coverage.

Project structure:

  • src/ – Source code.
  • src/menu/ – Core menu implementation.
  • src/components/ – Vue component.
  • src/core/ – Utilities and SVG wrapper.
  • public/ – Static assets for the demo.

📄 License

MIT © alekstar79

For more examples and a live demo, visit the repository. Feel free to open issues for questions or suggestions.

About

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Context Menu TS (Vanilla/Vue3)

NPM VersionLicenseGitHubTypeScriptCoverage

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription). The library is lightweight, has no required dependencies (Vue 3 is optional), and can be easily integrated into existing projects.

slider

View Live Demo

✨ Features

🎨 Customizable appearance (colors, radii, opacity)
🖼️ SVG icon support via sprites
💬 Hints with optional background
🖱️ Hover and wheel animations
🧩 Optional central button
📦 Two usage modes: vanilla JS and Vue 3 component
⚡ Full TypeScript support (types included)

📦 Installation

npm install @alekstar79/context-menu

The library has an optional peer dependency on vue. If you are using the Vue component, install Vue 3 as well:

npm install vue@^3

🚀 Usage

  1. Vanilla JS / TypeScript
import{defineConfig,Manager}from'@alekstar79/context-menu'constconfig=defineConfig({sprite: '/path/to/icons.svg',// path to SVG spriteinnerRadius: 50,outerRadius: 150,opacity: 0.7,color: '#1976D2',sectors: [{icon: 'new',hint: 'New'},{icon: 'open',hint: 'Open'},{icon: 'save',hint: 'Save'}],centralButton: {icon: 'home',hint: 'Home',hintPosition: 'top'}})// container element where the menu will be placedconstcontainer=document.getElementById('menu-container')constmenu=newManager(container,config)// subscribe to eventsmenu.on('click',(data)=>{console.log(`Selected: ${data.hint}`)})// show menu at cursor position (e.g., on contextmenu)window.addEventListener('contextmenu',(e)=>{e.preventDefault()menu.show(e)})
  1. Vue Component
<template>
<CircularMenu
ref="menuRef"
:sprite="sprite"
:inner-radius="75"
:outer-radius="150"
:sectors="sectors"
:central-button="centralButton"
color="#42B883"
@click="onMenuItemClick"
/>
</template>
<script setup lang="ts">import { ref } from'vue'importtype { ISector } from'@alekstar79/context-menu/context-menu'importContextMenufrom'@alekstar79/context-menu/context-menu/vue'const sprite ='/icons.svg'const sectors:ISector[] = [ { icon: 'new', hint: 'New' }, { icon: 'open', hint: 'Open' }, { icon: 'save', hint: 'Save' }];const centralButton = { icon: 'home', hint: 'Home', hintPosition: 'bottom'}const menuRef =ref()const onMenuItemClick = (data: { icon:string; hint:string }) => {console.log('Selected:', data.hint)}// Example of manually showing the menuconst showMenu = (e:PointerEvent) => {menuRef.value?.show(e)}</script>

⚙️ Configuration

defineConfig(options: Partial<IConfig>): IConfig

Creates a configuration object with default values.

IConfig interface

PropertyTypeDefaultDescription
spritestring../icons.svgPath to the SVG sprite containing icons
innerRadiusnumberInner radius of sectors (the smaller ring radius)
outerRadiusnumberOuter radius of sectors
opacitynumber0.7Opacity of sectors and hint backgrounds (if any)
colorstringMain color for sectors and hint backgrounds (default '#1976D2' if omitted)
hintPaddingnumberPadding around the hint text (pixels). If not set, the hint is rendered without a background
iconScalenumberGlobal scale factor for all icons (can be overridden per sector)
iconRadiusnumberGlobal radius at which icons are placed (can be overridden per sector)
sectorsISector[][]Array of menu sectors
centralButtonICentralButtonConfiguration for the central button
autoBindContextMenubooleantrueAutomatically bind the contextmenu event listener to window

ISector interface

PropertyTypeDefaultDescription
iconstringIcon identifier (without #)
hintstringHint text
onclick() => voidClick handler for the sector
rotatenumber0Additional rotation of the icon (degrees)
iconScalenumberglobalIcon scale for this specific sector
iconRadiusnumberglobalIcon placement radius for this sector
hintPaddingnumberglobalHint padding for this sector

ICentralButton interface

PropertyTypeDefaultDescription
iconstringIcon identifier
hintstringHint text
onclick() => voidClick handler
iconScalenumberglobalIcon scale
iconRadiusnumberglobalIcon radius (effectively the button size)
hintPositiontop | bottomtopPosition of the hint relative to the button
hintSpannumber180Angular span of the hint arc (degrees)
hintDistancenumber8Distance from button edge to the hint text (when no background)
hintOffsetnumberAbsolute offset of the hint (overrides hintDistance)
hintPaddingnumberglobalHint padding for the central button
hintStartAnglenumberStart angle of the arc (must be set together with hintEndAngle)
hintEndAnglenumberEnd angle of the arc

🧠 API

Manager class (vanilla)

constmenu=newManager(container: HTMLElement,config: IConfig)

Methods

  • show(event: MouseEvent | PointerEvent) – Shows the menu at the cursor position.
  • hide() – Hides the menu.
  • on(event: string, callback: Function) – Subscribes to events.

Events

  • click – Emitted when a sector or the central button is clicked. The callback receives { icon: string; hint: string }.

Vue component CircularMenu

Props

All properties from IConfig except sectors and centralButton (they are passed separately).
Additional props:

  • autoBindContextMenu – Automatically bind contextmenu to window (default true).

Events

  • click – Same as the vanilla click event.

Exposed methods (via ref)

  • show(event: PointerEvent) – Shows the menu.
  • hide() – Hides the menu.

💅 Styling

The library comes with basic styles that are automatically included. You can override them using the following CSS classes:

  • .context – Root menu container.
  • .radial-menu-svg – The SVG element.
  • .radial-sector – A sector.
  • .radial-icon – An icon.
  • .radial-hint – Hint text.
  • .radial-hint-bg – Hint background.
  • .central-sector, .central-icon, .central-hint – Central button elements.
  • .active – Class added to hints on hover.

Example of customization:

.radial-hint {
font-size: 14px;
font-weight: 600;
fill: #000;
}

🛠️ Development

git clone <repo>cd context-menu
npm install

Scripts

  • npm run dev – Start dev server with demo.
  • npm run build – Build the library.
  • npm run build:demo – Build the demo app.
  • npm run test – Run tests.
  • npm run test:ui – Run tests with UI.
  • npm run test:coverage – Run tests with coverage.

Project structure:

  • src/ – Source code.
  • src/menu/ – Core menu implementation.
  • src/components/ – Vue component.
  • src/core/ – Utilities and SVG wrapper.
  • public/ – Static assets for the demo.

📄 License

MIT © alekstar79

For more examples and a live demo, visit the repository. Feel free to open issues for questions or suggestions.

About

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Context Menu TS (Vanilla/Vue3)

NPM VersionLicenseGitHubTypeScriptCoverage

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription). The library is lightweight, has no required dependencies (Vue 3 is optional), and can be easily integrated into existing projects.

slider

View Live Demo

✨ Features

🎨 Customizable appearance (colors, radii, opacity)
🖼️ SVG icon support via sprites
💬 Hints with optional background
🖱️ Hover and wheel animations
🧩 Optional central button
📦 Two usage modes: vanilla JS and Vue 3 component
⚡ Full TypeScript support (types included)

📦 Installation

npm install @alekstar79/context-menu

The library has an optional peer dependency on vue. If you are using the Vue component, install Vue 3 as well:

npm install vue@^3

🚀 Usage

  1. Vanilla JS / TypeScript
import{defineConfig,Manager}from'@alekstar79/context-menu'constconfig=defineConfig({sprite: '/path/to/icons.svg',// path to SVG spriteinnerRadius: 50,outerRadius: 150,opacity: 0.7,color: '#1976D2',sectors: [{icon: 'new',hint: 'New'},{icon: 'open',hint: 'Open'},{icon: 'save',hint: 'Save'}],centralButton: {icon: 'home',hint: 'Home',hintPosition: 'top'}})// container element where the menu will be placedconstcontainer=document.getElementById('menu-container')constmenu=newManager(container,config)// subscribe to eventsmenu.on('click',(data)=>{console.log(`Selected: ${data.hint}`)})// show menu at cursor position (e.g., on contextmenu)window.addEventListener('contextmenu',(e)=>{e.preventDefault()menu.show(e)})
  1. Vue Component
<template>
<CircularMenu
ref="menuRef"
:sprite="sprite"
:inner-radius="75"
:outer-radius="150"
:sectors="sectors"
:central-button="centralButton"
color="#42B883"
@click="onMenuItemClick"
/>
</template>
<script setup lang="ts">import { ref } from'vue'importtype { ISector } from'@alekstar79/context-menu/context-menu'importContextMenufrom'@alekstar79/context-menu/context-menu/vue'const sprite ='/icons.svg'const sectors:ISector[] = [ { icon: 'new', hint: 'New' }, { icon: 'open', hint: 'Open' }, { icon: 'save', hint: 'Save' }];const centralButton = { icon: 'home', hint: 'Home', hintPosition: 'bottom'}const menuRef =ref()const onMenuItemClick = (data: { icon:string; hint:string }) => {console.log('Selected:', data.hint)}// Example of manually showing the menuconst showMenu = (e:PointerEvent) => {menuRef.value?.show(e)}</script>

⚙️ Configuration

defineConfig(options: Partial<IConfig>): IConfig

Creates a configuration object with default values.

IConfig interface

PropertyTypeDefaultDescription
spritestring../icons.svgPath to the SVG sprite containing icons
innerRadiusnumberInner radius of sectors (the smaller ring radius)
outerRadiusnumberOuter radius of sectors
opacitynumber0.7Opacity of sectors and hint backgrounds (if any)
colorstringMain color for sectors and hint backgrounds (default '#1976D2' if omitted)
hintPaddingnumberPadding around the hint text (pixels). If not set, the hint is rendered without a background
iconScalenumberGlobal scale factor for all icons (can be overridden per sector)
iconRadiusnumberGlobal radius at which icons are placed (can be overridden per sector)
sectorsISector[][]Array of menu sectors
centralButtonICentralButtonConfiguration for the central button
autoBindContextMenubooleantrueAutomatically bind the contextmenu event listener to window

ISector interface

PropertyTypeDefaultDescription
iconstringIcon identifier (without #)
hintstringHint text
onclick() => voidClick handler for the sector
rotatenumber0Additional rotation of the icon (degrees)
iconScalenumberglobalIcon scale for this specific sector
iconRadiusnumberglobalIcon placement radius for this sector
hintPaddingnumberglobalHint padding for this sector

ICentralButton interface

PropertyTypeDefaultDescription
iconstringIcon identifier
hintstringHint text
onclick() => voidClick handler
iconScalenumberglobalIcon scale
iconRadiusnumberglobalIcon radius (effectively the button size)
hintPositiontop | bottomtopPosition of the hint relative to the button
hintSpannumber180Angular span of the hint arc (degrees)
hintDistancenumber8Distance from button edge to the hint text (when no background)
hintOffsetnumberAbsolute offset of the hint (overrides hintDistance)
hintPaddingnumberglobalHint padding for the central button
hintStartAnglenumberStart angle of the arc (must be set together with hintEndAngle)
hintEndAnglenumberEnd angle of the arc

🧠 API

Manager class (vanilla)

constmenu=newManager(container: HTMLElement,config: IConfig)

Methods

  • show(event: MouseEvent | PointerEvent) – Shows the menu at the cursor position.
  • hide() – Hides the menu.
  • on(event: string, callback: Function) – Subscribes to events.

Events

  • click – Emitted when a sector or the central button is clicked. The callback receives { icon: string; hint: string }.

Vue component CircularMenu

Props

All properties from IConfig except sectors and centralButton (they are passed separately).
Additional props:

  • autoBindContextMenu – Automatically bind contextmenu to window (default true).

Events

  • click – Same as the vanilla click event.

Exposed methods (via ref)

  • show(event: PointerEvent) – Shows the menu.
  • hide() – Hides the menu.

💅 Styling

The library comes with basic styles that are automatically included. You can override them using the following CSS classes:

  • .context – Root menu container.
  • .radial-menu-svg – The SVG element.
  • .radial-sector – A sector.
  • .radial-icon – An icon.
  • .radial-hint – Hint text.
  • .radial-hint-bg – Hint background.
  • .central-sector, .central-icon, .central-hint – Central button elements.
  • .active – Class added to hints on hover.

Example of customization:

.radial-hint {
font-size: 14px;
font-weight: 600;
fill: #000;
}

🛠️ Development

git clone <repo>cd context-menu
npm install

Scripts

  • npm run dev – Start dev server with demo.
  • npm run build – Build the library.
  • npm run build:demo – Build the demo app.
  • npm run test – Run tests.
  • npm run test:ui – Run tests with UI.
  • npm run test:coverage – Run tests with coverage.

Project structure:

  • src/ – Source code.
  • src/menu/ – Core menu implementation.
  • src/components/ – Vue component.
  • src/core/ – Utilities and SVG wrapper.
  • public/ – Static assets for the demo.

📄 License

MIT © alekstar79

For more examples and a live demo, visit the repository. Feel free to open issues for questions or suggestions.

About

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Context Menu TS (Vanilla/Vue3)

NPM VersionLicenseGitHubTypeScriptCoverage

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription). The library is lightweight, has no required dependencies (Vue 3 is optional), and can be easily integrated into existing projects.

slider

View Live Demo

✨ Features

🎨 Customizable appearance (colors, radii, opacity)
🖼️ SVG icon support via sprites
💬 Hints with optional background
🖱️ Hover and wheel animations
🧩 Optional central button
📦 Two usage modes: vanilla JS and Vue 3 component
⚡ Full TypeScript support (types included)

📦 Installation

npm install @alekstar79/context-menu

The library has an optional peer dependency on vue. If you are using the Vue component, install Vue 3 as well:

npm install vue@^3

🚀 Usage

  1. Vanilla JS / TypeScript
import{defineConfig,Manager}from'@alekstar79/context-menu'constconfig=defineConfig({sprite: '/path/to/icons.svg',// path to SVG spriteinnerRadius: 50,outerRadius: 150,opacity: 0.7,color: '#1976D2',sectors: [{icon: 'new',hint: 'New'},{icon: 'open',hint: 'Open'},{icon: 'save',hint: 'Save'}],centralButton: {icon: 'home',hint: 'Home',hintPosition: 'top'}})// container element where the menu will be placedconstcontainer=document.getElementById('menu-container')constmenu=newManager(container,config)// subscribe to eventsmenu.on('click',(data)=>{console.log(`Selected: ${data.hint}`)})// show menu at cursor position (e.g., on contextmenu)window.addEventListener('contextmenu',(e)=>{e.preventDefault()menu.show(e)})
  1. Vue Component
<template>
<CircularMenu
ref="menuRef"
:sprite="sprite"
:inner-radius="75"
:outer-radius="150"
:sectors="sectors"
:central-button="centralButton"
color="#42B883"
@click="onMenuItemClick"
/>
</template>
<script setup lang="ts">import { ref } from'vue'importtype { ISector } from'@alekstar79/context-menu/context-menu'importContextMenufrom'@alekstar79/context-menu/context-menu/vue'const sprite ='/icons.svg'const sectors:ISector[] = [ { icon: 'new', hint: 'New' }, { icon: 'open', hint: 'Open' }, { icon: 'save', hint: 'Save' }];const centralButton = { icon: 'home', hint: 'Home', hintPosition: 'bottom'}const menuRef =ref()const onMenuItemClick = (data: { icon:string; hint:string }) => {console.log('Selected:', data.hint)}// Example of manually showing the menuconst showMenu = (e:PointerEvent) => {menuRef.value?.show(e)}</script>

⚙️ Configuration

defineConfig(options: Partial<IConfig>): IConfig

Creates a configuration object with default values.

IConfig interface

PropertyTypeDefaultDescription
spritestring../icons.svgPath to the SVG sprite containing icons
innerRadiusnumberInner radius of sectors (the smaller ring radius)
outerRadiusnumberOuter radius of sectors
opacitynumber0.7Opacity of sectors and hint backgrounds (if any)
colorstringMain color for sectors and hint backgrounds (default '#1976D2' if omitted)
hintPaddingnumberPadding around the hint text (pixels). If not set, the hint is rendered without a background
iconScalenumberGlobal scale factor for all icons (can be overridden per sector)
iconRadiusnumberGlobal radius at which icons are placed (can be overridden per sector)
sectorsISector[][]Array of menu sectors
centralButtonICentralButtonConfiguration for the central button
autoBindContextMenubooleantrueAutomatically bind the contextmenu event listener to window

ISector interface

PropertyTypeDefaultDescription
iconstringIcon identifier (without #)
hintstringHint text
onclick() => voidClick handler for the sector
rotatenumber0Additional rotation of the icon (degrees)
iconScalenumberglobalIcon scale for this specific sector
iconRadiusnumberglobalIcon placement radius for this sector
hintPaddingnumberglobalHint padding for this sector

ICentralButton interface

PropertyTypeDefaultDescription
iconstringIcon identifier
hintstringHint text
onclick() => voidClick handler
iconScalenumberglobalIcon scale
iconRadiusnumberglobalIcon radius (effectively the button size)
hintPositiontop | bottomtopPosition of the hint relative to the button
hintSpannumber180Angular span of the hint arc (degrees)
hintDistancenumber8Distance from button edge to the hint text (when no background)
hintOffsetnumberAbsolute offset of the hint (overrides hintDistance)
hintPaddingnumberglobalHint padding for the central button
hintStartAnglenumberStart angle of the arc (must be set together with hintEndAngle)
hintEndAnglenumberEnd angle of the arc

🧠 API

Manager class (vanilla)

constmenu=newManager(container: HTMLElement,config: IConfig)

Methods

  • show(event: MouseEvent | PointerEvent) – Shows the menu at the cursor position.
  • hide() – Hides the menu.
  • on(event: string, callback: Function) – Subscribes to events.

Events

  • click – Emitted when a sector or the central button is clicked. The callback receives { icon: string; hint: string }.

Vue component CircularMenu

Props

All properties from IConfig except sectors and centralButton (they are passed separately).
Additional props:

  • autoBindContextMenu – Automatically bind contextmenu to window (default true).

Events

  • click – Same as the vanilla click event.

Exposed methods (via ref)

  • show(event: PointerEvent) – Shows the menu.
  • hide() – Hides the menu.

💅 Styling

The library comes with basic styles that are automatically included. You can override them using the following CSS classes:

  • .context – Root menu container.
  • .radial-menu-svg – The SVG element.
  • .radial-sector – A sector.
  • .radial-icon – An icon.
  • .radial-hint – Hint text.
  • .radial-hint-bg – Hint background.
  • .central-sector, .central-icon, .central-hint – Central button elements.
  • .active – Class added to hints on hover.

Example of customization:

.radial-hint {
font-size: 14px;
font-weight: 600;
fill: #000;
}

🛠️ Development

git clone <repo>cd context-menu
npm install

Scripts

  • npm run dev – Start dev server with demo.
  • npm run build – Build the library.
  • npm run build:demo – Build the demo app.
  • npm run test – Run tests.
  • npm run test:ui – Run tests with UI.
  • npm run test:coverage – Run tests with coverage.

Project structure:

  • src/ – Source code.
  • src/menu/ – Core menu implementation.
  • src/components/ – Vue component.
  • src/core/ – Utilities and SVG wrapper.
  • public/ – Static assets for the demo.

📄 License

MIT © alekstar79

For more examples and a live demo, visit the repository. Feel free to open issues for questions or suggestions.

About

A beautiful and customizable radial context menu written in TypeScript. It can be used both as a plain JavaScript/TypeScript module and as a Vue component. The project includes full TypeScript support (types are exported) and provides a simple API for controlling the menu (show/hide, event subscription).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Used by

Contributors

Languages