schlechtenburg/packages/core/lib/components/ContextMenu.tsx

85 lines
2 KiB
TypeScript
Raw Normal View History

2021-02-22 18:13:37 +00:00
import {
watch,
defineComponent,
ref,
2022-03-12 16:16:24 +00:00
Ref,
2021-02-22 18:13:37 +00:00
} from 'vue';
import { SbButton } from './Button';
import './ContextMenu.scss';
2022-03-12 16:16:24 +00:00
export interface IContextMenuSlotContext {
opened: Ref<boolean>;
open: () => void;
close: () => void;
toggle: () => void;
}
2021-02-22 18:13:37 +00:00
export const SbContextMenu = defineComponent({
name: 'sb-context-menu',
props: {
onClose: { type: Function, default: () => {} },
onOpen: { type: Function, default: () => {} },
},
2021-03-08 15:29:35 +00:00
setup(props, context) {
2021-02-22 18:13:37 +00:00
const opened = ref(false);
2021-02-22 23:12:06 +00:00
const open = () => { opened.value = true; };
const close = () => { opened.value = false; };
2021-02-22 18:13:37 +00:00
const closeOnEscape = ($event: KeyboardEvent) => {
if ($event.key === 'Escape') {
close();
}
};
2021-02-22 23:12:06 +00:00
const toggle = () => { opened.value ? close() : open() };
2021-02-22 18:13:37 +00:00
2021-02-22 23:12:06 +00:00
watch(opened, (curr, prev) => {
if (curr === prev) {
return;
}
if (!curr) {
document.body.removeEventListener('click', close);
document.body.removeEventListener('keypress', closeOnEscape);
2021-03-08 15:29:35 +00:00
props.onClose();
2021-02-22 23:12:06 +00:00
} else {
setTimeout(() => {
document.body.addEventListener('click', close);
document.body.addEventListener('keypress', closeOnEscape);
2021-03-08 15:29:35 +00:00
props.onOpen();
2021-02-22 23:12:06 +00:00
});
2021-02-22 18:13:37 +00:00
}
});
return () => (
2021-02-22 23:12:06 +00:00
<div class="sb-context">
2021-02-22 18:13:37 +00:00
{
2021-03-08 15:29:35 +00:00
context.slots.context?.({
2021-02-22 18:13:37 +00:00
opened,
toggle,
close,
open,
2021-03-08 15:29:35 +00:00
}) || <SbButton {...{ onClick: toggle }}>Menu</SbButton>
2021-02-22 18:13:37 +00:00
}
<dialog
2021-02-22 23:12:06 +00:00
class="sb-context-menu"
open={opened.value ? true : undefined}
2021-02-22 18:13:37 +00:00
onClick={($event: Event) => {
// Make sure clicks inside do not autoclose this
2021-02-22 23:12:06 +00:00
$event.stopPropagation();
2021-02-22 18:13:37 +00:00
}}
2021-03-08 15:29:35 +00:00
{...{ onClose: close /* TODO: DialogHTMLAttributes needs an onClose handler type */ }}
2021-02-22 18:13:37 +00:00
>
2021-03-08 15:29:35 +00:00
{context.slots.default?.({
2021-02-22 18:13:37 +00:00
opened,
toggle,
close,
open,
}) || null}
</dialog>
</div>
);
},
});