Jhana UI uses a singleton Svelte component. You have to include this once in your root layout. Then you can use the context menu system across your whole app.
<script lang="ts"> import { CtxMenuRoot } from '@leon8ix/jhana-ui/ctx-menu'; import { menuGlobal, menuTagMap } from '$lib/menus'; </script> <CtxMenuRoot menu={menuGlobal} tags={menuTagMap} />
I like to have a single file that contains all context menus used by the app. However you can also write them specifically in those Svelte components or pages, where you actually need them.
import { iconPrint, iconReset, iconStore, iconUrl } from '@leon8ix/jhana-ui'; import type { CtxMenuConfig } from '@leon8ix/jhana-ui/ctx-menu'; import { app } from './app-state.svelte'; import { iconSwatch, iconSideCover, iconSideSpineBot, iconSideSpineTop } from './icons'; export const menuPrint: CtxMenuConfig = { anchor: 'right', items: [ 'Print side', { text: 'Cover', icon: iconSideCover, action: () => app.print('cover') }, { text: 'Spine top', icon: iconSideSpineTop, action: () => app.print('spine-top') }, { text: 'Spine bot', icon: iconSideSpineBot, action: () => app.print('spine-bot') }, ], }; export const menuStore: CtxMenuConfig = { anchor: 'right', items: [ 'Store with suffix', { text: 'Silver', icon: iconSwatch, color: '#c4c4c4', action: () => app.store('Silber') }, { text: 'Gold', icon: iconSwatch, color: '#d0a949', action: () => app.store('Gold') }, { text: 'White', icon: iconSwatch, color: '#f0f0f0', action: () => app.store('Weiß') }, 'Export', { text: 'Copy as URL', icon: iconUrl, action: () => app.copyAsUrl() }, ], }; export const menuGlobal: CtxMenuConfig = { items: [ { text: 'Reset', kbd: 'R', icon: iconReset, action: () => app.reset() }, { text: 'Print', kbd: 'CTRL+P', icon: iconPrint, action: () => app.print(), items: menuPrint.items }, { text: 'Store', kbd: 'CTRL+S', icon: iconStore, action: () => app.store(), items: menuStore.items }, ], };
You can also set up global behavior for specific element tags.
import { iconCopy, iconCut, iconPaste } from '@leon8ix/jhana-ui'; import type { CtxMenuConfig, CtxMenuTagMap } from '@leon8ix/jhana-ui/ctx-menu'; import { copy, cut, paste } from '@leon8ix/jhana-ui/ctx-menu'; import type { MapKey, MapValue } from '@leon8ix/utils'; export const menuInputs: CtxMenuConfig = { items: [ { text: 'Copy', icon: iconCopy, action: () => copy() }, { text: 'Cut', icon: iconCut, action: () => cut() }, { text: 'Paste', icon: iconPaste, action: () => paste() }, ], }; export const menuTagMap: CtxMenuTagMap = new Map<MapKey<CtxMenuTagMap>, MapValue<CtxMenuTagMap>>([ ['input', menuInputs], ['textarea', menuInputs], ['button', false], ['a', 'browser'], ]);
You've seen how you can set a global context menu, but of course you can bind one to any element.
<script lang="ts"> import { iconStore } from '@leon8ix/jhana-ui'; import { ctxMenu, openMenu, type CtxMenuConfig, type CtxMenuItem } from '@leon8ix/jhana-ui/ctx-menu'; import { delay } from '@leon8ix/utils/dom'; const menuItems: CtxMenuItem[] = [ { text: 'Basic Action Sync', icon: iconStore, action: () => null }, { text: 'Async Action 5s', icon: iconStore, action: () => delay(5000) }, { text: 'Async Action 500ms', icon: iconStore, action: () => delay(500) }, ]; const menuL: CtxMenuConfig = { items: menuItems, anchor: 'left' }; const menuC: CtxMenuConfig = { items: menuItems, anchor: 'center' }; const menuR: CtxMenuConfig = { items: menuItems, anchor: 'right' }; </script> <!-- Since there is a global context menu system handling the contextmenu event, you can not use oncontextmenu={openMenu}, as this would interfere with the global handling. The attachment handles the setup for that system. For normal clicks, there is no such global system, so just use onclick={openMenu(menu)} --> <div class="btn-group"> <button class="btn" onclick={openMenu(menuL)}>Left click me</button> <button class="btn" {@attach ctxMenu(menuC)}>Right click me</button> <button class="btn" onclick={openMenu(menuR)} {@attach ctxMenu(menuR)}>Any click me</button> </div>