Newer
Older
gnexus-ui-kit / src / vue / components / GnTable.js
/**
 * GnTable - Data table with columns, rows, scoped cell slots, and empty state.
 *
 * @typedef {Object} GnTableProps
 * @property {Array} columns - Array of { key, label } column definitions
 * @property {Array} [rows=[]] - Array of row data objects
 * @property {string} [caption=''] - Table caption
 * @property {string} [emptyText='Empty'] - Text shown when rows is empty
 *
 * @slots cell-${column.key} - Scoped slot per column: { row, column, value }
 * @slots empty - Override empty state
 */
import { defineComponent, h } from "vue";
import { cx } from "../utils.js";

export default defineComponent({
	name: "GnTable",
	props: {
		columns: { type: Array, required: true },
		rows: { type: Array, default: () => [] },
		caption: { type: String, default: "" },
		emptyText: { type: String, default: "Empty" }
	},
	setup(props, { attrs, slots }) {
		return () => h("div", { class: "table-wrapper" }, [
			h("table", { class: cx("table data-list", { "table-empty": !props.rows.length }, attrs.class) }, [
				props.caption && h("caption", { class: "table-caption" }, props.caption),
				h("thead", { class: "table-head" }, [
					h("tr", { class: "table-row" }, props.columns.map(column => h("th", { scope: "col" }, column.label)))
				]),
				h("tbody", { class: "table-body" }, props.rows.length
					? props.rows.map(row => h("tr", { class: "table-row" }, props.columns.map(column => {
						const name = `cell-${column.key}`;
						return h("td", {}, slots[name]?.({ row, column, value: row[column.key] }) || row[column.key]);
					})))
					: h("tr", {}, [h("td", { class: "is-empty", colspan: props.columns.length }, slots.empty?.() || props.emptyText)])
				)
			])
		]);
	}
});