UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

80 lines 3.83 kB
import { createComponent, Shade } from '@furystack/shades'; import { cssVariableTheme } from '../../services/css-variable-theme.js'; import { ContextMenuItemComponent } from './context-menu-item.js'; export const ContextMenu = Shade({ customElementName: 'shade-context-menu', css: { fontFamily: cssVariableTheme.typography.fontFamily, '& .context-menu-backdrop': { opacity: '0', transition: `opacity ${cssVariableTheme.transitions.duration.fast} ease-out`, }, '& .context-menu-backdrop.visible': { opacity: '1', }, '& .context-menu-container': { opacity: '0', transform: 'scale(0.95) translateY(-4px)', transition: `opacity ${cssVariableTheme.transitions.duration.fast} ease-out, transform ${cssVariableTheme.transitions.duration.fast} ease-out`, transformOrigin: 'top left', }, '& .context-menu-container.visible': { opacity: '1', transform: 'scale(1) translateY(0)', }, }, render: ({ props, useObservable, useDisposable, useState }) => { useDisposable('keydown-handler', () => { const listener = (ev) => { props.manager.handleKeyDown(ev); }; window.addEventListener('keydown', listener, true); return { [Symbol.dispose]: () => window.removeEventListener('keydown', listener, true) }; }); const { manager, onItemSelect } = props; useDisposable('onItemSelect', () => manager.subscribe('onSelectItem', (item) => onItemSelect?.(item))); const [isOpened] = useObservable('isOpened', manager.isOpened); const [items] = useObservable('items', manager.items); const [position] = useObservable('position', manager.position); const [isVisible, setIsVisible] = useState('isVisible', false); if (!isOpened) { return null; } requestAnimationFrame(() => { requestAnimationFrame(() => setIsVisible(true)); }); return (createComponent("div", { className: `context-menu-backdrop${isVisible ? ' visible' : ''}`, style: { position: 'fixed', top: '0', left: '0', width: '100%', height: '100%', zIndex: '9999', }, onclick: () => manager.close(), oncontextmenu: (ev) => { ev.preventDefault(); manager.close(); } }, createComponent("div", { role: "menu", className: `context-menu-container${isVisible ? ' visible' : ''}`, style: { position: 'absolute', left: `${position.x}px`, top: `${position.y}px`, minWidth: '200px', background: cssVariableTheme.background.paper, borderRadius: cssVariableTheme.shape.borderRadius.md, boxShadow: cssVariableTheme.shadows.lg, border: `1px solid ${cssVariableTheme.divider}`, padding: '4px 0', overflow: 'hidden', }, onclick: (ev) => ev.stopPropagation() }, items.map((item, index) => { if (item.type === 'separator') { return (createComponent("div", { role: "separator", className: "context-menu-separator", style: { height: '1px', margin: '4px 8px', backgroundColor: cssVariableTheme.divider, } })); } return createComponent(ContextMenuItemComponent, { item: item, index: index, manager: manager }); })))); }, }); //# sourceMappingURL=context-menu.js.map