Newer
Older
gnexus-ui-kit / src / vue / components / GnPopover.js
@Eugene Sukhodolskiy Eugene Sukhodolskiy 13 hours ago 1 KB Add Vue navigation overlay adapters
import { defineComponent, h, onBeforeUnmount, ref } from "vue";
import { cx } from "../utils.js";
import GnButton from "./GnButton.js";

export default defineComponent({
	name: "GnPopover",
	props: {
		label: { type: String, default: "Details" },
		title: { type: String, default: "" },
		text: { type: String, default: "" },
		icon: { type: String, default: "ph-info" },
		variant: { type: String, default: "accent" }
	},
	setup(props, { slots }) {
		const open = ref(false);
		const root = ref(null);
		const close = () => {
			open.value = false;
			document.removeEventListener("click", onOutsideClick);
			document.removeEventListener("keydown", onKeydown);
		};
		const onOutsideClick = event => {
			if(root.value && !root.value.contains(event.target)) {
				close();
			}
		};
		const onKeydown = event => {
			if(event.key === "Escape") {
				event.preventDefault();
				close();
			}
		};
		const toggle = () => {
			open.value = !open.value;

			if(open.value) {
				setTimeout(() => document.addEventListener("click", onOutsideClick), 0);
				document.addEventListener("keydown", onKeydown);
			} else {
				close();
			}
		};

		onBeforeUnmount(close);

		return () => h("div", { ref: root, class: cx("popover", { "is-open": open.value }) }, [
			slots.trigger?.({ open: open.value, toggle }) || h(GnButton, {
				variant: props.variant,
				icon: props.icon,
				"aria-expanded": open.value ? "true" : "false",
				onClick: toggle
			}, () => props.label),
			h("div", { class: "popover-panel" }, [
				(props.title || slots.title) && h("h3", { class: "popover-title" }, slots.title?.() || props.title),
				(props.text || slots.default) && h("p", { class: "popover-text" }, slots.default?.() || props.text)
			])
		]);
	}
});