// src/vue/components/GnAccordion.js
import { defineComponent, h as h2, ref } from "vue";
// src/vue/utils.js
import { h } from "vue";
var variants = /* @__PURE__ */ new Set([
"primary",
"secondary",
"accent",
"success",
"warning",
"danger",
"error",
"info"
]);
function cx(...items) {
return items.flatMap((item) => {
if (!item) {
return [];
}
if (Array.isArray(item)) {
return item;
}
if (typeof item === "object") {
return Object.entries(item).filter(([, enabled]) => enabled).map(([name]) => name);
}
return [item];
}).filter(Boolean).join(" ");
}
function normalizeVariant(value, fallback = "primary") {
return variants.has(value) ? value : fallback;
}
function iconNode(icon, extraClass = "") {
if (!icon) {
return null;
}
const iconClass = icon.includes("ph ") || icon.startsWith("ph-") ? icon : `ph ${icon}`;
return h("i", {
class: cx(iconClass, extraClass),
"aria-hidden": "true"
});
}
function eventValue(event) {
const target = event.target;
if (target.type === "checkbox") {
return target.checked;
}
return target.value;
}
var focusableSelector = [
"a[href]",
"button:not([disabled])",
"input:not([disabled])",
"select:not([disabled])",
"textarea:not([disabled])",
"[tabindex]:not([tabindex='-1'])"
].join(",");
function trapFocus(event, root) {
if (event.key !== "Tab" || !root) {
return;
}
const focusable = [...root.querySelectorAll(focusableSelector)].filter((node) => !node.hasAttribute("disabled") && node.offsetParent !== null);
if (!focusable.length) {
event.preventDefault();
root.focus();
return;
}
const first = focusable[0];
const last = focusable[focusable.length - 1];
if (event.shiftKey && document.activeElement === first) {
event.preventDefault();
last.focus();
} else if (!event.shiftKey && document.activeElement === last) {
event.preventDefault();
first.focus();
}
}
// src/vue/components/GnAccordion.js
var GnAccordion_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 () => h2("div", { class: "accordion" }, props.items.map((item) => {
var _a;
const open = isOpen(item.id);
return h2("section", { class: "accordion-item", open: open ? "" : void 0 }, [
h2("button", {
class: "accordion-summary",
type: "button",
"aria-expanded": open ? "true" : "false",
onClick: () => toggle(item.id)
}, [
h2("span", { class: "accordion-summary-content" }, [
iconNode(item.icon),
item.label
]),
h2("i", { class: cx("ph ph-caret-down accordion-icon", { "is-open": open }), "aria-hidden": "true" })
]),
open && h2("div", { class: "accordion-panel" }, ((_a = slots[item.id]) == null ? void 0 : _a.call(slots, { item, open })) || item.content)
]);
}));
}
});
// src/vue/components/GnActionCard.js
import { defineComponent as defineComponent2, h as h3 } from "vue";
var GnActionCard_default = defineComponent2({
name: "GnActionCard",
props: {
kicker: { type: String, default: "" },
title: { type: String, required: true },
text: { type: String, default: "" }
},
setup(props, { slots }) {
return () => {
var _a, _b, _c;
return h3("article", { class: "card action-card" }, [
h3("div", { class: "card-content" }, [
(props.kicker || slots.kicker) && h3("span", { class: "action-card-kicker" }, ((_a = slots.kicker) == null ? void 0 : _a.call(slots)) || props.kicker),
h3("h3", { class: "action-card-title" }, ((_b = slots.title) == null ? void 0 : _b.call(slots)) || props.title),
(props.text || slots.default) && h3("p", { class: "action-card-text" }, ((_c = slots.default) == null ? void 0 : _c.call(slots)) || props.text),
slots.actions && h3("div", { class: "action-card-actions" }, slots.actions())
])
]);
};
}
});
// src/vue/components/GnActionList.js
import { defineComponent as defineComponent3, h as h4 } from "vue";
var GnActionList_default = defineComponent3({
name: "GnActionList",
props: {
items: { type: Array, default: () => [] }
},
setup(props, { attrs, slots }) {
return () => h4("ul", { ...attrs, class: cx("list list-actions", attrs.class) }, props.items.map((item) => {
var _a, _b;
return h4("li", {
class: cx("list-item", item.muted && "list-item-muted")
}, [
h4("div", { class: "list-content" }, [
h4("div", { class: "list-title" }, ((_a = slots.title) == null ? void 0 : _a.call(slots, { item })) || item.title),
(item.subtitle || slots.subtitle) && h4("div", { class: "list-subtitle" }, ((_b = slots.subtitle) == null ? void 0 : _b.call(slots, { item })) || item.subtitle)
]),
slots.controls && h4("div", { class: "list-controls" }, slots.controls({ item }))
]);
}));
}
});
// src/vue/components/GnActivityLog.js
import { defineComponent as defineComponent4, h as h5 } from "vue";
var GnActivityLog_default = defineComponent4({
name: "GnActivityLog",
props: {
items: { type: Array, default: () => [] }
},
setup(props, { attrs, slots }) {
return () => h5("div", { ...attrs, class: cx("activity-log", attrs.class) }, props.items.map((item) => {
var _a;
return h5("div", {
class: "activity-log-row"
}, [
h5("time", { class: "activity-log-time" }, item.time),
h5("span", { class: "activity-log-title" }, ((_a = slots[item.key]) == null ? void 0 : _a.call(slots, { item })) || item.title),
slots.actions && h5("span", {}, slots.actions({ item }))
]);
}));
}
});
// src/vue/components/GnAlert.js
import { defineComponent as defineComponent5, h as h6 } from "vue";
var GnAlert_default = defineComponent5({
name: "GnAlert",
props: {
variant: { type: String, default: "primary" },
role: { type: String, default: "status" }
},
setup(props, { attrs, slots }) {
return () => {
var _a;
const variant = normalizeVariant(props.variant);
return h6("div", {
...attrs,
role: props.role,
class: cx("alert", `alert-${variant}`, attrs.class)
}, (_a = slots.default) == null ? void 0 : _a.call(slots));
};
}
});
// src/vue/components/GnAvatar.js
import { defineComponent as defineComponent6, h as h7 } from "vue";
var GnAvatar_default = defineComponent6({
name: "GnAvatar",
props: {
src: { type: String, default: "" },
alt: { type: String, default: "" },
initials: { type: String, default: "" },
icon: { type: String, default: "" },
size: { type: String, default: "md" },
variant: { type: String, default: "primary" },
outline: { type: Boolean, default: false },
status: { type: String, default: "" }
},
setup(props, { attrs }) {
return () => {
const variant = normalizeVariant(props.variant);
return h7("span", {
...attrs,
class: cx("avatar", `avatar-${variant}`, {
"avatar-sm": props.size === "sm",
"avatar-lg": props.size === "lg",
"avatar-outline": props.outline,
"is-online": props.status === "online",
"is-busy": props.status === "busy",
"is-offline": props.status === "offline"
}, attrs.class)
}, [
props.src ? h7("img", { src: props.src, alt: props.alt }) : iconNode(props.icon) || props.initials,
props.status && h7("span", { class: "avatar-status", "aria-hidden": "true" })
]);
};
}
});
// src/vue/components/GnAvatarStack.js
import { defineComponent as defineComponent7, h as h8 } from "vue";
var GnAvatarStack_default = defineComponent7({
name: "GnAvatarStack",
props: {
items: { type: Array, default: () => [] },
count: { type: [Number, String], default: "" }
},
setup(props, { slots }) {
return () => {
var _a;
return h8("span", { class: "avatar-stack" }, [
props.items.map((item) => h8(GnAvatar_default, { ...item, size: item.size || "sm" })),
(_a = slots.default) == null ? void 0 : _a.call(slots),
props.count && h8("span", { class: "avatar-stack-count" }, `+${props.count}`)
]);
};
}
});
// src/vue/components/GnBadge.js
import { defineComponent as defineComponent8, h as h9 } from "vue";
var GnBadge_default = defineComponent8({
name: "GnBadge",
props: {
variant: { type: String, default: "primary" },
outline: { type: Boolean, default: false }
},
setup(props, { attrs, slots }) {
return () => {
var _a;
const variant = normalizeVariant(props.variant);
return h9("span", {
...attrs,
class: cx(
"badge",
props.outline && variant === "primary" ? "badge-primary-outline" : `badge-${variant}`,
attrs.class
)
}, (_a = slots.default) == null ? void 0 : _a.call(slots));
};
}
});
// src/vue/components/GnButton.js
import { defineComponent as defineComponent9, h as h10 } from "vue";
var GnButton_default = defineComponent9({
name: "GnButton",
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 () => {
var _a;
const hasIcon = Boolean(props.icon || props.loading);
const variant = normalizeVariant(props.variant);
return h10("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),
(_a = slots.default) == null ? void 0 : _a.call(slots)
]);
};
}
});
// src/vue/components/GnCard.js
import { defineComponent as defineComponent10, h as h11 } from "vue";
var GnCard_default = defineComponent10({
name: "GnCard",
props: {
title: { type: String, default: "" },
variant: { type: String, default: "" }
},
setup(props, { attrs, slots }) {
return () => {
var _a, _b;
return h11("article", {
...attrs,
class: cx("card", props.variant && `card-${props.variant}`, attrs.class)
}, [
(props.title || slots.title) && h11("header", { class: "card-title" }, ((_a = slots.title) == null ? void 0 : _a.call(slots)) || props.title),
h11("div", { class: "card-content" }, (_b = slots.default) == null ? void 0 : _b.call(slots)),
slots.footer && h11("footer", { class: "card-footer" }, slots.footer())
]);
};
}
});
// src/vue/components/GnCheckbox.js
import { defineComponent as defineComponent11, h as h12 } from "vue";
var GnCheckbox_default = defineComponent11({
name: "GnCheckbox",
inheritAttrs: false,
props: {
modelValue: { type: Boolean, default: false },
label: { type: String, default: "" },
disabled: { type: Boolean, default: false }
},
emits: ["update:modelValue"],
setup(props, { attrs, emit, slots }) {
return () => {
var _a;
return h12("label", { class: cx("checkbox", attrs.class) }, [
h12("input", {
...attrs,
type: "checkbox",
checked: props.modelValue,
disabled: props.disabled,
onChange: (event) => emit("update:modelValue", event.target.checked)
}),
h12("span", { class: "checkbox-control", "aria-hidden": "true" }),
h12("span", { class: "checkbox-label" }, ((_a = slots.default) == null ? void 0 : _a.call(slots)) || props.label)
]);
};
}
});
// src/vue/components/GnChip.js
import { defineComponent as defineComponent12, h as h13 } from "vue";
var GnChip_default = defineComponent12({
name: "GnChip",
props: {
variant: { type: String, default: "" },
icon: { type: String, default: "" },
selected: { type: Boolean, default: false },
disabled: { type: Boolean, default: false },
removable: { type: Boolean, default: false }
},
emits: ["remove"],
setup(props, { attrs, emit, slots }) {
return () => {
var _a;
const tag = attrs.onClick ? "button" : "span";
const variant = props.variant ? normalizeVariant(props.variant) : "";
return h13(tag, {
...attrs,
type: tag === "button" ? "button" : void 0,
disabled: tag === "button" ? props.disabled : void 0,
"aria-pressed": tag === "button" ? String(props.selected) : void 0,
class: cx("chip", variant && `chip-${variant}`, {
"chip-selected": props.selected,
"chip-disabled": props.disabled
}, attrs.class)
}, [
iconNode(props.icon),
(_a = slots.default) == null ? void 0 : _a.call(slots),
props.removable && h13("button", {
class: "chip-remove",
type: "button",
"aria-label": "Remove",
onClick: (event) => {
event.stopPropagation();
emit("remove");
}
}, [iconNode("ph-x")])
]);
};
}
});
// src/vue/components/GnChipGroup.js
import { defineComponent as defineComponent13, h as h14 } from "vue";
var GnChipGroup_default = defineComponent13({
name: "GnChipGroup",
setup(_, { attrs, slots }) {
return () => {
var _a;
return h14("div", { ...attrs, class: cx("chip-group", attrs.class) }, (_a = slots.default) == null ? void 0 : _a.call(slots));
};
}
});
// src/vue/components/GnCombobox.js
import { computed, defineComponent as defineComponent14, h as h15, nextTick, ref as ref2 } from "vue";
var comboboxId = 0;
var GnCombobox_default = defineComponent14({
name: "GnCombobox",
inheritAttrs: false,
props: {
modelValue: { type: [String, Number], default: "" },
label: { type: String, default: "" },
icon: { type: String, default: "" },
options: { type: Array, default: () => [] },
placeholder: { type: String, default: "Search" },
notFoundText: { type: String, default: "Nothing found" },
state: { type: String, default: "" },
help: { type: String, default: "" }
},
emits: ["update:modelValue", "select"],
setup(props, { attrs, emit }) {
const id = `gn-combobox-${++comboboxId}`;
const listboxId = `${id}-listbox`;
const open = ref2(false);
const focused = ref2(-1);
const inputRef = ref2(null);
const normalized = computed(() => props.options.map((option) => typeof option === "object" ? option : {
value: option,
label: option
}));
const query = computed(() => {
var _a;
return String((_a = props.modelValue) != null ? _a : "").toLowerCase();
});
const filtered = computed(() => normalized.value.filter((option) => String(option.label).toLowerCase().includes(query.value)));
const select = (option) => {
if (!option) {
return;
}
emit("update:modelValue", option.label);
emit("select", option);
open.value = false;
focused.value = -1;
};
const move = (direction) => {
if (!filtered.value.length) {
return;
}
open.value = true;
focused.value = (focused.value + direction + filtered.value.length) % filtered.value.length;
nextTick(() => {
var _a, _b, _c;
const container = (_b = (_a = inputRef.value) == null ? void 0 : _a.closest(".form-group")) == null ? void 0 : _b.querySelector(".advanced-select");
(_c = container == null ? void 0 : container.querySelector(".option.focus")) == null ? void 0 : _c.scrollIntoView({ block: "nearest" });
});
};
const onKeydown = (event) => {
if (event.key === "ArrowDown") {
event.preventDefault();
move(1);
} else if (event.key === "ArrowUp") {
event.preventDefault();
move(-1);
} else if (event.key === "Enter") {
event.preventDefault();
select(filtered.value[focused.value]);
} else if (event.key === "Escape") {
open.value = false;
focused.value = -1;
}
};
return () => h15("div", { class: "form-group" }, [
h15("label", { class: cx("label", props.state) }, [
props.label,
iconNode(props.icon),
h15("input", {
...attrs,
ref: inputRef,
id,
type: "text",
value: props.modelValue,
placeholder: props.placeholder,
autocomplete: "off",
role: "combobox",
"aria-autocomplete": "list",
"aria-expanded": open.value ? "true" : "false",
"aria-controls": listboxId,
"aria-activedescendant": focused.value >= 0 ? `${id}-option-${focused.value}` : void 0,
class: cx("input", attrs.class),
onFocus: () => {
open.value = true;
},
onBlur: () => {
setTimeout(() => {
open.value = false;
}, 120);
},
onInput: (event) => {
focused.value = -1;
open.value = true;
emit("update:modelValue", eventValue(event));
},
onKeydown
})
]),
h15("div", { class: "advanced-select-container" }, [
h15("div", { class: cx("advanced-select", { "a-show": open.value }) }, [
h15("div", { class: "popup-options-container" }, [
h15("div", { class: cx("not-found", { show: !filtered.value.length }) }, props.notFoundText),
h15("div", {
id: listboxId,
class: cx("options", { show: filtered.value.length }),
role: "listbox"
}, filtered.value.map((option, index) => h15("div", {
id: `${id}-option-${index}`,
class: cx("option", { focus: index === focused.value }),
role: "option",
"aria-selected": index === focused.value ? "true" : "false",
"data-value": option.value,
"data-display-value": option.label,
onMousedown: (event) => {
event.preventDefault();
select(option);
}
}, option.label)))
])
])
]),
props.help && h15("div", { class: cx("input-info", props.state === "error" && "error") }, props.help)
]);
}
});
// src/vue/components/GnConfirmDialog.js
import { defineComponent as defineComponent16, h as h17 } from "vue";
// src/vue/components/GnModal.js
import { defineComponent as defineComponent15, h as h16, nextTick as nextTick2, onBeforeUnmount, ref as ref3, Teleport, watch } from "vue";
var modalId = 0;
var GnModal_default = defineComponent15({
name: "GnModal",
props: {
open: { type: Boolean, default: false },
title: { type: String, default: "" },
closeOnBackdrop: { type: Boolean, default: true }
},
emits: ["update:open", "close"],
setup(props, { emit, slots }) {
const titleId = `gn-modal-title-${++modalId}`;
const dialogRef = ref3(null);
let previousFocus = null;
const close = () => {
emit("update:open", false);
emit("close");
};
const onKeydown = (event) => {
if (event.key === "Escape") {
event.preventDefault();
close();
} else {
trapFocus(event, dialogRef.value);
}
};
const focusDialog = () => {
nextTick2(() => {
var _a;
(_a = dialogRef.value) == null ? void 0 : _a.focus();
});
};
watch(() => props.open, (open) => {
var _a;
if (open) {
previousFocus = document.activeElement;
document.addEventListener("keydown", onKeydown);
focusDialog();
} else {
document.removeEventListener("keydown", onKeydown);
(_a = previousFocus == null ? void 0 : previousFocus.focus) == null ? void 0 : _a.call(previousFocus);
previousFocus = null;
}
}, { flush: "post" });
onBeforeUnmount(() => {
document.removeEventListener("keydown", onKeydown);
});
return () => {
var _a, _b, _c;
return props.open ? h16(Teleport, { to: "body" }, [
h16("div", { class: "modal a-show", "aria-hidden": "false" }, [
h16("div", {
class: "modal-backdrop",
onClick: () => props.closeOnBackdrop && close()
}),
h16("div", {
ref: dialogRef,
class: "modal-dialog",
role: "dialog",
"aria-modal": "true",
"aria-labelledby": titleId,
tabindex: "-1"
}, [
h16("header", { class: "modal-header" }, [
h16("h4", { class: "modal-title", id: titleId }, ((_a = slots.title) == null ? void 0 : _a.call(slots)) || props.title),
h16("button", {
class: "btn-icon modal-close",
type: "button",
"aria-label": "Close",
onClick: close
}, [iconNode("ph-x")])
]),
h16("div", { class: "modal-panel" }, [
h16("div", { class: "modal-body" }, (_b = slots.default) == null ? void 0 : _b.call(slots)),
(slots.footer || slots.actions) && h16("footer", { class: "modal-footer" }, [
(_c = slots.footer) == null ? void 0 : _c.call(slots),
slots.actions && h16("div", { class: "actions" }, slots.actions({ close }))
])
])
])
])
]) : null;
};
}
});
// src/vue/components/GnConfirmDialog.js
var GnConfirmDialog_default = defineComponent16({
name: "GnConfirmDialog",
props: {
open: { type: Boolean, default: false },
title: { type: String, default: "Requires confirmation" },
message: { type: String, default: "" },
confirmText: { type: String, default: "YES" },
cancelText: { type: String, default: "NO" },
confirmVariant: { type: String, default: "warning" }
},
emits: ["update:open", "confirm", "cancel"],
setup(props, { emit, slots }) {
const close = () => emit("update:open", false);
const cancel = () => {
emit("cancel");
close();
};
const confirm = () => {
emit("confirm");
close();
};
return () => h17(GnModal_default, {
open: props.open,
title: props.title,
"onUpdate:open": (value) => emit("update:open", value)
}, {
default: () => {
var _a;
return ((_a = slots.default) == null ? void 0 : _a.call(slots)) || h17("p", {}, props.message);
},
actions: () => [
h17(GnButton_default, { variant: "primary", onClick: cancel }, () => props.cancelText),
h17(GnButton_default, { variant: props.confirmVariant, onClick: confirm }, () => props.confirmText)
]
});
}
});
// src/vue/components/GnDescriptionList.js
import { defineComponent as defineComponent17, h as h18 } from "vue";
var GnDescriptionList_default = defineComponent17({
name: "GnDescriptionList",
props: {
items: { type: Array, default: () => [] },
compact: { type: Boolean, default: false }
},
setup(props, { attrs, slots }) {
return () => h18("dl", {
...attrs,
class: cx("description-list", { "description-list-compact": props.compact }, attrs.class)
}, props.items.map((item) => {
var _a;
return h18("div", { class: "description-list-row" }, [
h18("dt", { class: "description-list-term" }, item.term || item.label),
h18(
"dd",
{ class: cx("description-list-value", item.muted && "description-list-value-muted") },
((_a = slots[item.key]) == null ? void 0 : _a.call(slots, { item })) || item.value
)
]);
}));
}
});
// src/vue/components/GnDefinitionList.js
import { defineComponent as defineComponent18, h as h19 } from "vue";
var GnDefinitionList_default = defineComponent18({
name: "GnDefinitionList",
props: {
items: { type: Array, default: () => [] }
},
setup(props, { attrs, slots }) {
return () => h19("dl", { ...attrs, class: cx("list list-definition", attrs.class) }, props.items.map((item) => {
var _a;
return h19("div", {
class: "list-row"
}, [
h19("dt", { class: "list-term" }, item.term || item.label),
h19("dd", { class: "list-desc" }, ((_a = slots[item.key]) == null ? void 0 : _a.call(slots, { item })) || item.description || item.value)
]);
}));
}
});
// src/vue/components/GnDropdown.js
import { defineComponent as defineComponent19, h as h20, onBeforeUnmount as onBeforeUnmount2, ref as ref4 } from "vue";
var GnDropdown_default = defineComponent19({
name: "GnDropdown",
props: {
label: { type: String, default: "Actions" },
icon: { type: String, default: "ph-dots-three-outline" },
variant: { type: String, default: "secondary" },
items: { type: Array, default: () => [] }
},
emits: ["select"],
setup(props, { emit, slots }) {
const open = ref4(false);
const root = ref4(null);
const close = () => {
open.value = false;
document.removeEventListener("click", onOutsideClick);
document.removeEventListener("keydown", onKeydown);
};
const onOutsideClick = (event) => {
if (root.value && !root.value.contains(event.target)) {
close();
}
};
const onKeydown = (event) => {
if (event.key === "Escape") {
event.preventDefault();
close();
}
};
const toggle = () => {
open.value = !open.value;
if (open.value) {
setTimeout(() => document.addEventListener("click", onOutsideClick), 0);
document.addEventListener("keydown", onKeydown);
} else {
close();
}
};
const select = (item) => {
var _a;
if (item.disabled) {
return;
}
(_a = item.onSelect) == null ? void 0 : _a.call(item, item);
emit("select", item);
close();
};
onBeforeUnmount2(close);
return () => {
var _a, _b;
return h20("div", { ref: root, class: cx("dropdown", { "is-open": open.value }) }, [
((_a = slots.trigger) == null ? void 0 : _a.call(slots, { open: open.value, toggle })) || h20(GnButton_default, {
variant: props.variant,
icon: props.icon,
"aria-expanded": open.value ? "true" : "false",
onClick: toggle
}, () => props.label),
h20("div", { class: "dropdown-menu", role: "menu" }, ((_b = slots.default) == null ? void 0 : _b.call(slots, { close })) || props.items.map((item) => h20("button", {
class: cx("dropdown-item", item.danger && "dropdown-item-danger"),
type: "button",
role: "menuitem",
disabled: item.disabled,
onClick: () => select(item)
}, [
iconNode(item.icon),
item.label
])))
]);
};
}
});
// src/vue/components/GnDrawer.js
import { defineComponent as defineComponent20, h as h21, nextTick as nextTick3, onBeforeUnmount as onBeforeUnmount3, ref as ref5, Teleport as Teleport2, watch as watch2 } from "vue";
var drawerId = 0;
var GnDrawer_default = defineComponent20({
name: "GnDrawer",
props: {
open: { type: Boolean, default: false },
title: { type: String, default: "" },
position: { type: String, default: "right" }
},
emits: ["update:open", "close"],
setup(props, { emit, slots }) {
const titleId = `gn-drawer-title-${++drawerId}`;
const panelRef = ref5(null);
let previousFocus = null;
const close = () => {
emit("update:open", false);
emit("close");
};
const onKeydown = (event) => {
if (event.key === "Escape") {
event.preventDefault();
close();
} else {
trapFocus(event, panelRef.value);
}
};
watch2(() => props.open, (open) => {
var _a;
if (open) {
previousFocus = document.activeElement;
document.addEventListener("keydown", onKeydown);
nextTick3(() => {
var _a2;
return (_a2 = panelRef.value) == null ? void 0 : _a2.focus();
});
} else {
document.removeEventListener("keydown", onKeydown);
(_a = previousFocus == null ? void 0 : previousFocus.focus) == null ? void 0 : _a.call(previousFocus);
previousFocus = null;
}
}, { flush: "post" });
onBeforeUnmount3(() => {
document.removeEventListener("keydown", onKeydown);
});
return () => {
var _a, _b;
return props.open ? h21(Teleport2, { to: "body" }, [
h21("div", {
class: cx("drawer a-show", { "drawer-left": props.position === "left" }),
"aria-hidden": "false"
}, [
h21("div", { class: "drawer-backdrop", onClick: close }),
h21("aside", {
ref: panelRef,
class: "drawer-panel",
role: "dialog",
"aria-modal": "true",
"aria-labelledby": titleId,
tabindex: "-1"
}, [
h21("header", { class: "drawer-header" }, [
h21("h4", { class: "drawer-title", id: titleId }, ((_a = slots.title) == null ? void 0 : _a.call(slots)) || props.title),
h21("button", {
class: "btn-icon drawer-close",
type: "button",
"aria-label": "Close",
onClick: close
}, [iconNode("ph-x")])
]),
h21("div", { class: "drawer-body" }, (_b = slots.default) == null ? void 0 : _b.call(slots)),
slots.footer && h21("footer", { class: "drawer-footer" }, slots.footer({ close }))
])
])
]) : null;
};
}
});
// src/vue/components/GnEmptyState.js
import { defineComponent as defineComponent21, h as h22 } from "vue";
var GnEmptyState_default = defineComponent21({
name: "GnEmptyState",
props: {
title: { type: String, required: true },
text: { type: String, default: "" },
icon: { type: String, default: "ph-package" },
variant: { type: String, default: "" }
},
setup(props, { attrs, slots }) {
return () => {
var _a, _b;
return h22("div", {
...attrs,
class: cx("empty-state", props.variant && `empty-state-${props.variant}`, attrs.class)
}, [
h22("div", { class: "empty-state-icon" }, [iconNode(props.icon)]),
h22("h3", { class: "empty-state-title" }, ((_a = slots.title) == null ? void 0 : _a.call(slots)) || props.title),
(props.text || slots.default) && h22("p", { class: "empty-state-text" }, ((_b = slots.default) == null ? void 0 : _b.call(slots)) || props.text),
slots.actions && h22("div", { class: "empty-state-actions" }, slots.actions())
]);
};
}
});
// src/vue/components/GnFileUpload.js
import { defineComponent as defineComponent22, h as h23, onBeforeUnmount as onBeforeUnmount4, ref as ref6, watch as watch3 } from "vue";
function fileType(file) {
const ext = file.name.split(".").pop();
return ext ? ext.slice(0, 6).toUpperCase() : "FILE";
}
function fileSize(file) {
if (!file.size) {
return "0 B";
}
const units = ["B", "KB", "MB", "GB"];
const index = Math.min(Math.floor(Math.log(file.size) / Math.log(1024)), units.length - 1);
const value = file.size / Math.pow(1024, index);
return `${value.toFixed(value >= 10 || index === 0 ? 0 : 1)} ${units[index]}`;
}
var GnFileUpload_default = defineComponent22({
name: "GnFileUpload",
props: {
modelValue: { type: Array, default: () => [] },
title: { type: String, default: "Upload files" },
description: { type: String, default: "Attach documents, archives or images." },
primary: { type: String, default: "Choose files" },
secondary: { type: String, default: "Images get thumbnails, other files show their type" },
badge: { type: String, default: "" },
multiple: { type: Boolean, default: true },
accept: { type: String, default: "" }
},
emits: ["update:modelValue", "change"],
setup(props, { emit, slots }) {
const urls = ref6(/* @__PURE__ */ new Map());
const revokeFile = (file) => {
const url = urls.value.get(file);
if (url) {
URL.revokeObjectURL(url);
urls.value.delete(file);
}
};
const revokeAll = () => {
urls.value.forEach((url) => URL.revokeObjectURL(url));
urls.value.clear();
};
const setFiles = (fileList) => {
const files = Array.from(fileList || []);
emit("update:modelValue", files);
emit("change", files);
};
const remove = (index) => {
revokeFile(props.modelValue[index]);
const files = props.modelValue.filter((_, itemIndex) => itemIndex !== index);
emit("update:modelValue", files);
emit("change", files);
};
const previewUrl = (file) => {
var _a;
if (!((_a = file.type) == null ? void 0 : _a.startsWith("image/"))) {
return "";
}
if (!urls.value.has(file)) {
urls.value.set(file, URL.createObjectURL(file));
}
return urls.value.get(file);
};
watch3(() => props.modelValue, (files) => {
const active = new Set(files);
[...urls.value.keys()].forEach((file) => {
if (!active.has(file)) {
revokeFile(file);
}
});
});
onBeforeUnmount4(revokeAll);
return () => {
var _a, _b;
return h23("div", { class: "file-upload-panel" }, [
h23("div", { class: "file-upload-form" }, [
h23("div", { class: "file-upload-header" }, [
h23("div", { class: "file-upload-heading" }, [
h23("h3", { class: "file-upload-title" }, ((_a = slots.title) == null ? void 0 : _a.call(slots)) || props.title),
h23("p", { class: "file-upload-description" }, ((_b = slots.description) == null ? void 0 : _b.call(slots)) || props.description)
]),
props.badge && h23(GnBadge_default, { variant: "info" }, () => props.badge)
]),
h23("label", { class: "file-upload-dropzone" }, [
h23("span", { class: "file-upload-icon", "aria-hidden": "true" }, [iconNode("ph-cloud-arrow-up")]),
h23("span", { class: "file-upload-body" }, [
h23("span", { class: "file-upload-primary" }, props.primary),
h23("span", { class: "file-upload-secondary" }, props.secondary)
]),
h23("input", {
type: "file",
multiple: props.multiple,
accept: props.accept || void 0,
onChange: (event) => setFiles(event.target.files)
})
]),
h23("div", { class: "file-upload-preview", hidden: !props.modelValue.length }, props.modelValue.map((file, index) => h23("figure", {
class: "file-upload-preview-item"
}, [
h23("button", {
class: "file-upload-preview-remove",
type: "button",
"aria-label": `Remove ${file.name}`,
onClick: () => remove(index)
}, [iconNode("ph-x")]),
h23(
"div",
{ class: "file-upload-preview-visual" },
previewUrl(file) ? h23("img", { src: previewUrl(file), alt: "" }) : h23("span", { class: "file-upload-preview-type" }, fileType(file))
),
h23("figcaption", {}, [
h23("span", { class: "file-upload-preview-name" }, file.name),
h23("span", { class: "file-upload-preview-meta" }, `${fileType(file)} / ${fileSize(file)}`)
])
]))),
slots.actions && h23("div", { class: "file-upload-actions" }, slots.actions()),
!slots.actions && props.modelValue.length > 0 && h23("div", { class: "file-upload-actions" }, [
h23(GnButton_default, {
variant: "secondary",
size: "sm",
onClick: () => {
revokeAll();
setFiles([]);
}
}, () => "Reset")
])
])
]);
};
}
});
// src/vue/components/GnIconButton.js
import { defineComponent as defineComponent23, h as h24 } from "vue";
var GnIconButton_default = defineComponent23({
name: "GnIconButton",
props: {
icon: { type: String, required: true },
label: { type: String, required: true },
type: { type: String, default: "button" },
withoutHover: { type: Boolean, default: false }
},
setup(props, { attrs }) {
return () => h24("button", {
...attrs,
type: props.type,
"aria-label": props.label,
class: cx("btn-icon", { "without-hover": props.withoutHover }, attrs.class)
}, [iconNode(props.icon)]);
}
});
// src/vue/components/GnIdentity.js
import { defineComponent as defineComponent24, h as h25 } from "vue";
var GnIdentity_default = defineComponent24({
name: "GnIdentity",
props: {
title: { type: String, required: true },
meta: { type: String, default: "" },
avatar: { type: Object, default: () => ({}) }
},
setup(props, { slots }) {
return () => {
var _a, _b, _c;
return h25("span", { class: "identity" }, [
((_a = slots.avatar) == null ? void 0 : _a.call(slots)) || h25(GnAvatar_default, props.avatar),
h25("span", { class: "identity-content" }, [
h25("span", { class: "identity-title" }, ((_b = slots.title) == null ? void 0 : _b.call(slots)) || props.title),
(props.meta || slots.meta) && h25("span", { class: "identity-meta" }, ((_c = slots.meta) == null ? void 0 : _c.call(slots)) || props.meta)
])
]);
};
}
});
// src/vue/components/GnInput.js
import { defineComponent as defineComponent25, h as h26 } from "vue";
var GnInput_default = defineComponent25({
name: "GnInput",
inheritAttrs: false,
props: {
modelValue: { type: [String, Number], default: "" },
label: { type: String, default: "" },
type: { type: String, default: "text" },
icon: { type: String, default: "" },
state: { type: String, default: "" },
help: { type: String, default: "" }
},
emits: ["update:modelValue"],
setup(props, { attrs, emit }) {
return () => h26("div", { class: "form-group" }, [
h26("label", { class: cx("label", props.state) }, [
props.label,
iconNode(props.icon),
h26("input", {
...attrs,
type: props.type,
value: props.modelValue,
class: cx("input", attrs.class),
onInput: (event) => emit("update:modelValue", eventValue(event))
})
]),
props.help && h26("div", { class: cx("input-info", props.state === "error" && "error") }, props.help)
]);
}
});
// src/vue/components/GnInputGroup.js
import { defineComponent as defineComponent26, h as h27 } from "vue";
var GnInputGroup_default = defineComponent26({
name: "GnInputGroup",
props: {
compact: { type: Boolean, default: false },
addon: { type: String, default: "" },
icon: { type: String, default: "" }
},
setup(props, { attrs, slots }) {
return () => {
var _a, _b;
return h27("div", {
...attrs,
class: cx("input-group", { "input-group-compact": props.compact }, attrs.class)
}, [
(props.addon || props.icon || slots.addon) && h27("span", { class: "input-group-addon" }, ((_a = slots.addon) == null ? void 0 : _a.call(slots)) || iconNode(props.icon) || props.addon),
(_b = slots.default) == null ? void 0 : _b.call(slots),
slots.action && h27("span", { class: "input-group-action" }, slots.action())
]);
};
}
});
// src/vue/components/GnList.js
import { defineComponent as defineComponent27, h as h28 } from "vue";
var GnList_default = defineComponent27({
name: "GnList",
props: {
items: { type: Array, default: () => [] },
ordered: { type: Boolean, default: false },
icons: { type: Boolean, default: false }
},
setup(props, { attrs, slots }) {
const tag = props.ordered ? "ol" : "ul";
return () => h28(tag, {
...attrs,
class: cx("list", {
"list-ordered": props.ordered,
"with-icons": props.icons
}, attrs.class)
}, props.items.map((item) => {
var _a;
return h28("li", { class: "list-item" }, [
iconNode(item.icon),
((_a = slots.item) == null ? void 0 : _a.call(slots, { item })) || item.label || item
]);
}));
}
});
// src/vue/components/GnLoader.js
import { defineComponent as defineComponent28, h as h29 } from "vue";
var GnLoader_default = defineComponent28({
name: "GnLoader",
props: {
circle: { type: Boolean, default: false },
label: { type: String, default: "Loading" }
},
setup(props, { attrs }) {
return () => props.circle ? h29("div", { ...attrs, class: cx("circle-loader", attrs.class) }, [
iconNode("ph-bold ph-spinner normalize"),
props.label
]) : h29("div", { ...attrs, class: cx("loader", attrs.class), role: "status", "aria-label": props.label });
}
});
// src/vue/components/GnMetricCard.js
import { defineComponent as defineComponent29, h as h30 } from "vue";
var GnMetricCard_default = defineComponent29({
name: "GnMetricCard",
props: {
label: { type: String, required: true },
value: { type: [String, Number], required: true },
icon: { type: String, default: "ph-chart-line-up" },
delta: { type: String, default: "" },
negative: { type: Boolean, default: false },
meta: { type: String, default: "" }
},
setup(props, { attrs, slots }) {
return () => {
var _a, _b, _c;
return h30("article", { ...attrs, class: cx("card metric-card", attrs.class) }, [
h30("div", { class: "card-content" }, [
h30("div", { class: "metric-card-header" }, [
h30("p", { class: "metric-card-label" }, ((_a = slots.label) == null ? void 0 : _a.call(slots)) || props.label),
h30("span", { class: "metric-card-icon" }, [iconNode(props.icon)])
]),
h30("p", { class: "metric-card-value" }, ((_b = slots.value) == null ? void 0 : _b.call(slots)) || props.value),
(props.delta || props.meta || slots.meta) && h30("div", { class: "metric-card-meta" }, [
props.delta && h30("span", {
class: cx("metric-card-delta", { "metric-card-delta-negative": props.negative })
}, props.delta),
((_c = slots.meta) == null ? void 0 : _c.call(slots)) || props.meta
])
])
]);
};
}
});
// src/vue/components/GnNavList.js
import { defineComponent as defineComponent30, h as h31 } from "vue";
var GnNavList_default = defineComponent30({
name: "GnNavList",
props: {
items: { type: Array, default: () => [] }
},
emits: ["select"],
setup(props, { attrs, emit, slots }) {
return () => h31("ul", { ...attrs, class: cx("list list-nav", attrs.class) }, props.items.map((item) => {
var _a, _b;
return h31("li", {
class: cx("list-item", { "list-item-active": item.active })
}, [
h31(item.href ? "a" : "button", {
class: "list-action",
href: item.href,
type: item.href ? void 0 : "button",
onClick: (event) => {
var _a2;
(_a2 = item.onSelect) == null ? void 0 : _a2.call(item, item, event);
emit("select", item);
}
}, [
h31("span", { class: "list-label" }, [
iconNode(item.icon),
((_a = slots.label) == null ? void 0 : _a.call(slots, { item })) || item.label
]),
(item.meta || slots.meta) && h31("span", { class: "list-meta" }, ((_b = slots.meta) == null ? void 0 : _b.call(slots, { item })) || item.meta)
])
]);
}));
}
});
// src/vue/components/GnNavigationShell.js
import { defineComponent as defineComponent31, h as h32, nextTick as nextTick4, onBeforeUnmount as onBeforeUnmount5, ref as ref7, watch as watch4 } from "vue";
var shellId = 0;
var GnNavigationShell_default = defineComponent31({
name: "GnNavigationShell",
props: {
brand: { type: String, default: "GNexus UI Kit" },
logoSrc: { type: String, default: "/assets/imgs/gnexus-mark.svg" },
current: { type: String, default: "" },
title: { type: String, default: "Sections" },
subtitle: { type: String, default: "Navigation" },
footerLeft: { type: String, default: "" },
footerRight: { type: String, default: "" },
items: { type: Array, default: () => [] }
},
emits: ["select"],
setup(props, { emit, slots }) {
const open = ref7(false);
const drawerId2 = `gn-nav-drawer-${++shellId}`;
const drawerRef = ref7(null);
let previousFocus = null;
const close = () => {
open.value = false;
};
const toggle = () => {
open.value = !open.value;
};
const onKeydown = (event) => {
if (event.key === "Escape") {
event.preventDefault();
close();
}
};
watch4(open, (isOpen) => {
var _a;
if (isOpen) {
previousFocus = document.activeElement;
document.body.classList.add("nav-drawer-open");
document.addEventListener("keydown", onKeydown);
nextTick4(() => {
var _a2;
return (_a2 = drawerRef.value) == null ? void 0 : _a2.focus();
});
} else {
document.body.classList.remove("nav-drawer-open");
document.removeEventListener("keydown", onKeydown);
(_a = previousFocus == null ? void 0 : previousFocus.focus) == null ? void 0 : _a.call(previousFocus);
previousFocus = null;
}
});
onBeforeUnmount5(() => {
document.body.classList.remove("nav-drawer-open");
document.removeEventListener("keydown", onKeydown);
});
return () => {
var _a, _b, _c, _d, _e, _f, _g;
return [
h32("header", { class: "nav-topbar" }, [
h32("button", {
class: "nav-topbar-toggle",
type: "button",
"aria-controls": drawerId2,
"aria-expanded": open.value ? "true" : "false",
onClick: toggle
}, [
iconNode("ph-sidebar-simple"),
h32("span", {}, "Menu")
]),
h32("div", { class: "nav-topbar-brand" }, [
props.logoSrc && h32("img", { src: props.logoSrc, alt: "", "aria-hidden": "true" }),
h32("span", {}, ((_a = slots.brand) == null ? void 0 : _a.call(slots)) || props.brand)
]),
h32("div", { class: "nav-topbar-current" }, ((_b = slots.current) == null ? void 0 : _b.call(slots)) || props.current)
]),
h32("div", { class: "nav-drawer-backdrop", onClick: close }),
h32("aside", {
ref: drawerRef,
class: ["nav-drawer", { "is-open": open.value }],
id: drawerId2,
"aria-label": "Navigation",
"aria-hidden": open.value ? "false" : "true",
tabindex: "-1"
}, [
h32("header", { class: "nav-drawer-header" }, [
h32("div", {}, [
h32("div", { class: "nav-drawer-title" }, ((_c = slots.title) == null ? void 0 : _c.call(slots)) || props.title),
h32("div", { class: "nav-drawer-subtitle" }, ((_d = slots.subtitle) == null ? void 0 : _d.call(slots)) || props.subtitle)
]),
h32("button", {
class: "nav-drawer-close",
type: "button",
"aria-label": "Close navigation",
onClick: close
}, [iconNode("ph-x")])
]),
h32("nav", { class: "nav-drawer-body" }, [
((_e = slots.default) == null ? void 0 : _e.call(slots, { close })) || h32(GnNavList_default, {
items: props.items,
onSelect: (item) => {
emit("select", item);
close();
}
})
]),
(slots.footer || props.footerLeft || props.footerRight) && h32(
"footer",
{ class: "nav-drawer-footer" },
((_f = slots.footer) == null ? void 0 : _f.call(slots)) || [
h32("span", {}, props.footerLeft),
h32("span", {}, props.footerRight)
]
)
]),
(_g = slots.content) == null ? void 0 : _g.call(slots)
];
};
}
});
// src/vue/components/GnPageHeader.js
import { defineComponent as defineComponent32, h as h33 } from "vue";
var GnPageHeader_default = defineComponent32({
name: "GnPageHeader",
props: {
title: { type: String, required: true },
subtitle: { type: String, default: "" },
kicker: { type: String, default: "" },
compact: { type: Boolean, default: false },
accent: { type: Boolean, default: false }
},
setup(props, { attrs, slots }) {
return () => {
var _a, _b, _c;
return h33("header", {
...attrs,
class: cx("page-header", {
"page-header-compact": props.compact,
"page-header-accent": props.accent
}, attrs.class)
}, [
h33("div", { class: "page-header-content" }, [
(props.kicker || slots.kicker) && h33("div", { class: "page-header-kicker" }, ((_a = slots.kicker) == null ? void 0 : _a.call(slots)) || props.kicker),
h33("h1", { class: "page-header-title" }, ((_b = slots.title) == null ? void 0 : _b.call(slots)) || props.title),
(props.subtitle || slots.subtitle) && h33("p", { class: "page-header-subtitle" }, ((_c = slots.subtitle) == null ? void 0 : _c.call(slots)) || props.subtitle),
slots.meta && h33("div", { class: "page-header-meta" }, slots.meta())
]),
slots.actions && h33("div", { class: "page-header-actions" }, slots.actions())
]);
};
}
});
// src/vue/components/GnPagination.js
import { defineComponent as defineComponent33, h as h34 } from "vue";
var GnPagination_default = defineComponent33({
name: "GnPagination",
props: {
page: { type: Number, required: true },
totalPages: { type: Number, required: true },
ariaLabel: { type: String, default: "Pagination" }
},
emits: ["update:page"],
setup(props, { emit }) {
const setPage = (page) => {
if (page >= 1 && page <= props.totalPages && page !== props.page) {
emit("update:page", page);
}
};
return () => {
const pages = Array.from({ length: props.totalPages }, (_, index) => index + 1);
return h34("nav", { class: "pagination", "aria-label": props.ariaLabel }, [
h34("button", {
class: "pagination-item",
type: "button",
disabled: props.page <= 1,
onClick: () => setPage(props.page - 1)
}, [iconNode("ph-arrow-left")]),
pages.map((page) => h34("button", {
class: cx("pagination-item", { "pagination-item-active": page === props.page }),
type: "button",
"aria-current": page === props.page ? "page" : void 0,
onClick: () => setPage(page)
}, page)),
h34("button", {
class: "pagination-item",
type: "button",
disabled: props.page >= props.totalPages,
onClick: () => setPage(props.page + 1)
}, [iconNode("ph-arrow-right")])
]);
};
}
});
// src/vue/components/GnPopover.js
import { defineComponent as defineComponent34, h as h35, onBeforeUnmount as onBeforeUnmount6, ref as ref8 } from "vue";
var GnPopover_default = defineComponent34({
name: "GnPopover",
props: {
label: { type: String, default: "Details" },
title: { type: String, default: "" },
text: { type: String, default: "" },
icon: { type: String, default: "ph-info" },
variant: { type: String, default: "accent" }
},
setup(props, { slots }) {
const open = ref8(false);
const root = ref8(null);
const close = () => {
open.value = false;
document.removeEventListener("click", onOutsideClick);
document.removeEventListener("keydown", onKeydown);
};
const onOutsideClick = (event) => {
if (root.value && !root.value.contains(event.target)) {
close();
}
};
const onKeydown = (event) => {
if (event.key === "Escape") {
event.preventDefault();
close();
}
};
const toggle = () => {
open.value = !open.value;
if (open.value) {
setTimeout(() => document.addEventListener("click", onOutsideClick), 0);
document.addEventListener("keydown", onKeydown);
} else {
close();
}
};
onBeforeUnmount6(close);
return () => {
var _a, _b, _c;
return h35("div", { ref: root, class: cx("popover", { "is-open": open.value }) }, [
((_a = slots.trigger) == null ? void 0 : _a.call(slots, { open: open.value, toggle })) || h35(GnButton_default, {
variant: props.variant,
icon: props.icon,
"aria-expanded": open.value ? "true" : "false",
onClick: toggle
}, () => props.label),
h35("div", { class: "popover-panel" }, [
(props.title || slots.title) && h35("h3", { class: "popover-title" }, ((_b = slots.title) == null ? void 0 : _b.call(slots)) || props.title),
(props.text || slots.default) && h35("p", { class: "popover-text" }, ((_c = slots.default) == null ? void 0 : _c.call(slots)) || props.text)
])
]);
};
}
});
// src/vue/components/GnProgress.js
import { defineComponent as defineComponent35, h as h36 } from "vue";
var GnProgress_default = defineComponent35({
name: "GnProgress",
props: {
value: { type: Number, required: true },
max: { type: Number, default: 100 },
label: { type: String, default: "" },
variant: { type: String, default: "secondary" },
striped: { type: Boolean, default: false },
animated: { type: Boolean, default: false }
},
setup(props, { attrs, slots }) {
return () => {
var _a;
const percent = Math.max(0, Math.min(100, Math.round(props.value / props.max * 100)));
const variant = normalizeVariant(props.variant, "secondary");
return h36("div", {
...attrs,
class: cx("progress", `progress-${variant}`, {
"progress-striped": props.striped,
"progress-animated": props.animated
}, attrs.class),
style: { "--progress-value": `${percent}%` }
}, [
(props.label || slots.label) && h36("div", { class: "progress-header" }, [
h36("span", {}, ((_a = slots.label) == null ? void 0 : _a.call(slots)) || props.label),
h36("span", { class: "progress-value" }, `${percent}%`)
]),
h36("div", { class: "progress-track" }, [
h36("span", {
class: "progress-bar",
role: "progressbar",
"aria-valuenow": props.value,
"aria-valuemin": 0,
"aria-valuemax": props.max
})
])
]);
};
}
});
// src/vue/components/GnProgressStages.js
import { defineComponent as defineComponent36, h as h37 } from "vue";
var GnProgressStages_default = defineComponent36({
name: "GnProgressStages",
props: {
items: { type: Array, default: () => [] }
},
setup(props, { attrs }) {
return () => h37("div", { ...attrs, class: cx("progress-stages", attrs.class) }, props.items.map((item) => h37("div", {
class: cx("progress-stage", {
"progress-stage-complete": item.status === "complete",
"progress-stage-current": item.status === "current"
})
}, item.label || item)));
}
});
// src/vue/components/GnRadio.js
import { defineComponent as defineComponent37, h as h38 } from "vue";
var GnRadio_default = defineComponent37({
name: "GnRadio",
inheritAttrs: false,
props: {
modelValue: { type: [String, Number, Boolean], default: "" },
value: { type: [String, Number, Boolean], required: true },
label: { type: String, default: "" },
name: { type: String, default: "" },
disabled: { type: Boolean, default: false }
},
emits: ["update:modelValue"],
setup(props, { attrs, emit, slots }) {
return () => {
var _a;
return h38("label", { class: cx("radio", attrs.class) }, [
h38("input", {
...attrs,
type: "radio",
name: props.name,
value: props.value,
checked: props.modelValue === props.value,
disabled: props.disabled,
onChange: () => emit("update:modelValue", props.value)
}),
h38("span", { class: "radio-control", "aria-hidden": "true" }),
h38("span", { class: "radio-label" }, ((_a = slots.default) == null ? void 0 : _a.call(slots)) || props.label)
]);
};
}
});
// src/vue/components/GnRadioGroup.js
import { defineComponent as defineComponent38, h as h39 } from "vue";
var GnRadioGroup_default = defineComponent38({
name: "GnRadioGroup",
props: {
modelValue: { type: [String, Number, Boolean], default: "" },
name: { type: String, default: "gn-radio-group" },
label: { type: String, default: "" },
options: { type: Array, default: () => [] }
},
emits: ["update:modelValue"],
setup(props, { emit, slots }) {
return () => {
var _a;
return h39("div", { class: "form-group", role: "radiogroup", "aria-label": props.label || void 0 }, [
props.label && h39("div", { class: "label" }, props.label),
((_a = slots.default) == null ? void 0 : _a.call(slots)) || props.options.map((option) => h39(GnRadio_default, {
modelValue: props.modelValue,
"onUpdate:modelValue": (value) => emit("update:modelValue", value),
name: props.name,
value: option.value,
label: option.label,
disabled: option.disabled
}))
]);
};
}
});
// src/vue/components/GnRange.js
import { defineComponent as defineComponent39, h as h40 } from "vue";
var GnRange_default = defineComponent39({
name: "GnRange",
inheritAttrs: false,
props: {
modelValue: { type: [Number, String], default: 0 },
label: { type: String, default: "" },
min: { type: [Number, String], default: 0 },
max: { type: [Number, String], default: 100 },
step: { type: [Number, String], default: 1 }
},
emits: ["update:modelValue"],
setup(props, { attrs, emit }) {
return () => h40("div", { class: "range" }, [
h40("label", { class: "label" }, [
props.label,
h40("input", {
...attrs,
type: "range",
value: props.modelValue,
min: props.min,
max: props.max,
step: props.step,
onInput: (event) => emit("update:modelValue", eventValue(event))
})
])
]);
}
});
// src/vue/components/GnSearchField.js
import { defineComponent as defineComponent40, h as h41 } from "vue";
var GnSearchField_default = defineComponent40({
name: "GnSearchField",
inheritAttrs: false,
props: {
modelValue: { type: String, default: "" },
placeholder: { type: String, default: "Search" },
compact: { type: Boolean, default: true },
clearable: { type: Boolean, default: true }
},
emits: ["update:modelValue", "clear"],
setup(props, { attrs, emit }) {
const clear = () => {
emit("update:modelValue", "");
emit("clear");
};
return () => h41("div", {
class: cx("input-group search-field", { "input-group-compact": props.compact })
}, [
h41("span", { class: "input-group-addon" }, [iconNode("ph-magnifying-glass")]),
h41("input", {
...attrs,
type: "search",
value: props.modelValue,
placeholder: props.placeholder,
class: cx("input-group-input", attrs.class),
onInput: (event) => emit("update:modelValue", eventValue(event))
}),
props.clearable && h41("button", {
class: "input-group-action",
type: "button",
"aria-label": "Clear search",
onClick: clear
}, [iconNode("ph-x")])
]);
}
});
// src/vue/components/GnSelect.js
import { defineComponent as defineComponent41, h as h42 } from "vue";
var GnSelect_default = defineComponent41({
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 h42("option", { value }, label);
});
return () => {
var _a;
return h42("div", { class: "form-group" }, [
h42("label", { class: cx("label", props.state) }, [
props.label,
iconNode(props.icon),
h42("div", { class: "select-wrap" }, [
h42("select", {
...attrs,
value: props.modelValue,
class: cx("input select", attrs.class),
onChange: (event) => emit("update:modelValue", eventValue(event))
}, ((_a = slots.default) == null ? void 0 : _a.call(slots)) || optionNodes())
])
]),
props.help && h42("div", { class: cx("input-info", props.state === "error" && "error") }, props.help)
]);
};
}
});
// src/vue/components/GnSkeleton.js
import { defineComponent as defineComponent42, h as h43 } from "vue";
var GnSkeleton_default = defineComponent42({
name: "GnSkeleton",
props: {
type: { type: String, default: "line" },
stack: { type: Boolean, default: false },
count: { type: Number, default: 1 }
},
setup(props, { attrs }) {
const skeleton = (key) => h43("span", {
key,
...attrs,
class: cx("skeleton", `skeleton-${props.type}`, attrs.class)
});
return () => props.stack ? h43("div", { class: "skeleton-stack" }, Array.from({ length: props.count }, (_, index) => skeleton(index))) : skeleton(0);
}
});
// src/vue/components/GnSteps.js
import { defineComponent as defineComponent43, h as h44 } from "vue";
var GnSteps_default = defineComponent43({
name: "GnSteps",
props: {
items: { type: Array, required: true },
vertical: { type: Boolean, default: false }
},
setup(props, { attrs }) {
return () => h44("ol", {
...attrs,
class: cx("steps", { "steps-vertical": props.vertical }, attrs.class)
}, props.items.map((item, index) => h44("li", {
class: cx("step", {
"step-complete": item.status === "complete",
"step-current": item.status === "current",
"step-disabled": item.disabled || item.status === "disabled"
})
}, [
h44("span", { class: "step-marker" }, item.marker || String(index + 1)),
h44("h3", { class: "step-title" }, item.title),
item.text && h44("p", { class: "step-text" }, item.text)
])));
}
});
// src/vue/components/GnStatusCard.js
import { defineComponent as defineComponent44, h as h45 } from "vue";
var GnStatusCard_default = defineComponent44({
name: "GnStatusCard",
props: {
title: { type: String, required: true },
text: { type: String, default: "" },
icon: { type: String, default: "ph-stack" },
variant: { type: String, default: "primary" }
},
setup(props, { attrs, slots }) {
const variant = normalizeVariant(props.variant);
return () => {
var _a, _b, _c;
return h45("article", { ...attrs, class: cx("card status-card", `card-${variant}`, attrs.class) }, [
h45("span", { class: "card-title" }, ((_a = slots.title) == null ? void 0 : _a.call(slots)) || props.title),
h45("div", { class: "card-content" }, [
h45("div", { class: "status-icon-container" }, [
h45("div", { class: "status-icon" }, ((_b = slots.icon) == null ? void 0 : _b.call(slots)) || [iconNode(props.icon)])
]),
(props.text || slots.default) && h45("p", { class: "status-name" }, ((_c = slots.default) == null ? void 0 : _c.call(slots)) || props.text)
])
]);
};
}
});
// src/vue/components/GnTable.js
import { defineComponent as defineComponent45, h as h46 } from "vue";
var GnTable_default = defineComponent45({
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 () => {
var _a;
return h46("div", { class: "table-wrapper" }, [
h46("table", { class: cx("table data-list", { "table-empty": !props.rows.length }, attrs.class) }, [
props.caption && h46("caption", { class: "table-caption" }, props.caption),
h46("thead", { class: "table-head" }, [
h46("tr", { class: "table-row" }, props.columns.map((column) => h46("th", { scope: "col" }, column.label)))
]),
h46(
"tbody",
{ class: "table-body" },
props.rows.length ? props.rows.map((row) => h46("tr", { class: "table-row" }, props.columns.map((column) => {
var _a2;
const name = `cell-${column.key}`;
return h46("td", {}, ((_a2 = slots[name]) == null ? void 0 : _a2.call(slots, { row, column, value: row[column.key] })) || row[column.key]);
}))) : h46("tr", {}, [h46("td", { class: "is-empty", colspan: props.columns.length }, ((_a = slots.empty) == null ? void 0 : _a.call(slots)) || props.emptyText)])
)
])
]);
};
}
});
// src/vue/components/GnTabs.js
import { computed as computed2, defineComponent as defineComponent46, h as h47 } from "vue";
var GnTabs_default = defineComponent46({
name: "GnTabs",
props: {
modelValue: { type: String, default: "" },
items: { type: Array, required: true },
compact: { type: Boolean, default: false },
vertical: { type: Boolean, default: false },
ariaLabel: { type: String, default: "Tabs" }
},
emits: ["update:modelValue"],
setup(props, { emit, slots }) {
const activeId = computed2(() => {
var _a, _b;
return props.modelValue || ((_a = props.items.find((item) => !item.disabled)) == null ? void 0 : _a.id) || ((_b = props.items[0]) == null ? void 0 : _b.id);
});
const activate = (item) => {
if (!item.disabled) {
emit("update:modelValue", item.id);
}
};
const enabledItems = () => props.items.filter((item) => !item.disabled);
const move = (item, direction) => {
const items = enabledItems();
const index = items.findIndex((enabled) => enabled.id === item.id);
const next = items[(index + direction + items.length) % items.length];
activate(next);
};
const handleKeydown = (event, item) => {
if (event.key === "ArrowRight" || event.key === "ArrowDown") {
event.preventDefault();
move(item, 1);
} else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
event.preventDefault();
move(item, -1);
} else if (event.key === "Home") {
event.preventDefault();
activate(enabledItems()[0]);
} else if (event.key === "End") {
event.preventDefault();
const items = enabledItems();
activate(items[items.length - 1]);
}
};
return () => h47("div", {
class: cx("tabs", {
"tabs-compact": props.compact,
"tabs-vertical": props.vertical
})
}, [
h47("div", { class: "tabs-list", role: "tablist", "aria-label": props.ariaLabel }, props.items.map((item) => {
const active = item.id === activeId.value;
const panelId = `${item.id}-panel`;
return h47("button", {
class: cx("tab", { "tab-active": active }),
type: "button",
role: "tab",
"aria-selected": active ? "true" : "false",
"aria-controls": panelId,
"aria-disabled": item.disabled ? "true" : void 0,
tabindex: active ? "0" : "-1",
onClick: () => activate(item),
onKeydown: (event) => handleKeydown(event, item)
}, [
iconNode(item.icon),
item.label
]);
})),
h47("div", { class: "tabs-panels" }, props.items.map((item) => {
var _a, _b;
const active = item.id === activeId.value;
return h47("div", {
id: `${item.id}-panel`,
class: cx("tab-panel", { "tab-panel-active": active }),
role: "tabpanel",
hidden: !active
}, ((_a = slots[item.id]) == null ? void 0 : _a.call(slots, { item, active })) || active && ((_b = slots.default) == null ? void 0 : _b.call(slots, { item, active })));
}))
]);
}
});
// src/vue/components/GnTextarea.js
import { defineComponent as defineComponent47, h as h48 } from "vue";
var GnTextarea_default = defineComponent47({
name: "GnTextarea",
inheritAttrs: false,
props: {
modelValue: { type: String, default: "" },
label: { type: String, default: "" },
icon: { type: String, default: "" },
state: { type: String, default: "" },
help: { type: String, default: "" }
},
emits: ["update:modelValue"],
setup(props, { attrs, emit }) {
return () => h48("div", { class: "form-group" }, [
h48("label", { class: cx("label", props.state) }, [
props.label,
iconNode(props.icon),
h48("textarea", {
...attrs,
value: props.modelValue,
class: cx("input", attrs.class),
onInput: (event) => emit("update:modelValue", eventValue(event))
})
]),
props.help && h48("div", { class: cx("input-info", props.state === "error" && "error") }, props.help)
]);
}
});
// src/vue/components/GnTimeline.js
import { defineComponent as defineComponent48, h as h49 } from "vue";
var GnTimeline_default = defineComponent48({
name: "GnTimeline",
props: {
items: { type: Array, default: () => [] }
},
setup(props, { attrs, slots }) {
return () => h49("ol", { ...attrs, class: cx("timeline", attrs.class) }, props.items.map((item) => {
var _a, _b;
const variant = item.variant ? normalizeVariant(item.variant) : "";
return h49("li", { class: cx("timeline-item", variant && `timeline-item-${variant}`) }, [
h49("span", { class: "timeline-marker" }, [iconNode(item.icon || "ph-circle")]),
h49("div", { class: "timeline-content" }, [
h49("article", { class: "timeline-card" }, [
h49("header", { class: "timeline-header" }, [
h49("h3", { class: "timeline-title" }, item.title),
item.time && h49("time", { class: "timeline-time" }, item.time)
]),
h49("p", { class: "timeline-text" }, ((_a = slots[item.key]) == null ? void 0 : _a.call(slots, { item })) || item.text),
(item.meta || slots.meta) && h49("div", { class: "timeline-meta" }, ((_b = slots.meta) == null ? void 0 : _b.call(slots, { item })) || item.meta)
])
])
]);
}));
}
});
// src/vue/components/GnTooltip.js
import { defineComponent as defineComponent49, h as h50, ref as ref9 } from "vue";
var GnTooltip_default = defineComponent49({
name: "GnTooltip",
props: {
text: { type: String, default: "" }
},
setup(props, { attrs, slots }) {
const open = ref9(false);
return () => {
var _a, _b;
return h50("span", {
...attrs,
class: cx("tooltip", { "is-open": open.value }, attrs.class),
onFocusin: () => {
open.value = true;
},
onFocusout: () => {
open.value = false;
}
}, [
(_a = slots.default) == null ? void 0 : _a.call(slots),
h50("span", { class: "tooltip-panel", role: "tooltip" }, ((_b = slots.panel) == null ? void 0 : _b.call(slots)) || props.text)
]);
};
}
});
// src/vue/components/GnToolbar.js
import { defineComponent as defineComponent50, h as h51 } from "vue";
var GnToolbar_default = defineComponent50({
name: "GnToolbar",
props: {
title: { type: String, default: "" },
meta: { type: String, default: "" }
},
setup(props, { attrs, slots }) {
return () => {
var _a, _b, _c, _d;
return h51("div", { ...attrs, class: cx("toolbar", attrs.class) }, [
h51("div", { class: "toolbar-group" }, [
h51("div", {}, [
(props.title || slots.title) && h51("h3", { class: "toolbar-title" }, ((_a = slots.title) == null ? void 0 : _a.call(slots)) || props.title),
(props.meta || slots.meta) && h51("span", { class: "toolbar-meta" }, ((_b = slots.meta) == null ? void 0 : _b.call(slots)) || props.meta)
])
]),
(slots.default || slots.actions) && h51("div", { class: "toolbar-group" }, ((_c = slots.actions) == null ? void 0 : _c.call(slots)) || ((_d = slots.default) == null ? void 0 : _d.call(slots)))
]);
};
}
});
// src/vue/components/GnToastProvider.js
import { defineComponent as defineComponent51, h as h52, provide, ref as ref10 } from "vue";
// src/vue/composables/toast-context.js
var toastKey = Symbol("gnexus-ui-kit-toast");
// src/vue/components/GnToastProvider.js
var iconByVariant = {
info: "ph-info",
success: "ph-check-circle",
warning: "ph-warning",
danger: "ph-warning-octagon",
error: "ph-warning-octagon",
primary: "ph-info",
secondary: "ph-info"
};
var GnToastProvider_default = defineComponent51({
name: "GnToastProvider",
props: {
lifetime: { type: Number, default: 4e3 }
},
setup(props, { slots, expose }) {
const toast = ref10(null);
let timer = null;
const close = () => {
toast.value = null;
window.clearTimeout(timer);
timer = null;
};
const show = (options) => {
const variant = normalizeVariant(options.variant || options.type || "info", "info");
toast.value = {
id: Date.now(),
variant: variant === "error" ? "danger" : variant,
title: options.title || "",
text: options.text || options.message || "",
icon: options.icon || iconByVariant[variant] || iconByVariant.info
};
window.clearTimeout(timer);
if (options.lifetime !== 0) {
timer = window.setTimeout(close, options.lifetime || props.lifetime);
}
};
const api = {
show,
close,
info: (options) => show({ ...options, variant: "info" }),
success: (options) => show({ ...options, variant: "success" }),
warning: (options) => show({ ...options, variant: "warning" }),
danger: (options) => show({ ...options, variant: "danger" }),
error: (options) => show({ ...options, variant: "danger" })
};
provide(toastKey, api);
expose(api);
return () => {
var _a;
return [
(_a = slots.default) == null ? void 0 : _a.call(slots),
toast.value && h52("div", {
class: cx("toast a-show", `toast-${toast.value.variant}`),
role: "alert"
}, [
h52("div", { class: "toast-content" }, [
h52("h4", { class: "toast-title" }, [
iconNode(toast.value.icon),
toast.value.title
]),
h52("p", { class: "toast-text" }, toast.value.text)
]),
h52("button", {
class: "btn-icon toast-close",
type: "button",
"aria-label": "Close",
onClick: close
}, [iconNode("ph-x")])
])
];
};
}
});
// src/vue/components/GnUsageMeter.js
import { defineComponent as defineComponent52, h as h53 } from "vue";
var GnUsageMeter_default = defineComponent52({
name: "GnUsageMeter",
props: {
title: { type: String, required: true },
value: { type: Number, required: true },
max: { type: Number, default: 100 },
meta: { type: String, default: "" }
},
setup(props, { slots }) {
return () => {
var _a, _b;
const percent = Math.max(0, Math.min(100, Math.round(props.value / props.max * 100)));
return h53("section", { class: "usage-meter" }, [
h53("h3", { class: "usage-meter-title" }, [
((_a = slots.title) == null ? void 0 : _a.call(slots)) || props.title,
h53("span", { class: "usage-meter-value" }, `${percent}%`)
]),
h53(GnProgress_default, { value: props.value, max: props.max }),
(props.meta || slots.meta) && h53("p", { class: "usage-meter-meta" }, ((_b = slots.meta) == null ? void 0 : _b.call(slots)) || props.meta)
]);
};
}
});
// src/vue/composables/useToast.js
import { inject } from "vue";
function useToast() {
const api = inject(toastKey, null);
if (api) {
return api;
}
const missingProvider = () => {
throw new Error("GNexus UI Kit: useToast() requires <GnToastProvider> near the app root.");
};
return {
show: missingProvider,
info: missingProvider,
success: missingProvider,
warning: missingProvider,
danger: missingProvider,
error: missingProvider,
close: missingProvider
};
}
// src/vue/plugin.js
var components = {
GnAccordion: GnAccordion_default,
GnActionCard: GnActionCard_default,
GnActionList: GnActionList_default,
GnActivityLog: GnActivityLog_default,
GnAlert: GnAlert_default,
GnAvatar: GnAvatar_default,
GnAvatarStack: GnAvatarStack_default,
GnBadge: GnBadge_default,
GnButton: GnButton_default,
GnCard: GnCard_default,
GnCheckbox: GnCheckbox_default,
GnChip: GnChip_default,
GnChipGroup: GnChipGroup_default,
GnCombobox: GnCombobox_default,
GnConfirmDialog: GnConfirmDialog_default,
GnDescriptionList: GnDescriptionList_default,
GnDefinitionList: GnDefinitionList_default,
GnDropdown: GnDropdown_default,
GnDrawer: GnDrawer_default,
GnEmptyState: GnEmptyState_default,
GnFileUpload: GnFileUpload_default,
GnIconButton: GnIconButton_default,
GnIdentity: GnIdentity_default,
GnInput: GnInput_default,
GnInputGroup: GnInputGroup_default,
GnList: GnList_default,
GnLoader: GnLoader_default,
GnMetricCard: GnMetricCard_default,
GnModal: GnModal_default,
GnNavList: GnNavList_default,
GnNavigationShell: GnNavigationShell_default,
GnPageHeader: GnPageHeader_default,
GnPagination: GnPagination_default,
GnPopover: GnPopover_default,
GnProgress: GnProgress_default,
GnProgressStages: GnProgressStages_default,
GnRadio: GnRadio_default,
GnRadioGroup: GnRadioGroup_default,
GnRange: GnRange_default,
GnSearchField: GnSearchField_default,
GnSelect: GnSelect_default,
GnSkeleton: GnSkeleton_default,
GnSteps: GnSteps_default,
GnStatusCard: GnStatusCard_default,
GnSwitch: GnCheckbox_default,
GnTable: GnTable_default,
GnTabs: GnTabs_default,
GnTextarea: GnTextarea_default,
GnTimeline: GnTimeline_default,
GnTooltip: GnTooltip_default,
GnToolbar: GnToolbar_default,
GnToastProvider: GnToastProvider_default,
GnUsageMeter: GnUsageMeter_default
};
var plugin_default = {
install(app) {
Object.entries(components).forEach(([name, component]) => {
app.component(name, component);
});
}
};
export {
GnAccordion_default as GnAccordion,
GnActionCard_default as GnActionCard,
GnActionList_default as GnActionList,
GnActivityLog_default as GnActivityLog,
GnAlert_default as GnAlert,
GnAvatar_default as GnAvatar,
GnAvatarStack_default as GnAvatarStack,
GnBadge_default as GnBadge,
GnButton_default as GnButton,
GnCard_default as GnCard,
GnCheckbox_default as GnCheckbox,
GnChip_default as GnChip,
GnChipGroup_default as GnChipGroup,
GnCombobox_default as GnCombobox,
GnConfirmDialog_default as GnConfirmDialog,
GnDefinitionList_default as GnDefinitionList,
GnDescriptionList_default as GnDescriptionList,
GnDrawer_default as GnDrawer,
GnDropdown_default as GnDropdown,
GnEmptyState_default as GnEmptyState,
GnFileUpload_default as GnFileUpload,
GnIconButton_default as GnIconButton,
GnIdentity_default as GnIdentity,
GnInput_default as GnInput,
GnInputGroup_default as GnInputGroup,
GnList_default as GnList,
GnLoader_default as GnLoader,
GnMetricCard_default as GnMetricCard,
GnModal_default as GnModal,
GnNavList_default as GnNavList,
GnNavigationShell_default as GnNavigationShell,
GnPageHeader_default as GnPageHeader,
GnPagination_default as GnPagination,
GnPopover_default as GnPopover,
GnProgress_default as GnProgress,
GnProgressStages_default as GnProgressStages,
GnRadio_default as GnRadio,
GnRadioGroup_default as GnRadioGroup,
GnRange_default as GnRange,
GnSearchField_default as GnSearchField,
GnSelect_default as GnSelect,
GnSkeleton_default as GnSkeleton,
GnStatusCard_default as GnStatusCard,
GnSteps_default as GnSteps,
GnCheckbox_default as GnSwitch,
GnTable_default as GnTable,
GnTabs_default as GnTabs,
GnTextarea_default as GnTextarea,
GnTimeline_default as GnTimeline,
GnToastProvider_default as GnToastProvider,
GnToolbar_default as GnToolbar,
GnTooltip_default as GnTooltip,
GnUsageMeter_default as GnUsageMeter,
plugin_default as GnexusUiVue,
components,
useToast
};
//# sourceMappingURL=index.js.map