Newer
Older
gnexus-ui-kit / src / vue / components / GnSelect.js
/**
 * GnSelect - Dropdown select with label, icon, state, and help text.
 *
 * @typedef {Object} GnSelectProps
 * @property {string|number} [modelValue=''] - Bound value
 * @property {string} [label=''] - Label text
 * @property {string} [icon=''] - Phosphor icon name with ph- prefix
 * @property {string} [state=''] - error | warning | success
 * @property {string} [help=''] - Help or validation message
 * @property {Array} [options=[]] - Array of strings or { value, label } objects
 *
 * @slots default - Override option nodes
 * @emits update:modelValue
 */
import { defineComponent, h } from "vue";
import { cx, eventValue, iconNode } from "../utils.js";

export default defineComponent({
	name: "GnSelect",
	inheritAttrs: false,
	props: {
		modelValue: { type: [String, Number], default: "" },
		label: { type: String, default: "" },
		icon: { type: String, default: "" },
		state: { type: String, default: "" },
		help: { type: String, default: "" },
		options: { type: Array, default: () => [] }
	},
	emits: ["update:modelValue"],
	setup(props, { attrs, emit, slots }) {
		const optionNodes = () => props.options.map(option => {
			const value = typeof option === "object" ? option.value : option;
			const label = typeof option === "object" ? option.label : option;

			return h("option", { value }, label);
		});

		return () => h("div", { class: "form-group" }, [
			h("label", { class: cx("label", props.state) }, [
				props.label,
				iconNode(props.icon),
				h("div", { class: "select-wrap" }, [
					h("select", {
						...attrs,
						value: props.modelValue,
						class: cx("input select", attrs.class),
						onChange: event => emit("update:modelValue", eventValue(event))
					}, slots.default?.() || optionNodes())
				])
			]),
			props.help && h("div", { class: cx("input-info", props.state === "error" && "error") }, props.help)
		]);
	}
});