Newer
Older
gnexus-ui-kit / src / vue / components / GnButton.js
/**
 * GnButton - Primary command component.
 *
 * @typedef {Object} GnButtonProps
 * @property {string} [variant='primary'] - primary | secondary | accent | success | warning | danger | error | info
 * @property {string} [size='md'] - sm | md | lg
 * @property {string} [icon=''] - Phosphor icon name with ph- prefix (e.g. "ph-plus", "ph-house")
 * @property {boolean} [loading=false] - Show spinner and disable interaction
 * @property {boolean} [disabled=false] - Disabled state
 * @property {string} [type='button'] - button | submit | reset
 *
 * @slots default - Button label text
 */
import { defineComponent, h } from "vue";
import { cx, iconNode, normalizeVariant } from "../utils.js";

export default defineComponent({
	name: "GnButton",
	inheritAttrs: false,
	props: {
		variant: { type: String, default: "primary" },
		size: { type: String, default: "md" },
		icon: { type: String, default: "" },
		loading: { type: Boolean, default: false },
		disabled: { type: Boolean, default: false },
		type: { type: String, default: "button" }
	},
	setup(props, { attrs, slots }) {
		return () => {
			const hasIcon = Boolean(props.icon || props.loading);
			const variant = normalizeVariant(props.variant);

			return h("button", {
				...attrs,
				type: props.type,
				disabled: props.disabled || props.loading,
				class: cx(
					"btn",
					`btn-${variant}`,
					{
						"btn-small": props.size === "sm",
						"btn-large": props.size === "lg",
						"with-icon": hasIcon,
						"loading-state": props.loading
					},
					attrs.class
				)
			}, [
				props.loading ? iconNode("ph-bold ph-spinner") : iconNode(props.icon),
				slots.default?.()
			]);
		};
	}
});