Newer
Older
vmk-ui-kit / src / js / components / drawer.js
/**
 * Drawer browser helper.
 *
 * Mirrors gnexus-ui-kit Drawer public surface:
 *   create(id, props)
 */

function appendContent(container, content, mode = "html") {
	if (content instanceof Node) {
		container.append(content);
		return;
	}

	if (typeof content !== "undefined" && content !== null) {
		if (mode === "text") {
			container.textContent = content;
		} else {
			container.innerHTML = content;
		}
	}
}

function template(id, title, position) {
	const drawer = document.createElement("div");
	drawer.className = `drawer drawer-${position}`;
	drawer.setAttribute("aria-hidden", "true");
	drawer.id = id;

	const backdrop = document.createElement("div");
	backdrop.className = "drawer-backdrop";

	const panel = document.createElement("aside");
	panel.className = "drawer-panel";
	panel.setAttribute("role", "dialog");
	panel.setAttribute("aria-modal", "true");
	panel.setAttribute("aria-labelledby", `${id}-title`);

	const header = document.createElement("header");
	header.className = "drawer-header";

	const drawerTitle = document.createElement("h4");
	drawerTitle.className = "drawer-title";
	drawerTitle.id = `${id}-title`;
	drawerTitle.textContent = title;

	const close = document.createElement("button");
	close.className = "drawer-close";
	close.type = "button";
	close.setAttribute("aria-label", "Close");
	close.textContent = "✕";

	const body = document.createElement("div");
	body.className = "drawer-body";

	header.append(drawerTitle, close);
	panel.append(header, body);
	drawer.append(backdrop, panel);

	return drawer;
}

function init(drawer, onready) {
	drawer.show = function () {
		document.querySelector("body").append(drawer);
		setTimeout(() => {
			drawer.classList.add("a-show");
		}, 10);
	};

	drawer.close = function () {
		drawer.classList.add("a-hide");
		setTimeout(() => {
			drawer.remove();
		}, 300);
	};

	drawer.querySelector(".drawer-close").addEventListener("click", () => {
		drawer.close();
	});

	drawer.querySelector(".drawer-backdrop")?.addEventListener("click", () => {
		drawer.close();
	});

	if (typeof onready === "function") {
		onready(drawer);
	}

	return drawer;
}

/**
 * Create a new drawer panel.
 * @param {string} id - Unique id
 * @param {object} props - { title, position: "right"|"left", body, bodyText, bodyHtml, footer, onready }
 * @returns {HTMLElement} Drawer DOM element with show()/close()
 */
function create(id, props = {}) {
	const title = props.title || "";
	const position = props.position === "left" ? "left" : "right";
	const footer = props.footer || "";

	const drawer = template(id, title, position);
	const drawerBody = drawer.querySelector(".drawer-body");

	if (typeof props.body === "function") {
		const bodyResult = props.body(drawer);
		appendContent(drawerBody, bodyResult, props.bodyMode ?? "html");
	} else if (typeof props.bodyText !== "undefined") {
		appendContent(drawerBody, props.bodyText, "text");
	} else if (typeof props.bodyHtml !== "undefined") {
		appendContent(drawerBody, props.bodyHtml, "html");
	}

	if (footer) {
		const drawerFooter = document.createElement("footer");
		drawerFooter.className = "drawer-footer";
		appendContent(drawerFooter, footer);
		drawer.querySelector(".drawer-panel").append(drawerFooter);
	}

	return init(drawer, props?.onready);
}

export default {
	create
};