vue-tui-components
Version:
TUI-styled Vue3 components with Pip-Boy aesthetics - retro terminal UI components for Vue 3
1,639 lines • 84.5 kB
JavaScript
import { ref as $, computed as V, createElementBlock as o, openBlock as l, normalizeClass as _, createCommentVNode as h, toDisplayString as g, useSlots as ce, renderSlot as Y, createBlock as Z, Transition as X, withCtx as W, createElementVNode as s, normalizeStyle as K, onMounted as J, onUnmounted as le, createVNode as ae, Fragment as N, renderList as L, watch as G, withDirectives as te, vModelText as se, withModifiers as U, Teleport as de, withKeys as F, nextTick as j, createTextVNode as H, unref as ue, createStaticVNode as he, vModelCheckbox as oe, h as ge, render as be } from "vue";
const D = (e, u) => {
const a = e.__vccOpts || e;
for (const [t, n] of u)
a[t] = n;
return a;
}, ke = ["aria-label"], $e = ["src", "alt"], we = {
key: 1,
class: "avatar-initials"
}, Te = {
key: 2,
class: "avatar-icon"
}, Se = {
key: 3,
class: "avatar-placeholder"
}, _e = ["aria-label"], Ie = {
__name: "TuiAvatar",
props: {
src: {
type: String,
default: ""
},
alt: {
type: String,
default: "Avatar"
},
initials: {
type: String,
default: ""
},
icon: {
type: String,
default: ""
},
size: {
type: String,
default: "medium",
validator: (e) => ["small", "medium", "large", "xlarge"].includes(e)
},
shape: {
type: String,
default: "circle",
validator: (e) => ["circle", "square"].includes(e)
},
status: {
type: String,
default: "",
validator: (e) => !e || ["online", "offline", "away", "busy"].includes(e)
}
},
setup(e) {
const u = e, a = $(!1), t = V(() => u.initials ? u.initials.slice(0, 2).toUpperCase() : ""), n = V(() => u.alt !== "Avatar" ? u.alt : u.initials ? `Avatar: ${u.initials}` : u.icon ? `Avatar with icon: ${u.icon}` : "Avatar"), i = () => {
a.value = !0;
};
return (p, c) => (l(), o("div", {
class: _(["tui-avatar", [e.size, e.shape, { "has-status": e.status }]]),
"aria-label": n.value
}, [
e.src ? (l(), o("img", {
key: 0,
src: e.src,
alt: e.alt,
class: "avatar-image",
onError: i
}, null, 40, $e)) : e.initials ? (l(), o("span", we, g(t.value), 1)) : e.icon ? (l(), o("span", Te, g(e.icon), 1)) : (l(), o("span", Se, "?")),
e.status ? (l(), o("span", {
key: 4,
class: _(["avatar-status", e.status]),
"aria-label": `Status: ${e.status}`
}, null, 10, _e)) : h("", !0)
], 10, ke));
}
}, xe = /* @__PURE__ */ D(Ie, [["__scopeId", "data-v-84d07ae3"]]), Ce = ["aria-label"], De = {
key: 0,
class: "badge-content"
}, Be = { key: 0 }, Ve = { key: 1 }, Me = {
__name: "TuiBadge",
props: {
content: {
type: [String, Number],
default: ""
},
variant: {
type: String,
default: "primary",
validator: (e) => ["primary", "secondary", "success", "error", "warning", "info"].includes(e)
},
size: {
type: String,
default: "medium",
validator: (e) => ["small", "medium", "large"].includes(e)
},
placement: {
type: String,
default: "top-right",
validator: (e) => ["top-right", "top-left", "bottom-right", "bottom-left"].includes(e)
},
max: {
type: Number,
default: 99
},
dot: {
type: Boolean,
default: !1
},
icon: {
type: String,
default: ""
},
visible: {
type: Boolean,
default: !0
}
},
setup(e) {
const u = e, a = ce(), t = V(() => !!a.default), n = V(() => typeof u.content == "number" && u.content > u.max ? `${u.max}+` : u.content), i = V(() => u.dot ? "Notification indicator" : u.icon ? `Badge with icon: ${u.icon}` : `Badge: ${n.value}`);
return (p, c) => (l(), o("span", {
class: _(["tui-badge-wrapper", { standalone: !t.value }])
}, [
Y(p.$slots, "default", {}, void 0, !0),
e.visible ? (l(), o("span", {
key: 0,
class: _(["tui-badge", [e.variant, e.size, e.placement, { dot: e.dot }]]),
"aria-label": i.value
}, [
e.dot ? h("", !0) : (l(), o("span", De, [
e.icon ? (l(), o("span", Be, g(e.icon), 1)) : e.content ? (l(), o("span", Ve, g(n.value), 1)) : h("", !0)
]))
], 10, Ce)) : h("", !0)
], 2));
}
}, Ae = /* @__PURE__ */ D(Me, [["__scopeId", "data-v-bd1fb1e4"]]), Ee = { class: "banner-content" }, Ne = {
key: 0,
class: "banner-icon"
}, Le = { class: "banner-message" }, ze = {
key: 0,
class: "banner-title"
}, Re = { class: "banner-text" }, Oe = { class: "banner-actions" }, qe = ["href"], Pe = {
__name: "TuiBanner",
props: {
message: {
type: String,
required: !0
},
title: {
type: String,
default: ""
},
variant: {
type: String,
default: "info",
validator: (e) => ["primary", "success", "error", "warning", "info"].includes(e)
},
icon: {
type: String,
default: ""
},
dismissible: {
type: Boolean,
default: !0
},
linkText: {
type: String,
default: ""
},
linkUrl: {
type: String,
default: ""
},
modelValue: {
type: Boolean,
default: !0
}
},
emits: ["update:modelValue", "dismiss", "link-click"],
setup(e, { emit: u }) {
const a = e, t = u, n = $(a.modelValue), i = () => {
n.value = !1, t("update:modelValue", !1), t("dismiss");
}, p = (c) => {
t("link-click", c);
};
return (c, d) => (l(), Z(X, { name: "banner-slide" }, {
default: W(() => [
n.value ? (l(), o("div", {
key: 0,
class: _(["tui-banner", e.variant]),
role: "banner"
}, [
s("div", Ee, [
e.icon ? (l(), o("span", Ne, g(e.icon), 1)) : h("", !0),
s("div", Le, [
e.title ? (l(), o("strong", ze, g(e.title), 1)) : h("", !0),
s("span", Re, g(e.message), 1)
])
]),
s("div", Oe, [
Y(c.$slots, "actions", {}, () => [
e.linkText && e.linkUrl ? (l(), o("a", {
key: 0,
href: e.linkUrl,
class: "banner-link",
onClick: p
}, g(e.linkText), 9, qe)) : h("", !0)
], !0),
e.dismissible ? (l(), o("button", {
key: 0,
class: "banner-close",
type: "button",
onClick: i,
"aria-label": "Dismiss banner"
}, " ✕ ")) : h("", !0)
])
], 2)) : h("", !0)
]),
_: 3
}));
}
}, Ye = /* @__PURE__ */ D(Pe, [["__scopeId", "data-v-c1d3534c"]]), Fe = ["disabled"], Ue = { class: "button-text" }, He = {
__name: "TuiButton",
props: {
label: {
type: String,
required: !0
},
variant: {
type: String,
default: "primary",
validator: (e) => ["primary", "warning", "info", "success", "secondary", "danger"].includes(e)
},
disabled: {
type: Boolean,
default: !1
},
pulse: {
type: Boolean,
default: !1
}
},
emits: ["click"],
setup(e) {
return (u, a) => (l(), o("button", {
class: _(["tui-button", [e.variant, { disabled: e.disabled, pulse: e.pulse }]]),
disabled: e.disabled,
onClick: a[0] || (a[0] = (t) => u.$emit("click", t))
}, [
a[1] || (a[1] = s("span", { class: "button-brackets" }, "[", -1)),
s("span", Ue, g(e.label), 1),
a[2] || (a[2] = s("span", { class: "button-brackets" }, "]", -1))
], 10, Fe));
}
}, ie = /* @__PURE__ */ D(He, [["__scopeId", "data-v-9ad134c2"]]), Ke = {
key: 0,
class: "card-header"
}, Ge = {
key: 0,
class: "card-title"
}, We = ["title", "aria-expanded", "aria-label"], je = ["aria-hidden"], Xe = { class: "card-body" }, Je = {
key: 0,
class: "card-footer"
}, Qe = {
__name: "TuiCard",
props: {
title: {
type: String,
default: ""
},
glowing: {
type: Boolean,
default: !1
},
fadeIn: {
type: Boolean,
default: !1
},
slideIn: {
type: Boolean,
default: !1
},
animationDelay: {
type: Number,
default: 0
},
animationDuration: {
type: Number,
default: 500
},
minimizable: {
type: Boolean,
default: !1
}
},
setup(e) {
const u = e, a = ce(), t = V(() => {
var d;
const c = (d = a.footer) == null ? void 0 : d.call(a);
return Array.isArray(c) ? c.length > 0 : !!c;
}), n = $(!1), i = () => {
n.value = !n.value;
}, p = V(() => !u.fadeIn && !u.slideIn ? {} : {
animationDelay: `${u.animationDelay}ms`,
animationDuration: `${u.animationDuration}ms`
});
return (c, d) => (l(), o("div", {
class: _(["tui-card", {
glowing: e.glowing,
"animate-fade-in": e.fadeIn,
"animate-slide-in": e.slideIn,
minimized: n.value
}]),
style: K(p.value)
}, [
e.title || e.minimizable ? (l(), o("div", Ke, [
e.title ? (l(), o("h3", Ge, g(e.title), 1)) : h("", !0),
e.minimizable ? (l(), o("button", {
key: 1,
class: "minimize-button",
type: "button",
onClick: i,
title: n.value ? "Expand" : "Minimize",
"aria-expanded": (!n.value).toString(),
"aria-label": n.value ? "Expand card" : "Minimize card"
}, g(n.value ? "▼" : "▲"), 9, We)) : h("", !0)
])) : h("", !0),
s("div", {
class: _(["card-content", { collapsed: n.value }]),
"aria-hidden": n.value ? "true" : "false"
}, [
s("div", Xe, [
Y(c.$slots, "default", {}, void 0, !0)
]),
t.value ? (l(), o("div", Je, [
Y(c.$slots, "footer", {}, void 0, !0)
])) : h("", !0)
], 10, je)
], 6));
}
}, Ze = /* @__PURE__ */ D(Qe, [["__scopeId", "data-v-d497e929"]]), et = { class: "tui-carousel" }, tt = { class: "carousel-container" }, at = ["disabled"], lt = { class: "carousel-viewport" }, st = { class: "carousel-track" }, nt = ["src", "alt"], ot = {
key: 1,
class: "carousel-caption"
}, it = ["disabled"], rt = {
key: 0,
class: "carousel-indicators"
}, ut = ["onClick", "aria-label", "aria-current"], ct = {
__name: "TuiCarousel",
props: {
items: {
type: Array,
required: !0
},
autoplay: {
type: Boolean,
default: !1
},
interval: {
type: Number,
default: 3e3
},
loop: {
type: Boolean,
default: !0
},
showControls: {
type: Boolean,
default: !0
},
showIndicators: {
type: Boolean,
default: !0
},
transition: {
type: String,
default: "slide",
validator: (e) => ["slide", "fade"].includes(e)
}
},
emits: ["change"],
setup(e, { emit: u }) {
const a = e, t = u, n = $(0), i = $("next");
let p = null;
const c = V(() => a.transition === "fade" ? "carousel-fade" : i.value === "next" ? "carousel-slide-next" : "carousel-slide-prev"), d = () => {
n.value < a.items.length - 1 ? (i.value = "next", n.value++, t("change", n.value)) : a.loop && (i.value = "next", n.value = 0, t("change", n.value));
}, y = () => {
n.value > 0 ? (i.value = "prev", n.value--, t("change", n.value)) : a.loop && (i.value = "prev", n.value = a.items.length - 1, t("change", n.value));
}, b = (r) => {
i.value = r > n.value ? "next" : "prev", n.value = r, t("change", n.value);
}, v = () => {
a.autoplay && (p = setInterval(() => {
d();
}, a.interval));
}, f = () => {
p && (clearInterval(p), p = null);
};
return J(() => {
v();
}), le(() => {
f();
}), (r, m) => (l(), o("div", et, [
s("div", tt, [
e.showControls ? (l(), o("button", {
key: 0,
class: "carousel-control prev",
onClick: y,
"aria-label": "Previous slide",
disabled: n.value === 0 && !e.loop
}, " ◄ ", 8, at)) : h("", !0),
s("div", lt, [
s("div", st, [
ae(X, {
name: c.value,
mode: "out-in"
}, {
default: W(() => [
(l(), o("div", {
key: n.value,
class: "carousel-slide"
}, [
Y(r.$slots, "default", {
item: e.items[n.value],
index: n.value
}, () => [
e.items[n.value].image ? (l(), o("img", {
key: 0,
src: e.items[n.value].image,
alt: e.items[n.value].caption || "",
class: "carousel-image"
}, null, 8, nt)) : h("", !0),
e.items[n.value].caption ? (l(), o("div", ot, g(e.items[n.value].caption), 1)) : h("", !0)
], !0)
]))
]),
_: 3
}, 8, ["name"])
])
]),
e.showControls ? (l(), o("button", {
key: 1,
class: "carousel-control next",
onClick: d,
"aria-label": "Next slide",
disabled: n.value === e.items.length - 1 && !e.loop
}, " ► ", 8, it)) : h("", !0)
]),
e.showIndicators ? (l(), o("div", rt, [
(l(!0), o(N, null, L(e.items, (k, B) => (l(), o("button", {
key: B,
class: _(["indicator", { active: B === n.value }]),
onClick: (T) => b(B),
"aria-label": `Go to slide ${B + 1}`,
"aria-current": B === n.value
}, " ■ ", 10, ut))), 128))
])) : h("", !0)
]));
}
}, dt = /* @__PURE__ */ D(ct, [["__scopeId", "data-v-27747afa"]]), vt = { class: "tui-checkbox" }, mt = ["checked"], pt = { class: "checkbox-box" }, ft = {
key: 0,
class: "checkbox-check"
}, yt = {
key: 1,
class: "checkbox-empty"
}, ht = { class: "checkbox-label" }, gt = {
__name: "TuiCheckbox",
props: {
modelValue: {
type: Boolean,
default: !1
},
label: {
type: String,
required: !0
}
},
emits: ["update:modelValue"],
setup(e) {
return (u, a) => (l(), o("label", vt, [
s("input", {
type: "checkbox",
checked: e.modelValue,
onChange: a[0] || (a[0] = (t) => u.$emit("update:modelValue", t.target.checked)),
class: "checkbox-input"
}, null, 40, mt),
s("span", pt, [
e.modelValue ? (l(), o("span", ft, "✓")) : (l(), o("span", yt, "[ ]"))
]),
s("span", ht, g(e.label), 1)
]));
}
}, bt = /* @__PURE__ */ D(gt, [["__scopeId", "data-v-7e8d4e28"]]), kt = {
key: 0,
class: "chip-icon"
}, $t = {
key: 1,
class: "chip-avatar"
}, wt = ["src", "alt"], Tt = { key: 1 }, St = { class: "chip-label" }, _t = {
__name: "TuiChip",
props: {
label: {
type: String,
required: !0
},
variant: {
type: String,
default: "primary",
validator: (e) => ["primary", "secondary", "success", "error", "warning", "info"].includes(e)
},
size: {
type: String,
default: "medium",
validator: (e) => ["small", "medium", "large"].includes(e)
},
closable: {
type: Boolean,
default: !1
},
icon: {
type: String,
default: ""
},
avatar: {
type: Boolean,
default: !1
},
avatarSrc: {
type: String,
default: ""
},
avatarText: {
type: String,
default: ""
}
},
emits: ["close"],
setup(e, { emit: u }) {
const a = u, t = (n) => {
n.stopPropagation(), a("close");
};
return (n, i) => (l(), o("div", {
class: _(["tui-chip", [e.variant, e.size, { closable: e.closable }]])
}, [
e.icon ? (l(), o("span", kt, g(e.icon), 1)) : h("", !0),
e.avatar ? (l(), o("span", $t, [
e.avatarSrc ? (l(), o("img", {
key: 0,
src: e.avatarSrc,
alt: e.label
}, null, 8, wt)) : (l(), o("span", Tt, g(e.avatarText), 1))
])) : h("", !0),
s("span", St, g(e.label), 1),
e.closable ? (l(), o("button", {
key: 2,
class: "chip-close",
type: "button",
onClick: t,
"aria-label": "Remove chip"
}, " ✕ ")) : h("", !0)
], 2));
}
}, It = /* @__PURE__ */ D(_t, [["__scopeId", "data-v-87d00535"]]), xt = { class: "tui-datepicker" }, Ct = {
key: 0,
class: "datepicker-label"
}, Dt = { class: "datepicker-input-wrapper" }, Bt = ["placeholder"], Vt = { class: "datepicker-header" }, Mt = { class: "current-month" }, At = { class: "datepicker-calendar" }, Et = { class: "calendar-weekdays" }, Nt = { class: "calendar-days" }, Lt = ["disabled", "onClick"], zt = {
__name: "TuiDatepicker",
props: {
modelValue: {
type: [Date, Array, null],
default: null
},
label: {
type: String,
default: ""
},
placeholder: {
type: String,
default: "Select date"
},
format: {
type: String,
default: "YYYY-MM-DD"
},
range: {
type: Boolean,
default: !1
}
},
emits: ["update:modelValue", "change"],
setup(e, { emit: u }) {
const a = e, t = u, n = $(!1), i = $(""), p = $((/* @__PURE__ */ new Date()).getMonth()), c = $((/* @__PURE__ */ new Date()).getFullYear()), d = $(a.modelValue), y = $(null), b = $(null), v = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], f = V(() => new Date(c.value, p.value).toLocaleDateString("en-US", { month: "long", year: "numeric" })), r = V(() => {
const w = [], S = new Date(c.value, p.value, 1), A = new Date(c.value, p.value + 1, 0), O = new Date(c.value, p.value, 0), ne = S.getDay(), fe = A.getDate(), re = O.getDate();
for (let q = ne - 1; q >= 0; q--)
w.push({
date: re - q,
month: p.value - 1,
year: c.value,
currentMonth: !1,
key: `prev-${re - q}`
});
for (let q = 1; q <= fe; q++)
w.push({
date: q,
month: p.value,
year: c.value,
currentMonth: !0,
key: `current-${q}`
});
const ye = 42 - w.length;
for (let q = 1; q <= ye; q++)
w.push({
date: q,
month: p.value + 1,
year: c.value,
currentMonth: !1,
key: `next-${q}`
});
return w;
}), m = (w) => {
if (!w) return "";
const S = new Date(w), A = S.getFullYear(), O = String(S.getMonth() + 1).padStart(2, "0"), ne = String(S.getDate()).padStart(2, "0");
return a.format.replace("YYYY", A).replace("MM", O).replace("DD", ne);
}, k = () => {
a.range && y.value ? b.value ? i.value = `${m(y.value)} - ${m(b.value)}` : i.value = m(y.value) : d.value ? i.value = m(d.value) : i.value = "";
}, B = (w) => {
if (!w.currentMonth) return !1;
const S = new Date(w.year, w.month, w.date);
if (a.range) {
if (y.value && b.value) {
const A = new Date(y.value), O = new Date(b.value);
return A.setHours(0, 0, 0, 0), O.setHours(0, 0, 0, 0), S.setHours(0, 0, 0, 0), S.getTime() === A.getTime() || S.getTime() === O.getTime();
}
return y.value && S.getTime() === new Date(y.value).setHours(0, 0, 0, 0);
}
return d.value && S.getTime() === new Date(d.value).setHours(0, 0, 0, 0);
}, T = (w) => {
if (!w.currentMonth) return !1;
const S = /* @__PURE__ */ new Date();
return w.date === S.getDate() && w.month === S.getMonth() && w.year === S.getFullYear();
}, I = (w) => {
if (!a.range || !y.value || !b.value || !w.currentMonth) return !1;
const S = new Date(w.year, w.month, w.date), A = new Date(y.value), O = new Date(b.value);
return S.setHours(0, 0, 0, 0), A.setHours(0, 0, 0, 0), O.setHours(0, 0, 0, 0), S > A && S < O;
}, x = (w) => {
const S = new Date(w.year, w.month, w.date);
a.range ? !y.value || y.value && b.value ? (y.value = S, b.value = null) : (S < y.value ? (b.value = y.value, y.value = S) : b.value = S, t("update:modelValue", [y.value, b.value]), t("change", [y.value, b.value])) : (d.value = S, t("update:modelValue", S), t("change", S), ee()), k();
}, z = () => {
p.value === 0 ? (p.value = 11, c.value--) : p.value--;
}, P = () => {
p.value === 11 ? (p.value = 0, c.value++) : p.value++;
}, E = () => {
n.value = !0;
}, ee = () => {
n.value = !1;
}, R = () => {
n.value = !n.value;
}, C = () => {
setTimeout(() => {
n.value = !1;
}, 200);
}, M = () => {
d.value = null, y.value = null, b.value = null, i.value = "", t("update:modelValue", null), t("change", null);
};
return G(() => a.modelValue, (w) => {
a.range && Array.isArray(w) ? (y.value = w[0] || null, b.value = w[1] || null) : d.value = w, k();
}, { immediate: !0 }), (w, S) => (l(), o("div", xt, [
e.label ? (l(), o("label", Ct, g(e.label), 1)) : h("", !0),
s("div", Dt, [
te(s("input", {
"onUpdate:modelValue": S[0] || (S[0] = (A) => i.value = A),
type: "text",
class: "datepicker-input",
placeholder: e.placeholder,
onFocus: E,
onBlur: C,
readonly: ""
}, null, 40, Bt), [
[se, i.value]
]),
s("button", {
type: "button",
class: "datepicker-toggle",
onClick: R,
"aria-label": "Toggle date picker"
}, " ▼ ")
]),
ae(X, { name: "picker-fade" }, {
default: W(() => [
n.value ? (l(), o("div", {
key: 0,
class: "datepicker-popup",
onMousedown: S[1] || (S[1] = U(() => {
}, ["prevent"]))
}, [
s("div", Vt, [
s("button", {
type: "button",
onClick: z,
class: "nav-button",
"aria-label": "Previous month"
}, "◄"),
s("span", Mt, g(f.value), 1),
s("button", {
type: "button",
onClick: P,
class: "nav-button",
"aria-label": "Next month"
}, "►")
]),
s("div", At, [
s("div", Et, [
(l(), o(N, null, L(v, (A) => s("span", {
key: A,
class: "weekday"
}, g(A), 1)), 64))
]),
s("div", Nt, [
(l(!0), o(N, null, L(r.value, (A) => (l(), o("button", {
key: A.key,
type: "button",
class: _(["calendar-day", {
"other-month": !A.currentMonth,
selected: B(A),
today: T(A),
"in-range": I(A)
}]),
disabled: !A.currentMonth,
onClick: (O) => x(A)
}, g(A.date), 11, Lt))), 128))
])
]),
s("div", { class: "datepicker-actions" }, [
s("button", {
type: "button",
onClick: M,
class: "action-button"
}, "Clear"),
s("button", {
type: "button",
onClick: ee,
class: "action-button primary"
}, "Done")
])
], 32)) : h("", !0)
]),
_: 1
})
]));
}
}, Rt = /* @__PURE__ */ D(zt, [["__scopeId", "data-v-cba7510f"]]), Ot = ["aria-labelledby"], qt = {
key: 0,
class: "dialog-header"
}, Pt = {
key: 0,
id: "dialog-title",
class: "dialog-title"
}, Yt = { class: "dialog-body" }, Ft = {
key: 1,
class: "dialog-footer"
}, Ut = {
key: 0,
class: "dialog-actions"
}, Ht = {
__name: "TuiDialog",
props: {
modelValue: {
type: Boolean,
default: !1
},
title: {
type: String,
default: ""
},
closable: {
type: Boolean,
default: !0
},
closeOnOverlay: {
type: Boolean,
default: !0
},
overlayOpacity: {
type: Number,
default: 0.8
},
showActions: {
type: Boolean,
default: !0
},
showConfirm: {
type: Boolean,
default: !0
},
showCancel: {
type: Boolean,
default: !0
},
confirmText: {
type: String,
default: "Confirm"
},
cancelText: {
type: String,
default: "Cancel"
},
confirmVariant: {
type: String,
default: "primary",
validator: (e) => ["primary", "success", "danger", "warning", "info"].includes(e)
}
},
emits: ["update:modelValue", "confirm", "cancel", "close"],
setup(e, { emit: u }) {
const a = e, t = u, n = () => {
t("update:modelValue", !1), t("close");
}, i = () => {
a.closeOnOverlay && a.closable && n();
}, p = () => {
t("confirm"), n();
}, c = () => {
t("cancel"), n();
};
return G(() => a.modelValue, (d) => {
d ? document.body.style.overflow = "hidden" : document.body.style.overflow = "";
}), (d, y) => (l(), Z(de, { to: "body" }, [
ae(X, { name: "dialog-fade" }, {
default: W(() => [
e.modelValue ? (l(), o("div", {
key: 0,
class: "tui-dialog-overlay",
style: K({ "--overlay-opacity": e.overlayOpacity }),
onClick: U(i, ["self"])
}, [
s("div", {
class: _(["tui-dialog", { "no-close": !e.closable }]),
role: "dialog",
"aria-modal": "true",
"aria-labelledby": e.title ? "dialog-title" : void 0
}, [
e.title || e.closable ? (l(), o("div", qt, [
e.title ? (l(), o("h3", Pt, g(e.title), 1)) : h("", !0),
e.closable ? (l(), o("button", {
key: 1,
class: "dialog-close",
type: "button",
onClick: n,
"aria-label": "Close dialog"
}, " ✕ ")) : h("", !0)
])) : h("", !0),
s("div", Yt, [
Y(d.$slots, "default", {}, void 0, !0)
]),
d.$slots.footer || e.showActions ? (l(), o("div", Ft, [
Y(d.$slots, "footer", {}, () => [
e.showActions ? (l(), o("div", Ut, [
e.showCancel ? (l(), Z(ie, {
key: 0,
label: e.cancelText,
variant: "secondary",
onClick: c
}, null, 8, ["label"])) : h("", !0),
e.showConfirm ? (l(), Z(ie, {
key: 1,
label: e.confirmText,
variant: e.confirmVariant,
onClick: p
}, null, 8, ["label", "variant"])) : h("", !0)
])) : h("", !0)
], !0)
])) : h("", !0)
], 10, Ot)
], 4)) : h("", !0)
]),
_: 3
})
]));
}
}, Kt = /* @__PURE__ */ D(Ht, [["__scopeId", "data-v-ecc5e202"]]), Gt = ["onKeydown", "tabindex"], Wt = { class: "default-trigger" }, jt = { class: "dropdown-inner" }, Xt = ["onClick", "onMouseenter"], Jt = {
key: 0,
class: "dropdown-separator"
}, Qt = {
key: 0,
class: "item-icon"
}, Zt = { class: "item-label" }, ea = {
key: 1,
class: "item-shortcut"
}, ta = {
key: 2,
class: "item-arrow"
}, aa = {
__name: "TuiDropdown",
props: {
label: {
type: String,
default: ""
},
items: {
type: Array,
required: !0
},
disabled: {
type: Boolean,
default: !1
},
align: {
type: String,
default: "left",
// 'left' or 'right'
validator: (e) => ["left", "right"].includes(e)
}
},
emits: ["item-click", "open", "close"],
setup(e, { expose: u, emit: a }) {
const t = e, n = a, i = $(null), p = $(null), c = $(!1), d = $(-1), y = $({}), b = () => {
t.disabled || (c.value ? f() : v());
}, v = async () => {
if (!t.disabled) {
if (i.value) {
const T = i.value.querySelector(".dropdown-trigger").getBoundingClientRect();
y.value = {
position: "fixed",
top: `${T.bottom + 2}px`,
left: `${T.left}px`,
minWidth: `${T.width}px`,
zIndex: 9999
};
}
c.value = !0, d.value = -1, n("open"), await j(), requestAnimationFrame(() => {
requestAnimationFrame(() => {
m();
});
}), document.addEventListener("click", r);
}
}, f = () => {
c.value = !1, d.value = -1, n("close"), document.removeEventListener("click", r);
}, r = (T) => {
i.value && !i.value.contains(T.target) && p.value && !p.value.contains(T.target) && f();
}, m = () => {
if (!i.value || !p.value) return;
const T = i.value.querySelector(".dropdown-trigger").getBoundingClientRect(), I = p.value.getBoundingClientRect();
if (I.width === 0 || I.height === 0) {
requestAnimationFrame(() => m());
return;
}
const x = window.innerWidth, z = window.innerHeight;
let P = T.bottom + 2, E = T.left;
t.align === "right" && (E = T.right - I.width), E + I.width > x && (E = x - I.width - 10), E < 10 && (E = 10), P + I.height > z && (P = T.top - I.height - 2, P < 10 && (P = 10)), y.value = {
position: "fixed",
top: `${P}px`,
left: `${E}px`,
minWidth: `${T.width}px`,
zIndex: 9999
};
}, k = (T) => {
T.disabled || T.separator || (n("item-click", T), T.action && T.action(), T.submenu || f());
}, B = (T) => {
if (!c.value) {
v();
return;
}
let I = d.value + T;
for (; I >= 0 && I < t.items.length; ) {
const x = t.items[I];
if (!x.separator && !x.disabled) {
d.value = I;
return;
}
I += T;
}
I < 0 ? d.value = t.items.length - 1 : I >= t.items.length && (d.value = 0);
};
return J(() => {
window.addEventListener("resize", m);
}), le(() => {
document.removeEventListener("click", r), window.removeEventListener("resize", m);
}), u({ open: v, close: f, toggle: b }), (T, I) => (l(), o("div", {
class: "tui-dropdown",
ref_key: "dropdownRef",
ref: i
}, [
s("div", {
class: _(["dropdown-trigger", { "is-open": c.value, "is-disabled": e.disabled }]),
onClick: b,
onKeydown: [
F(f, ["escape"]),
F(U(b, ["prevent"]), ["enter"]),
F(U(b, ["prevent"]), ["space"]),
I[0] || (I[0] = F(U((x) => B(-1), ["prevent"]), ["up"])),
I[1] || (I[1] = F(U((x) => B(1), ["prevent"]), ["down"]))
],
tabindex: e.disabled ? -1 : 0
}, [
Y(T.$slots, "trigger", { isOpen: c.value }, () => [
s("span", Wt, g(e.label), 1)
], !0)
], 42, Gt),
(l(), Z(de, { to: "body" }, [
ae(X, { name: "dropdown" }, {
default: W(() => [
c.value ? (l(), o("div", {
key: 0,
class: "dropdown-menu",
style: K(y.value),
ref_key: "menuRef",
ref: p
}, [
s("div", jt, [
(l(!0), o(N, null, L(e.items, (x, z) => (l(), o("div", {
key: x.id || z,
class: _(["dropdown-item", {
"is-highlighted": z === d.value,
"is-disabled": x.disabled,
"is-separator": x.separator,
"has-submenu": x.submenu
}]),
onClick: (P) => !x.disabled && !x.separator && k(x),
onMouseenter: (P) => d.value = z
}, [
x.separator ? (l(), o("div", Jt)) : (l(), o(N, { key: 1 }, [
x.icon ? (l(), o("span", Qt, g(x.icon), 1)) : h("", !0),
s("span", Zt, g(x.label), 1),
x.shortcut ? (l(), o("span", ea, g(x.shortcut), 1)) : h("", !0),
x.submenu ? (l(), o("span", ta, "►")) : h("", !0)
], 64))
], 42, Xt))), 128))
])
], 4)) : h("", !0)
]),
_: 1
})
]))
], 512));
}
}, ve = /* @__PURE__ */ D(aa, [["__scopeId", "data-v-d6fd60c2"]]), la = { class: "tui-header" }, sa = { class: "header-content" }, na = { class: "header-title" }, oa = {
key: 0,
class: "header-subtitle"
}, ia = { class: "header-timestamp" }, ra = {
__name: "TuiHeader",
props: {
title: {
type: String,
required: !0
},
subtitle: {
type: String,
default: ""
}
},
setup(e) {
const u = $(""), a = () => {
const n = /* @__PURE__ */ new Date();
u.value = n.toLocaleString("en-US", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: !1
});
};
let t;
return J(() => {
a(), t = setInterval(a, 1e3);
}), le(() => {
clearInterval(t);
}), (n, i) => (l(), o("header", la, [
i[0] || (i[0] = s("div", { class: "header-top" }, [
s("span", { class: "corner" }, "╔"),
s("div", { class: "header-line" }),
s("span", { class: "corner" }, "╗")
], -1)),
s("div", sa, [
s("h1", na, g(e.title), 1),
e.subtitle ? (l(), o("p", oa, g(e.subtitle), 1)) : h("", !0),
s("div", ia, g(u.value), 1)
]),
i[1] || (i[1] = s("div", { class: "header-bottom" }, [
s("span", { class: "corner" }, "╚"),
s("div", { class: "header-line" }),
s("span", { class: "corner" }, "╝")
], -1))
]));
}
}, ua = /* @__PURE__ */ D(ra, [["__scopeId", "data-v-40df859c"]]), ca = ["aria-label", "role"], da = {
__name: "TuiIcon",
props: {
icon: {
type: String,
required: !0
},
type: {
type: String,
default: "unicode",
validator: (e) => ["unicode", "material"].includes(e)
},
materialVariant: {
type: String,
default: "outlined",
validator: (e) => ["filled", "outlined", "round", "sharp"].includes(e)
},
size: {
type: String,
default: "medium",
validator: (e) => ["small", "medium", "large", "xlarge"].includes(e)
},
variant: {
type: String,
default: "primary",
validator: (e) => ["primary", "secondary", "success", "error", "warning", "info", "inherit"].includes(e)
},
spin: {
type: Boolean,
default: !1
},
pulse: {
type: Boolean,
default: !1
},
ariaLabel: {
type: String,
default: ""
},
customSize: {
type: String,
default: ""
}
},
setup(e) {
const u = e, a = V(() => u.type === "material" ? {
filled: "material-icons",
outlined: "material-icons-outlined",
round: "material-icons-round",
sharp: "material-icons-sharp"
}[u.materialVariant] : ""), t = V(() => u.customSize ? { fontSize: u.customSize } : {});
return (n, i) => (l(), o("span", {
class: _(["tui-icon", [
e.size,
e.variant,
{ spin: e.spin, pulse: e.pulse },
a.value
]]),
style: K(t.value),
"aria-label": e.ariaLabel,
role: e.ariaLabel ? "img" : void 0
}, g(e.icon), 15, ca));
}
}, va = /* @__PURE__ */ D(da, [["__scopeId", "data-v-48751b1e"]]), ma = ["src", "alt"], pa = {
key: 1,
class: "image-placeholder"
}, fa = { class: "loading-text" }, ya = {
key: 2,
class: "image-loading"
}, ha = {
key: 3,
class: "image-error"
}, ga = { class: "error-text" }, ba = {
key: 0,
class: "image-caption"
}, ka = {
__name: "TuiImage",
props: {
src: {
type: String,
required: !0
},
alt: {
type: String,
default: ""
},
lazy: {
type: Boolean,
default: !1
},
aspectRatio: {
type: String,
default: "",
validator: (e) => !e || ["1:1", "4:3", "16:9", "21:9", "3:2"].includes(e)
},
overlay: {
type: Boolean,
default: !1
},
overlayOpacity: {
type: Number,
default: 0.7
},
caption: {
type: String,
default: ""
},
loadingText: {
type: String,
default: "Loading..."
},
errorText: {
type: String,
default: "Failed to load image"
}
},
emits: ["load", "error"],
setup(e, { emit: u }) {
const a = e, t = u, n = $(!a.lazy), i = $(!1), p = $(!1);
let c = null;
const d = V(() => a.aspectRatio ? {
paddingBottom: {
"1:1": "100%",
"4:3": "75%",
"16:9": "56.25%",
"21:9": "42.86%",
"3:2": "66.67%"
}[a.aspectRatio],
position: "relative"
} : {}), y = V(() => ({
backgroundColor: `rgba(0, 0, 0, ${a.overlayOpacity})`
})), b = () => {
i.value = !0, t("load");
}, v = () => {
p.value = !0, i.value = !1, t("error");
};
return J(() => {
if (a.lazy && "IntersectionObserver" in window) {
c = new IntersectionObserver((r) => {
r.forEach((m) => {
m.isIntersecting && (n.value = !0, c == null || c.disconnect());
});
}, {
rootMargin: "50px"
});
const f = document.querySelector(".tui-image");
f && c.observe(f);
}
}), le(() => {
c == null || c.disconnect();
}), (f, r) => (l(), o("div", {
class: _(["tui-image", { "has-overlay": e.overlay || e.caption }]),
style: K(d.value)
}, [
!e.lazy || n.value ? (l(), o("img", {
key: 0,
src: e.src,
alt: e.alt,
class: _(["image-element", { loaded: i.value, error: p.value }]),
onLoad: b,
onError: v
}, null, 42, ma)) : (l(), o("div", pa, [
s("span", fa, g(e.loadingText), 1)
])),
!i.value && !p.value ? (l(), o("div", ya, [...r[0] || (r[0] = [
s("span", { class: "loading-spinner" }, "◐", -1)
])])) : h("", !0),
p.value ? (l(), o("div", ha, [
r[1] || (r[1] = s("span", null, "✕", -1)),
s("span", ga, g(e.errorText), 1)
])) : h("", !0),
(e.overlay || e.caption) && i.value ? (l(), o("div", {
key: 4,
class: "image-overlay",
style: K(y.value)
}, [
Y(f.$slots, "overlay", {}, () => [
e.caption ? (l(), o("div", ba, g(e.caption), 1)) : h("", !0)
], !0)
], 4)) : h("", !0)
], 6));
}
}, $a = /* @__PURE__ */ D(ka, [["__scopeId", "data-v-29b0ea40"]]), wa = { class: "tui-input-wrapper" }, Ta = {
key: 0,
class: "tui-label"
}, Sa = { class: "input-container" }, _a = ["type", "value", "placeholder", "disabled"], Ia = {
__name: "TuiInput",
props: {
modelValue: {
type: [String, Number],
default: ""
},
label: {
type: String,
default: ""
},
type: {
type: String,
default: "text"
},
placeholder: {
type: String,
default: ""
},
disabled: {
type: Boolean,
default: !1
}
},
emits: ["update:modelValue"],
setup(e) {
return (u, a) => (l(), o("div", wa, [
e.label ? (l(), o("label", Ta, [
a[1] || (a[1] = s("span", { class: "label-bracket" }, ">", -1)),
H(" " + g(e.label), 1)
])) : h("", !0),
s("div", Sa, [
a[2] || (a[2] = s("span", { class: "input-prompt" }, ">>", -1)),
s("input", {
type: e.type,
value: e.modelValue,
placeholder: e.placeholder,
disabled: e.disabled,
class: "tui-input",
onInput: a[0] || (a[0] = (t) => u.$emit("update:modelValue", t.target.value))
}, null, 40, _a),
a[3] || (a[3] = s("span", { class: "input-cursor" }, "_", -1))
])
]));
}
}, xa = /* @__PURE__ */ D(Ia, [["__scopeId", "data-v-808aff2f"]]), Ca = { class: "menubar-inner" }, Da = { class: "menubar-left" }, Ba = { class: "menu-label" }, Va = {
key: 0,
class: "menubar-right"
}, Ma = {
__name: "TuiMenubar",
props: {
menus: {
type: Array,
required: !0
},
compact: {
type: Boolean,
default: !1
}
},
emits: ["menu-item-click"],
setup(e, { emit: u }) {
const a = u, t = (n) => {
a("menu-item-click", n);
};
return (n, i) => (l(), o("div", {
class: _(["tui-menubar", { "is-compact": e.compact }])
}, [
s("div", Ca, [
s("div", Da, [
(l(!0), o(N, null, L(e.menus, (p) => (l(), Z(ve, {
key: p.id,
items: p.items,
onItemClick: t,
class: "menubar-item"
}, {
trigger: W(({ isOpen: c }) => [
s("div", {
class: _(["menu-trigger", { "is-open": c }])
}, [
i[0] || (i[0] = s("span", { class: "menu-prompt" }, "►", -1)),
s("span", Ba, g(p.label), 1)
], 2)
]),
_: 2
}, 1032, ["items"]))), 128))
]),
n.$slots.right ? (l(), o("div", Va, [
Y(n.$slots, "right", {}, void 0, !0)
])) : h("", !0)
])
], 2));
}
}, Aa = /* @__PURE__ */ D(Ma, [["__scopeId", "data-v-ca7b423d"]]), Ea = { class: "otp-inputs" }, Na = ["onUpdate:modelValue", "aria-label", "onInput", "onKeydown", "disabled"], La = {
key: 0,
class: "otp-error"
}, za = {
__name: "TuiOTP",
props: {
modelValue: {
type: String,
default: ""
},
length: {
type: Number,
default: 6,
validator: (e) => e > 0 && e <= 10
},
masked: {
type: Boolean,
default: !1
},
disabled: {
type: Boolean,
default: !1
},
error: {
type: String,
default: ""
},
autoFocus: {
type: Boolean,
default: !0
}
},
emits: ["update:modelValue", "complete"],
setup(e, { emit: u }) {
const a = e, t = u, n = $(Array(a.length).fill("")), i = $([]), p = $(!1);
G(() => a.modelValue, (v) => {
if (v) {
const f = v.split("").slice(0, a.length);
n.value = [...f, ...Array(a.length - f.length).fill("")];
}
}, { immediate: !0 }), G(() => a.error, (v) => {
p.value = !!v;
});
const c = (v, f) => {
const r = f.target.value;
if (!/^\d*$/.test(r)) {
n.value[v] = "";
return;
}
n.value[v] = r.slice(-1), b(), r && v < a.length - 1 && j(() => {
var m;
(m = i.value[v + 1]) == null || m.focus();
});
}, d = (v, f) => {
var r, m;
f.key === "Backspace" ? !n.value[v] && v > 0 ? j(() => {
var k;
(k = i.value[v - 1]) == null || k.focus();
}) : (n.value[v] = "", b()) : f.key === "ArrowLeft" && v > 0 ? (f.preventDefault(), (r = i.value[v - 1]) == null || r.focus()) : f.key === "ArrowRight" && v < a.length - 1 && (f.preventDefault(), (m = i.value[v + 1]) == null || m.focus());
}, y = (v) => {
var m;
v.preventDefault();
const r = (((m = v.clipboardData) == null ? void 0 : m.getData("text")) || "").replace(/\D/g, "").slice(0, a.length);
if (r) {
const k = r.split("");
n.value = [...k, ...Array(a.length - k.length).fill("")], b();
const B = Math.min(k.length, a.length - 1);
j(() => {
var T;
(T = i.value[B]) == null || T.focus();
});
}
}, b = () => {
const v = n.value.join("");
t("update:modelValue", v), v.length === a.length && t("complete", v);
};
return J(() => {
a.autoFocus && j(() => {
var v;
(v = i.value[0]) == null || v.focus();
});
}), (v, f) => (l(), o("div", {
class: _(["tui-otp", { error: p.value }])
}, [
s("div", Ea, [
(l(!0), o(N, null, L(n.value, (r, m) => te((l(), o("input", {
key: m,
ref_for: !0,
ref: (k) => i.value[m] = k,
"onUpdate:modelValue": (k) => n.value[m] = k,
type: "text",
inputmode: "numeric",
maxlength: "1",
class: _(["otp-input", { filled: n.value[m] }]),
"aria-label": `Digit ${m + 1}`,
onInput: (k) => c(m, k),
onKeydown: (k) => d(m, k),
onPaste: y,
disabled: e.disabled
}, null, 42, Na)), [
[se, n.value[m]]
])), 128))
]),
e.error ? (l(), o("p", La, g(e.error), 1)) : h("", !0)
], 2));
}
}, Ra = /* @__PURE__ */ D(za, [["__scopeId", "data-v-ca0fbb71"]]), Oa = { class: "tui-progress-wrapper" }, qa = {
key: 0,
class: "progress-header"
}, Pa = { class: "progress-label" }, Ya = { class: "progress-value" }, Fa = { class: "progress-bar-container" }, Ua = { class: "progress-segments" }, Ha = {
__name: "TuiProgressBar",
props: {
value: {
type: Number,
required: !0,
validator: (e) => e >= 0 && e <= 100
},
label: {
type: String,
default: ""
},
animated: {
type: Boolean,
default: !0
}
},
setup(e) {
return (u, a) => (l(), o("div", Oa, [
e.label ? (l(), o("div", qa, [
s("span", Pa, g(e.label), 1),
s("span", Ya, g(e.value) + "%", 1)
])) : h("", !0),
s("div", Fa, [
s("div", {
class: "progress-bar",
style: K({ width: e.value + "%" })
}, [
s("div", {
class: _(["progress-fill", { animated: e.animated }])
}, null, 2)
], 4),
s("div", Ua, [
(l(), o(N, null, L(20, (t) => s("span", {
key: t,
class: "segment"
})), 64))
])
])
]));
}
}, Ka = /* @__PURE__ */ D(Ha, [["__scopeId", "data-v-06bb074d"]]), Ga = { class: "tui-radio-group" }, Wa = {
key: 0,
class: "group-label"
}, ja = ["value", "checked", "onChange"], Xa = { class: "radio-circle" }, Ja = {
key: 0,
class: "radio-dot"
}, Qa = {
key: 1,
class: "radio-empty"
}, Za = { class: "radio-label" }, el = {
__name: "TuiRadio",
props: {
modelValue: {
type: [String, Number],
default: ""
},
options: {
type: Array,
required: !0
},
groupLabel: {
type: String,
default: ""
}
},
emits: ["update:modelValue"],
setup(e) {
return (u, a) => (l(), o("div", Ga, [
e.groupLabel ? (l(), o("label", Wa, [
a[0] || (a[0] = s("span", { class: "label-bracket" }, ">", -1)),
H(" " + g(e.groupLabel), 1)
])) : h("", !0),
(l(!0), o(N, null, L(e.options, (t) => (l(), o("label", {
key: t.value,
class: "tui-radio"
}, [
s("input", {
type: "radio",
value: t.value,
checked: e.modelValue === t.value,
onChange: (n) => u.$emit("update:modelValue", t.value),
class: "radio-input"
}, null, 40, ja),
s("span", Xa, [
e.modelValue === t.value ? (l(), o("span", Ja, "●")) : (l(), o("span", Qa, "○"))
]),
s("span", Za, g(t.label), 1)
]))), 128))
]));
}
}, tl = /* @__PURE__ */ D(el, [["__scopeId", "data-v-75d211d9"]]), al = {
key: 0,
class: "tui-label"
}, ll = ["onKeydown"], sl = { class: "select-display" }, nl = {
key: 0,
class: "dropdown-menu"
}, ol = { class: "dropdown-inner" }, il = ["onClick", "onMouseenter"], rl = { class: "option-bracket" }, ul = {
__name: "TuiSelect",
props: {
modelValue: {
type: [String, Number],
default: ""
},
label: {
type: String,
default: ""
},
options: {
type: Array,
required: !0
},
placeholder: {
type: String,
default: "SELECT OPTION"
}
},
emits: ["update:modelValue"],
setup(e, { emit: u }) {
const a = e, t = u, n = $(!1), i = $(-1), p = $(null), c = V(() => {
if (!a.modelValue) return a.placeholder;
const f = a.options.find((r) => r.value === a.modelValue);
return f ? f.label : a.placeholder;
}), d = () => {
if (n.value = !n.value, n.value) {
const f = a.options.findIndex((r) => r.value === a.modelValue);
i.value = f >= 0 ? f : 0;
}
}, y = () => {
n.value = !1, i.value = -1;
}, b = (f) => {
t("update:modelValue", f), y();
}, v = (f) => {
if (!n.value) {
n.value = !0, i.value = 0;
return;
}
i.value += f, i.value < 0 ? i.value = a.options.length - 1 : i.value >= a.options.length && (i.value = 0), i.value >= 0 && i.value < a.options.length && t("update:modelValue", a.options[i.value].value);
};
return G(() => a.modelValue, () => {
if (n.value) {
const f = a.options.findIndex((r) => r.value === a.modelValue);
f >= 0 && (i.value = f);
}
}), (f, r) => (l(), o("div", {
class: "tui-select-wrapper",
ref_key: "selectWrapper",
ref: p
}, [
e.label ? (l(), o("label", al, [
r[2] || (r[2] = s("span", { class: "label-bracket" }, ">", -1)),
H(" " + g(e.label), 1)
])) : h("", !0),
s("div", {
class: _(["select-container", { "is-open": n.value }]),
onClick: d,
tabindex: "0",
onBlur: y,
onKeydown: [
F(y, ["escape"]),
F(U(d, ["prevent"]), ["enter"]),
F(U(d, ["prevent"]), ["space"]),
r[0] || (r[0] = F(U((m) => v(-1), ["prevent"]), ["up"])),
r[1] || (r[1] = F(U((m) => v(1), ["prevent"]), ["down"]))
]
}, [
r[3] || (r[3] = s("span", { class: "select-prompt" }, ">>", -1)),
s("div", sl, g(c.value), 1),
s("span", {
class: _(["select-arrow", { "is-open": n.value }])
}, "▼", 2)
], 42, ll),
ae(X,