API Reference
Monaco Component
Monaco
is the core code editor component built on Monaco Editor and Shiki, providing rich code editing functionality.
Basic Usage
<template>
<Monaco
language="javascript"
theme="vitesse-light"
:value="code"
height="400px"
:show-toolbar="true"
:auto-resize="true"
:context-menu="{ enabled: true, items: 'full', variant: 'glass' }"
:minimap-context-menu="{ enabled: true, items: 'basic', variant: 'glass' }"
@change="handleChange"
@ready="handleReady"
/>
</template>
Props
currentLanguage
- Type:
BundledLanguage
- Default:
'javascript'
- Description: Set the current language mode of the editor
Supported languages include: javascript
, typescript
, python
, html
, css
, json
, markdown
, vue
, react
, go
, rust
, php
, java
, c
, cpp
, csharp
, etc.
<Monaco current-language="typescript" />
currentTheme
- Type:
BundledTheme
- Default:
'vitesse-light'
- Description: Set the current theme of the editor
Supported themes include: vitesse-light
, vitesse-dark
, github-light
, github-dark
, one-dark-pro
, dracula
, nord
, material-theme
, etc.
<Monaco current-theme="vitesse-dark" />
languages
- Type:
BundledLanguage[]
- Default:
['javascript', 'typescript', 'python', 'html', 'css', 'json']
- Description: List of languages supported by the editor
<Monaco :languages="['javascript', 'typescript', 'vue', 'go']" />
themes
- Type:
BundledTheme[]
- Default:
['vitesse-light', 'vitesse-dark', 'github-light', 'github-dark']
- Description: List of themes supported by the editor
<Monaco :themes="['vitesse-light', 'vitesse-dark', 'one-dark-pro']" />
value
- Type:
string
- Default:
''
- Description: Initial content of the editor
<Monaco :value="initialCode" />
height
- Type:
string
- Default:
'400px'
- Description: Height of the editor
<Monaco height="600px" />
showToolbar
- Type:
boolean
- Default:
true
- Description: Whether to show the top toolbar
<Monaco :show-toolbar="false" />
autoResize
- Type:
boolean
- Default:
true
- Description: Whether to enable automatic size adjustment
<Monaco :auto-resize="false" />
monacoEditClass
- Type:
string
- Default:
undefined
- Description: Custom CSS class name for the editor container
<Monaco monaco-edit-class="my-custom-editor" />
fileName
- Type:
string
- Default:
undefined
- Description: File name displayed in the toolbar
<Monaco file-name="main.ts" />
contextMenu
- Type:
ContextMenuConfig
- Default:
{ enabled: true, items: 'full', variant: 'glass' }
- Description: Editor area custom context menu configuration
ContextMenuConfig Interface
interface ContextMenuConfig {
enabled?: boolean; // Whether to enable context menu
items?: string[] | "minimal" | "basic" | "full"; // Menu item configuration
customItems?: ContextMenuItem[]; // Custom menu items
variant?: "classic" | "glass"; // Menu style variant
teleportTarget?: string | HTMLElement; // Menu mount target
}
Preset Menu Configurations
<!-- Minimal menu: copy, paste, select all -->
<Monaco :context-menu="{ enabled: true, items: 'minimal', variant: 'glass' }" />
<!-- Basic menu: copy, cut, paste, select all, undo, redo -->
<Monaco :context-menu="{ enabled: true, items: 'basic', variant: 'glass' }" />
<!-- Full menu: all features -->
<Monaco :context-menu="{ enabled: true, items: 'full', variant: 'glass' }" />
<!-- Classic style menu -->
<Monaco :context-menu="{ enabled: true, items: 'full', variant: 'classic' }" />
<!-- Custom menu items -->
<Monaco
:context-menu="{
enabled: true,
items: ['copy', 'paste', 'selectAll'],
variant: 'glass',
teleportTarget: '.my-menu-container',
customItems: [
{
type: 'separator',
},
{
type: 'item',
id: 'custom-action',
label: 'Custom Action',
shortcut: 'Ctrl+Shift+X',
action: () => console.log('Custom action'),
},
],
}"
/>
<!-- Specify menu mount to specific DOM element -->
<Monaco
:context-menu="{
enabled: true,
items: 'full',
variant: 'glass',
teleportTarget: document.getElementById('menu-container'),
}"
/>
teleportTarget
- Type:
string | HTMLElement
- Default:
'.monaco-editor'
- Description: Specify the mount target for the context menu to control where the menu is rendered
<!-- Mount to specific selector -->
<Monaco teleport-target=".my-container" />
<!-- Mount to DOM element -->
<Monaco :teleport-target="myElement" />
minimapContextMenu
- Type:
MinimapContextMenuConfig
- Default:
{ enabled: true, items: 'basic', variant: 'glass' }
- Description: Minimap area specific context menu configuration
MinimapContextMenuConfig Interface
interface MinimapContextMenuConfig {
enabled?: boolean; // Whether to enable Minimap context menu
items?: string[] | "minimal" | "basic" | "full"; // Menu item configuration
customItems?: ContextMenuItem[]; // Custom menu items
variant?: "classic" | "glass"; // Menu style variant
teleportTarget?: string | HTMLElement; // Menu mount target
}
Minimap Menu Examples
<!-- Minimap basic menu -->
<Monaco
:minimap-context-menu="{ enabled: true, items: 'basic', variant: 'glass' }"
/>
<!-- Minimap full menu -->
<Monaco
:minimap-context-menu="{ enabled: true, items: 'full', variant: 'glass' }"
/>
<!-- Disable Minimap menu -->
<Monaco :minimap-context-menu="{ enabled: false }" />
Events
change
- Parameters:
(value: string) => void
- Description: Triggered when editor content changes
<Monaco @change="handleCodeChange" />
ready
- Parameters:
(editor: EditInstance) => void
- Description: Triggered when editor initialization is complete
<Monaco @ready="handleEditorReady" />
Slots
toolbar
- Description: Custom toolbar content
<Monaco>
<template #toolbar>
<div class="custom-toolbar">
<button @click="runCode">Run Code</button>
<button @click="saveCode">Save</button>
<button @click="shareCode">Share</button>
</div>
</template>
</Monaco>
Exposed Methods
The following methods can be accessed through ref
:
getEditor()
- Returns:
EditInstance | null
- Description: Get Monaco Editor instance
<script setup>
const monacoRef = ref();
const getEditorInstance = () => {
const editor = monacoRef.value?.getEditor();
if (editor) {
console.log("Editor instance:", editor);
}
};
</script>
setValue(value: string)
- Parameters:
value
- Code content to set - Description: Set editor content
<script setup>
const monacoRef = ref();
const updateCode = () => {
monacoRef.value?.setValue('console.log("New code")');
};
</script>
getValue()
- Returns:
string
- Description: Get current editor content
<script setup>
const monacoRef = ref();
const getCurrentCode = () => {
const code = monacoRef.value?.getValue();
console.log("Current code:", code);
};
</script>
focus()
- Description: Give focus to the editor
<script setup>
const monacoRef = ref();
const focusEditor = () => {
monacoRef.value?.focus();
};
</script>
setTheme(theme: BundledTheme)
- Parameters:
theme
- Theme to switch to - Description: Dynamically switch editor theme
<script setup>
const monacoRef = ref();
const switchTheme = () => {
monacoRef.value?.setTheme("vitesse-dark");
};
</script>
setLanguage(language: BundledLanguage)
- Parameters:
language
- Language to switch to - Description: Dynamically switch editor language
<script setup>
const monacoRef = ref();
const switchLanguage = () => {
monacoRef.value?.setLanguage("typescript");
};
</script>
layout()
- Description: Manually trigger editor layout update
<script setup>
const monacoRef = ref();
const refreshLayout = () => {
monacoRef.value?.layout();
};
</script>
enableAutoResize()
- Description: Enable automatic size adjustment
<script setup>
const monacoRef = ref();
const enableResize = () => {
monacoRef.value?.enableAutoResize();
};
</script>
disableAutoResize()
- Description: Disable automatic size adjustment
<script setup>
const monacoRef = ref();
const disableResize = () => {
monacoRef.value?.disableAutoResize();
};
</script>
copyCode()
- Description: Copy current code to clipboard (supports multiple strategies)
<script setup>
const monacoRef = ref();
const copyCurrentCode = () => {
monacoRef.value?.copyCode();
};
</script>
pasteCode()
- Description: Paste content from clipboard to editor (supports multiple strategies)
<script setup>
const monacoRef = ref();
const pasteFromClipboard = () => {
monacoRef.value?.pasteCode();
};
</script>
formatCode()
- Description: Format current code
<script setup>
const monacoRef = ref();
const formatCurrentCode = () => {
monacoRef.value?.formatCode();
};
</script>
useMonacoEdit Hook
useMonacoEdit
is the underlying editor initialization hook used for creating and managing Monaco Editor instances.
Basic Usage
import { useMonacoEdit } from "vue-shiki-monaco";
const { initMonacoEdit, destroy, setTheme, setLanguage } = useMonacoEdit({
target: editorElement,
languages: ["javascript", "typescript"],
themes: ["vitesse-light", "vitesse-dark"],
codeValue: 'console.log("Hello World")',
defaultTheme: "vitesse-light",
defaultLanguage: "javascript",
contextMenu: {
enabled: true,
items: "full",
},
});
Parameters
MonacoOptions
interface MonacoOptions
extends monaco.editor.IStandaloneEditorConstructionOptions {
target: HTMLElement; // Target element to mount the editor
languages: BundledLanguage[]; // List of supported languages
codeValue: string; // Initial code content
themes: BundledTheme[]; // List of supported themes
defaultTheme: BundledTheme; // Default theme
defaultLanguage: BundledLanguage; // Default language
contextMenu?: {
// Context menu configuration
enabled?: boolean;
items?: string[] | "minimal" | "basic" | "full";
customItems?: ContextMenuItem[];
};
}
Return Value
UseMonacoEditReturn
interface UseMonacoEditReturn {
initMonacoEdit: () => Promise<EditInstance>; // Initialize editor
destroy: () => void; // Destroy editor
registerLanguage: (language: string) => void; // Register new language
setTheme: (theme: BundledTheme) => Promise<void>; // Switch theme
setLanguage: (language: BundledLanguage) => Promise<void>; // Switch language
layout: () => void; // Re-layout
enableAutoResize: () => void; // Enable auto resize
disableAutoResize: () => void; // Disable auto resize
editInstance: EditInstance | null; // Editor instance
onContextMenu: (callback: (event: MouseEvent) => void) => void; // Editor context menu callback
offContextMenu: () => void; // Remove editor context menu callback
onMinimapContextMenu: (callback: (event: MouseEvent) => void) => void; // Minimap context menu callback
offMinimapContextMenu: () => void; // Remove Minimap context menu callback
}
MonacoDiff Component
MonacoDiff
is a specialized component for displaying code difference comparisons, built on Monaco Editor's Diff Editor, providing powerful code comparison functionality.
Basic Usage
<template>
<MonacoDiff
:old-model="oldCode"
:new-model="newCode"
language="typescript"
theme="vitesse-light"
height="500px"
:show-toolbar="true"
:auto-resize="true"
:context-menu="{ enabled: true, items: 'full', variant: 'glass' }"
:minimap-context-menu="{ enabled: true, items: 'basic', variant: 'glass' }"
@change="handleChange"
@ready="handleReady"
/>
</template>
Props
oldModel
- Type:
string
- Required:
true
- Description: Original code content (displayed in left editor)
<MonacoDiff old-model="const a = 1;" />
newModel
- Type:
string
- Required:
true
- Description: Modified code content (displayed in right editor)
<MonacoDiff new-model="const a = 2;" />
diffViewType
- Type:
'default' | 'inline' | 'unified'
- Default:
'default'
- Description: Difference display mode
<!-- Default side-by-side mode -->
<MonacoDiff diff-view-type="default" />
<!-- Inline mode -->
<MonacoDiff diff-view-type="inline" />
<!-- Unified mode -->
<MonacoDiff diff-view-type="unified" />
currentLanguage
- Type:
BundledLanguage
- Default:
'typescript'
- Description: Code language mode
<MonacoDiff current-language="javascript" />
currentTheme
- Type:
BundledTheme
- Default:
'vitesse-light'
- Description: Editor theme
<MonacoDiff current-theme="vitesse-dark" />
languages
- Type:
BundledLanguage[]
- Default:
['typescript']
- Description: List of supported languages
<MonacoDiff :languages="['typescript', 'javascript', 'vue']" />
themes
- Type:
BundledTheme[]
- Default:
['vitesse-light', 'vitesse-dark']
- Description: List of supported themes
<MonacoDiff :themes="['vitesse-light', 'vitesse-dark', 'github-light']" />
height
- Type:
string
- Default:
'400px'
- Description: Editor height
<MonacoDiff height="600px" />
showToolbar
- Type:
boolean
- Default:
true
- Description: Whether to show the top toolbar (including diff navigation)
<MonacoDiff :show-toolbar="false" />
autoResize
- Type:
boolean
- Default:
true
- Description: Whether to enable automatic size adjustment
<MonacoDiff :auto-resize="false" />
fileName
- Type:
string
- Default:
'Untitled'
- Description: File name displayed in the toolbar
<MonacoDiff file-name="app.ts" />
contextMenu
- Type:
ContextMenuConfig
- Default:
{ enabled: true, items: 'full', variant: 'glass' }
- Description: Editor area context menu configuration
<!-- Original editor (left): copy, find/replace, font adjustment -->
<!-- Modified editor (right): full functionality menu -->
<MonacoDiff
:context-menu="{
enabled: true,
items: 'full',
variant: 'glass',
}"
/>
minimapContextMenu
- Type:
MinimapContextMenuConfig
- Default:
{ enabled: true, items: 'basic', variant: 'glass' }
- Description: Minimap area context menu configuration
<MonacoDiff
:minimap-context-menu="{
enabled: true,
items: 'basic',
variant: 'glass',
}"
/>
Events
change
- Parameters:
(value: string) => void
- Description: Triggered when the modified editor (right) content changes
<MonacoDiff @change="handleDiffChange" />
ready
- Parameters:
(editor: DiffEditInstance) => void
- Description: Triggered when the diff editor initialization is complete
<MonacoDiff @ready="handleDiffEditorReady" />
Exposed Methods
The following methods can be accessed through ref
:
getEditor()
- Returns:
DiffEditInstance | null
- Description: Get Monaco Diff Editor instance
<script setup>
const diffRef = ref();
const getDiffEditorInstance = () => {
const editor = diffRef.value?.getEditor();
if (editor) {
console.log("Diff editor instance:", editor);
// Access getOriginalEditor() and getModifiedEditor()
const originalEditor = editor.getOriginalEditor();
const modifiedEditor = editor.getModifiedEditor();
}
};
</script>
focus()
- Description: Give focus to the modified editor (right)
<script setup>
const diffRef = ref();
const focusDiffEditor = () => {
diffRef.value?.focus();
};
</script>
setTheme(theme: BundledTheme)
- Parameters:
theme
- Theme to switch to - Description: Dynamically switch editor theme
<script setup>
const diffRef = ref();
const switchTheme = () => {
diffRef.value?.setTheme("vitesse-dark");
};
</script>
layout()
- Description: Manually trigger editor layout update
<script setup>
const diffRef = ref();
const refreshLayout = () => {
diffRef.value?.layout();
};
</script>
enableAutoResize() / disableAutoResize()
- Description: Enable or disable automatic size adjustment
<script setup>
const diffRef = ref();
const toggleAutoResize = () => {
diffRef.value?.enableAutoResize();
// or
diffRef.value?.disableAutoResize();
};
</script>
Toolbar Features
The MonacoDiff component toolbar includes the following diff navigation features:
- Diff Counter: Shows current diff position and total count (e.g., "2 / 5")
- Previous Diff Button: Jump to previous diff location
- Next Diff Button: Jump to next diff location
- Collapse/Expand Button: Collapse or expand unchanged code regions
Special Features
Diff Navigation
- Automatically detects code difference count
- Supports circular navigation (jump from last diff to first)
- Auto-scroll to diff position and center display
Context Menu Hierarchy
- Original Editor (Left): Read-only mode, provides copy, find/replace, font adjustment
- Modified Editor (Right): Full editing functionality, supports all menu items
Copy Functionality
- Toolbar copy button defaults to copying modified content (right editor)
- Supports modern clipboard API and fallback solutions
useMonacoDiffEdit Hook
useMonacoDiffEdit
is a specialized hook for creating and managing Monaco Diff Editor instances.
Basic Usage
import { useMonacoDiffEdit } from "vue-shiki-monaco";
const diffHook = useMonacoDiffEdit({
target: diffEditorElement,
languages: ["typescript", "javascript"],
themes: ["vitesse-light", "vitesse-dark"],
defaultTheme: "vitesse-light",
contextMenu: {
enabled: true,
items: "full",
},
});
// Initialize diff editor
const diffEditor = await diffHook.initMonacoDiffEdit();
// Create models
const originalModel = diffHook.createModel(oldCode, "typescript");
const modifiedModel = diffHook.createModel(newCode, "typescript");
// Set diff model
diffHook.setDiffModel({
original: originalModel,
modified: modifiedModel,
});
Parameters
MonacoDiffOptions
interface MonacoDiffOptions {
target: HTMLElement; // Target element to mount the editor
languages: BundledLanguage[]; // List of supported languages
themes: BundledTheme[]; // List of supported themes
defaultTheme: BundledTheme; // Default theme
diffViewType?: "default" | "inline" | "unified"; // Diff display mode
contextMenu?: {
enabled?: boolean;
items?: string[] | "minimal" | "basic" | "full";
customItems?: ContextMenuItem[];
};
}
Return Value
UseMonacoDiffEditReturn
interface UseMonacoDiffEditReturn {
initMonacoDiffEdit: () => Promise<DiffEditInstance>; // Initialize diff editor
createModel: (content: string, language: string) => any; // Create model
setDiffModel: (models: { original: any; modified: any }) => void; // Set diff model
setDiffViewOptions: (viewType: string) => void; // Set diff view type
setTheme: (theme: BundledTheme) => Promise<void>; // Switch theme
layout: () => void; // Re-layout
enableAutoResize: () => void; // Enable auto resize
disableAutoResize: () => void; // Disable auto resize
destroy: (target: HTMLElement) => void; // Destroy editor
onOriginalContextMenu: (callback: (event: MouseEvent) => void) => void; // Original editor context menu
onModifiedContextMenu: (callback: (event: MouseEvent) => void) => void; // Modified editor context menu
onMinimapContextMenu: (callback: (event: MouseEvent) => void) => void; // Minimap context menu
}
useContextMenu Hook
useContextMenu
is a hook for managing custom context menus.
Basic Usage
import { useContextMenu } from "vue-shiki-monaco";
const contextMenu = useContextMenu({
items: [
{
type: "item",
id: "copy",
label: "Copy",
shortcut: "Ctrl+C",
action: () => console.log("Copy"),
},
{ type: "separator" },
{
type: "item",
id: "paste",
label: "Paste",
shortcut: "Ctrl+V",
action: () => console.log("Paste"),
},
],
target: ".monaco-editor", // Specify menu target container
});
Parameters and Return Values
UseContextMenuOptions
interface UseContextMenuOptions {
items: ContextMenuItem[]; // Menu item list
target?: string | HTMLDivElement; // Menu target container
onShow?: () => void; // Show callback
onHide?: () => void; // Hide callback
}
UseContextMenuReturn
interface UseContextMenuReturn {
isVisible: Ref<boolean>; // Menu visibility
position: ContextMenuPosition; // Menu position
items: Ref<ContextMenuItem[]>; // Menu items
show: (
event: MouseEvent,
menuItems: ContextMenuItem[],
target?: HTMLDivElement,
) => void; // Show menu, supports dynamic target specification
hide: () => void; // Hide menu
handleItemClick: (item: MenuItem) => void; // Handle menu item click
updateTarget: (target: HTMLDivElement) => void; // Update target element
}
Context Menu Refactoring Improvements
In the latest version, the useContextMenu
hook has undergone important refactoring optimizations:
Smart Target Finding
- Automatic Container Finding: Added intelligent finding functionality in the
show
method. When no target element is specified, it automatically searches up for the nearest.monaco-editor
or.monaco-diff-editor
container - Dynamic Target Specification: The
show
method adds atarget
parameter, allowing dynamic specification of target elements when displaying the menu - Update Target Method: Added
updateTarget
method, allowing target element updates before displaying the menu
Usage Examples
import { useContextMenu } from "vue-shiki-monaco";
const contextMenu = useContextMenu({
items: menuItems,
});
// Method 1: Let system automatically find nearest editor container
contextMenu.show(event, menuItems);
// Method 2: Dynamically specify target container
const targetElement = document.querySelector(".my-editor-container");
contextMenu.show(event, menuItems, targetElement);
// Method 3: Update target then show
contextMenu.updateTarget(myEditorElement);
contextMenu.show(event, menuItems);
Improvement Effects
- More Accurate Positioning: Menu can automatically find the correct editor container, ensuring menu displays at appropriate position
- More Flexible Usage: Supports dynamic target switching in multi-editor scenarios
- Better Compatibility: Supports both Monaco Editor and Monaco Diff Editor containers
TypeScript Type Definitions
Monaco Component Types
import type { BundledLanguage, BundledTheme } from "shiki";
import type { EditInstance } from "vue-shiki-monaco";
// Component Props
interface MonacoProps {
currentLanguage?: BundledLanguage;
currentTheme?: BundledTheme;
languages?: BundledLanguage[];
themes?: BundledTheme[];
value?: string;
height?: string;
showToolbar?: boolean;
autoResize?: boolean;
monacoEditClass?: string;
fileName?: string;
teleportTarget?: string | HTMLElement; // Menu mount target
contextMenu?: {
enabled?: boolean;
items?: string[] | "minimal" | "basic" | "full";
customItems?: ContextMenuItem[];
teleportTarget?: string | HTMLElement; // Menu mount target
};
minimapContextMenu?: {
enabled?: boolean;
items?: string[] | "minimal" | "basic" | "full";
customItems?: ContextMenuItem[];
variant?: "classic" | "glass";
teleportTarget?: string | HTMLElement; // Menu mount target
};
}
// Component Emits
interface MonacoEmits {
change: [value: string];
ready: [editor: EditInstance];
}
// Editor instance type
type EditInstance = monaco.editor.IStandaloneCodeEditor;
MonacoDiff Component Types
import type { BundledLanguage, BundledTheme } from "shiki";
import type { DiffEditInstance } from "vue-shiki-monaco";
// MonacoDiff Component Props
interface MonacoDiffProps {
oldModel: string; // Original code content
newModel: string; // Modified code content
diffViewType?: "default" | "inline" | "unified"; // Diff display mode
currentLanguage?: BundledLanguage;
currentTheme?: BundledTheme;
languages?: BundledLanguage[];
themes?: BundledTheme[];
height?: string;
showToolbar?: boolean;
autoResize?: boolean;
monacoEditClass?: string;
fileName?: string;
teleportTarget?: string | HTMLElement;
contextMenu?: {
enabled?: boolean;
items?: string[] | "minimal" | "basic" | "full";
customItems?: ContextMenuItem[];
variant?: "classic" | "glass";
};
minimapContextMenu?: {
enabled?: boolean;
items?: string[] | "minimal" | "basic" | "full";
customItems?: ContextMenuItem[];
variant?: "classic" | "glass";
};
}
// MonacoDiff Component Emits
interface MonacoDiffEmits {
change: [value: string]; // Modified editor content change
ready: [editor: DiffEditInstance]; // Diff editor ready
}
// Diff editor instance type
type DiffEditInstance = monaco.editor.IStandaloneDiffEditor;
Hook Types
import type * as monaco from "monaco-editor-core";
import type { BundledLanguage, BundledTheme } from "shiki";
// Hook options
interface MonacoOptions
extends monaco.editor.IStandaloneEditorConstructionOptions {
target: HTMLElement;
languages: BundledLanguage[];
codeValue: string;
themes: BundledTheme[];
defaultTheme: BundledTheme;
defaultLanguage: BundledLanguage;
contextMenu?: {
enabled?: boolean;
items?: string[] | "minimal" | "basic" | "full";
customItems?: ContextMenuItem[];
};
}
// Hook return value
interface UseMonacoEditReturn {
initMonacoEdit: () => Promise<EditInstance>;
destroy: () => void;
registerLanguage: (language: string) => void;
setTheme: (theme: BundledTheme) => Promise<void>;
setLanguage: (language: BundledLanguage) => Promise<void>;
layout: () => void;
enableAutoResize: () => void;
disableAutoResize: () => void;
editInstance: EditInstance | null;
onContextMenu: (callback: (event: MouseEvent) => void) => void;
offContextMenu: () => void;
}
// Editor instance
type EditInstance = monaco.editor.IStandaloneCodeEditor;
Context Menu Types
// Menu position
interface ContextMenuPosition {
x: number;
y: number;
direction?: "down" | "up"; // Menu display direction
}
// Menu item
interface MenuItem {
type: "item";
id: string;
label: string;
icon?: string;
shortcut?: string;
disabled?: boolean;
action: () => void;
}
// Separator
interface MenuItemSeparator {
type: "separator";
}
// Union type
type ContextMenuItem = MenuItem | MenuItemSeparator;
// Menu preset
type MenuPreset = "minimal" | "basic" | "full";