@furystack/shades-common-components
Version:
Common UI components for FuryStack Shades
80 lines • 3.83 kB
JavaScript
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