Newer
Older
gnexus-ui-kit / src / vue / components / GnAccordion.js
@Eugene Sukhodolskiy Eugene Sukhodolskiy 15 hours ago 1 KB Add Vue adapter foundation
import { defineComponent, h, ref } from "vue";
import { cx, iconNode } from "../utils.js";

export default defineComponent({
	name: "GnAccordion",
	props: {
		items: { type: Array, required: true },
		modelValue: { type: [String, Array], default: "" },
		multiple: { type: Boolean, default: false }
	},
	emits: ["update:modelValue"],
	setup(props, { emit, slots }) {
		const localOpen = ref(props.multiple ? [] : "");

		const getOpen = () => props.modelValue || localOpen.value;
		const isOpen = id => props.multiple ? getOpen().includes(id) : getOpen() === id;
		const toggle = id => {
			let next;

			if(props.multiple) {
				const current = [...getOpen()];
				next = current.includes(id) ? current.filter(item => item !== id) : [...current, id];
			} else {
				next = isOpen(id) ? "" : id;
			}

			localOpen.value = next;
			emit("update:modelValue", next);
		};

		return () => h("div", { class: "accordion" }, props.items.map(item => {
			const open = isOpen(item.id);

			return h("section", { class: "accordion-item", open: open ? "" : undefined }, [
				h("button", {
					class: "accordion-summary",
					type: "button",
					"aria-expanded": open ? "true" : "false",
					onClick: () => toggle(item.id)
				}, [
					h("span", { class: "accordion-summary-content" }, [
						iconNode(item.icon),
						item.label
					]),
					h("i", { class: cx("ph ph-caret-down accordion-icon", { "is-open": open }), "aria-hidden": "true" })
				]),
				open && h("div", { class: "accordion-panel" }, slots[item.id]?.({ item, open }) || item.content)
			]);
		}));
	}
});