UNPKG

vue-smart-ui

Version:

A collection of Vue 3 smart and highly customizable UI components for modern web applications

1,633 lines (1,632 loc) 47 kB
import { computed as S, ref as $, provide as ie, createElementBlock as d, openBlock as r, unref as q, normalizeClass as _, renderSlot as B, inject as re, onMounted as A, onUnmounted as U, watch as W, createElementVNode as p, createCommentVNode as b, createTextVNode as X, toDisplayString as T, normalizeStyle as N, Fragment as j, nextTick as ue, createVNode as le, Transition as de, withCtx as ne, withDirectives as ce, vShow as fe, useSlots as me, createBlock as Z, Teleport as ve, withModifiers as Y, renderList as J, resolveDynamicComponent as pe, createApp as ye, h as ge, TransitionGroup as be, mergeProps as he } from "vue"; let ee = 0; function P(e = "base", f) { const t = () => (ee++, `${e}-${ee}`); return { autoId: S(() => f.id || t()) }; } const ke = ["id"], we = { __name: "BaseAccordion", props: { id: { type: String, default: "" }, multiple: { type: Boolean, default: !1 }, variant: { type: String, default: "default", validator: (e) => ["default", "bordered", "minimal"].includes(e) } }, setup(e) { const f = e, { autoId: t } = P("accordion", f), l = $([]); return ie("accordion", { activeItems: l, toggleItem: (a) => { if (f.multiple) { const c = l.value.indexOf(a); c === -1 ? l.value.push(a) : l.value.splice(c, 1); } else l.value = l.value.includes(a) ? [] : [a]; }, variant: f.variant }), (a, c) => (r(), d("div", { class: _(["vsui base-accordion", `base-accordion--${e.variant}`]), id: q(t) }, [ B(a.$slots, "default") ], 10, ke)); } }, $e = ["disabled", "aria-expanded"], xe = { class: "base-accordion-item__body" }, Be = { __name: "BaseAccordionItem", props: { title: { type: String, required: !0 }, disabled: { type: Boolean, default: !1 } }, setup(e) { const f = e, t = re("accordion"), l = $(Symbol()), o = $("0px"), a = $(null), c = S(() => t.activeItems.value.includes(l.value)), i = S(() => t.variant), u = () => { f.disabled || t.toggleItem(l.value); }, y = () => { a.value && (o.value = c.value ? `${a.value.scrollHeight}px` : "0px"); }, V = new ResizeObserver(y); return A(() => { a.value && (V.observe(a.value), y()); }), U(() => { V.disconnect(); }), W(c, y), (h, x) => (r(), d("div", { class: _(["vsui base-accordion-item", [ `base-accordion-item--${i.value}`, { "base-accordion-item--active": c.value, "base-accordion-item--disabled": e.disabled } ]]) }, [ p("button", { class: "base-accordion-item__header", onClick: u, disabled: e.disabled, "aria-expanded": c.value }, [ h.$slots.icon ? B(h.$slots, "icon", { key: 0 }) : b("", !0), B(h.$slots, "title", {}, () => [ X(T(e.title), 1) ]), B(h.$slots, "chevron", {}, () => [ x[0] || (x[0] = p("svg", { class: "base-accordion-item__chevron", viewBox: "0 0 24 24", width: "1.2em", height: "1.2em" }, [ p("path", { fill: "currentColor", d: "M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z" }) ], -1)) ]) ], 8, $e), p("div", { class: "base-accordion-item__content", ref_key: "contentRef", ref: a, style: N({ height: o.value }) }, [ p("div", xe, [ B(h.$slots, "default") ]) ], 4) ], 2)); } }, Se = ["id", "disabled"], Ve = { key: 0, class: "spinner" }, _e = { key: 0, class: "spinner" }, Ie = { key: 3, class: "spinner" }, Ce = { __name: "BaseButton", props: { id: { type: String, default: "" }, type: { type: String, default: "button", validator: (e) => ["button", "submit", "reset"].includes(e) }, variant: { type: String, default: "primary", validator: (e) => ["primary", "secondary", "gray", "outline", "ghost"].includes(e) }, size: { type: String, default: "medium", validator: (e) => ["small", "medium", "large", "auto"].includes(e) }, block: { type: Boolean, default: !1 }, disabled: { type: Boolean, default: !1 }, loading: { type: Boolean, default: !1 }, iconOnly: { type: Boolean, default: !1 } }, emits: ["click"], setup(e) { const f = e, { autoId: t } = P("button", f); return (l, o) => (r(), d("button", { id: q(t), class: _(["vsui base-button", [ `base-button--${e.variant}`, `base-button--${e.size}`, { "base-button--block": e.block, "base-button--disabled": e.disabled || e.loading, "base-button--icon-only": e.iconOnly } ]]), disabled: e.disabled || e.loading, onClick: o[0] || (o[0] = (a) => l.$emit("click", a)) }, [ l.$slots.prefix ? (r(), d(j, { key: 0 }, [ e.loading ? (r(), d("div", Ve)) : B(l.$slots, "prefix", { key: 1 }) ], 64)) : b("", !0), e.iconOnly ? b("", !0) : B(l.$slots, "default", { key: 1 }), l.$slots.suffix ? (r(), d(j, { key: 2 }, [ e.loading ? (r(), d("div", _e)) : B(l.$slots, "suffix", { key: 1 }) ], 64)) : b("", !0), e.loading && !l.$slots.prefix && !l.$slots.suffix ? (r(), d("div", Ie)) : b("", !0) ], 10, Se)); } }, Te = ["id", "checked", "disabled", "indeterminate"], Me = { class: "base-checkbox__checkmark" }, Ee = { key: 0, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, Re = { key: 1, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, qe = { key: 0, class: "base-checkbox__label" }, Le = { __name: "BaseCheckbox", props: { id: { type: String, default: "" }, modelValue: { type: [Boolean, Array], default: !1 }, value: { type: [String, Number, Boolean, Object], default: null }, label: { type: String, default: "" }, size: { type: String, default: "medium", validator: (e) => ["small", "medium", "large"].includes(e) }, disabled: { type: Boolean, default: !1 }, error: { type: Boolean, default: !1 }, indeterminate: { type: Boolean, default: !1 } }, emits: ["update:modelValue"], setup(e, { emit: f }) { const t = e, { autoId: l } = P("checkbox", t), o = f, a = S(() => Array.isArray(t.modelValue) ? t.modelValue.includes(t.value) : t.modelValue), c = (i) => { if (Array.isArray(t.modelValue)) { const u = [...t.modelValue]; if (i.target.checked) u.push(t.value); else { const y = u.indexOf(t.value); y > -1 && u.splice(y, 1); } o("update:modelValue", u); } else o("update:modelValue", i.target.checked); }; return (i, u) => (r(), d("label", { class: _([ "vsui base-checkbox", `base-checkbox--${e.size}`, { "base-checkbox--disabled": e.disabled, "base-checkbox--error": e.error } ]) }, [ p("input", { id: q(l), type: "checkbox", checked: a.value, disabled: e.disabled, indeterminate: e.indeterminate, class: "base-checkbox__input", onChange: c }, null, 40, Te), p("span", Me, [ B(i.$slots, "checkmark", {}, () => [ a.value && !e.indeterminate ? (r(), d("svg", Ee, u[0] || (u[0] = [ p("path", { d: "M11.6666 3.5L5.24992 9.91667L2.33325 7", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, null, -1) ]))) : b("", !0), e.indeterminate ? (r(), d("svg", Re, u[1] || (u[1] = [ p("path", { d: "M2.91675 7H11.0834", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, null, -1) ]))) : b("", !0) ]) ]), i.$slots.default || e.label ? (r(), d("span", qe, [ B(i.$slots, "default", {}, () => [ X(T(e.label), 1) ]) ])) : b("", !0) ], 2)); } }, Oe = ["id"], Ae = { __name: "BaseDropdown", props: { id: { type: String, default: "" }, modelValue: { type: Boolean, default: !1 }, variant: { type: String, default: "default", validator: (e) => ["default", "white", "dark"].includes(e) }, width: { type: String, default: "auto" }, closeOnClick: { type: Boolean, default: !0 }, closeOnClickOutside: { type: Boolean, default: !0 } }, emits: ["update:modelValue"], setup(e, { emit: f }) { const t = e, { autoId: l } = P("dropdown", t), o = f, a = $(null), c = $(null), i = $(t.modelValue), u = () => { if (!c.value || !a.value) return; const h = c.value.getBoundingClientRect(), x = a.value.getBoundingClientRect(), I = { width: window.innerWidth, height: window.innerHeight }; c.value.style.top = "100%", c.value.style.bottom = "auto", c.value.style.left = "auto", c.value.style.right = "0", x.right + h.width > I.width && (c.value.style.right = "0", c.value.style.left = "auto"), x.right - h.width < 0 && (c.value.style.left = "0", c.value.style.right = "auto"), x.bottom + h.height > I.height && (c.value.style.bottom = "100%", c.value.style.top = "auto", c.value.style.marginTop = "0", c.value.style.marginBottom = "0.5rem"); }; W( () => t.modelValue, (h) => { i.value = h, h ? (document.addEventListener("click", y), ue(() => { u(); })) : document.removeEventListener("click", y); } ); const y = (h) => { t.closeOnClickOutside && a.value && !a.value.contains(h.target) && o("update:modelValue", !1); }, V = (h) => { t.closeOnClick && !h.target.closest("[data-prevent-close]") && o("update:modelValue", !1); }; return A(() => { t.modelValue && document.addEventListener("click", y), window.addEventListener("scroll", u, !0), window.addEventListener("resize", u); }), U(() => { document.removeEventListener("click", y), window.removeEventListener("scroll", u, !0), window.removeEventListener("resize", u); }), (h, x) => (r(), d("div", { ref_key: "dropdownRef", ref: a, class: "vsui base-dropdown", id: q(l) }, [ p("div", { class: "base-dropdown__trigger", onClick: x[0] || (x[0] = (I) => o("update:modelValue", !e.modelValue)) }, [ B(h.$slots, "trigger") ]), le(de, { name: "dropdown" }, { default: ne(() => [ ce(p("div", { ref_key: "menuRef", ref: c, class: _(["base-dropdown__menu", `base-dropdown__menu--${e.variant}`]), style: N({ width: e.width }), onClick: V }, [ B(h.$slots, "default") ], 6), [ [fe, i.value] ]) ]), _: 3 }) ], 8, Oe)); } }, ze = { class: "vsui infinite-scroll" }, Fe = { class: "infinite-scroll__loader" }, Ne = { key: 0 }, je = { key: 0, class: "infinite-scroll__end" }, Pe = { __name: "BaseInfiniteScroll", props: { loading: { type: Boolean, default: !1 }, disabled: { type: Boolean, default: !1 }, threshold: { type: Number, default: 20 // pixels before the end to trigger }, container: { type: String, default: null // If null, uses window }, loadingText: { type: String, default: "Loading more items..." }, endText: { type: String, default: "There are no more items to load" } }, emits: ["load-more"], setup(e, { emit: f }) { const t = e, l = f, o = $(null), a = $(null), c = () => { o.value && o.value.disconnect(), o.value = new IntersectionObserver( (i) => { i[0].isIntersecting && !t.loading && !t.disabled && l("load-more"); }, { threshold: 0, root: t.container ? document.querySelector(t.container) : null, rootMargin: `0px 0px ${t.threshold}px 0px` } ), a.value && o.value.observe(a.value); }; return W( () => t.loading, (i, u) => { u === !0 && i === !1 && setTimeout(() => { c(); }, 100); } ), A(() => { c(); }), U(() => { o.value && o.value.disconnect(); }), (i, u) => (r(), d("div", ze, [ B(i.$slots, "default"), p("div", { ref_key: "bottomElement", ref: a, class: "infinite-scroll__trigger" }, [ e.loading ? B(i.$slots, "loading", { key: 0 }, () => [ p("div", Fe, [ u[0] || (u[0] = p("div", { class: "spinner" }, null, -1)), e.loadingText ? (r(), d("span", Ne, T(e.loadingText), 1)) : b("", !0) ]) ]) : e.disabled ? B(i.$slots, "disabled", { key: 1 }, () => [ e.endText ? (r(), d("div", je, T(e.endText), 1)) : b("", !0) ]) : b("", !0) ], 512) ])); } }, De = { key: 0, class: "base-input__label" }, He = { key: 0, class: "base-input__required", "aria-hidden": "true" }, Ke = { class: "base-input__wrapper" }, We = { key: 0, class: "base-input__prefix" }, Ue = ["id", "type", "value", "placeholder", "disabled", "readonly", "required", "aria-required", "maxlength"], Xe = { key: 1, class: "base-input__suffix" }, Ge = { __name: "BaseInput", props: { id: { type: String, default: "" }, modelValue: { type: [String, Number], default: "" }, variant: { type: String, default: "default", validator: (e) => ["default", "filled", "outlined"].includes(e) }, state: { type: String, default: null, validator: (e) => ["success", "error", "warning"].includes(e) }, type: { type: String, default: "text" }, label: { type: String, default: null }, placeholder: { type: String, default: "" }, disabled: { type: Boolean, default: !1 }, readonly: { type: Boolean, default: !1 }, required: { type: Boolean, default: !1 }, helperText: { type: String, default: null }, errorMessage: { type: String, default: null }, prefixIcon: { type: String, default: null }, suffixIcon: { type: String, default: null }, rules: { type: Array, default: () => [] }, validateOnBlur: { type: Boolean, default: !0 }, validateOnInput: { type: Boolean, default: !1 }, name: { type: String, default: "" }, mask: { type: [String, Object], default: null } }, emits: ["update:modelValue", "focus", "blur", "input", "validation", "mounted"], setup(e, { emit: f }) { const t = me(), l = e, { autoId: o } = P("input", l), a = f, c = $(null), i = $(!1), u = $(""), y = S(() => ({ "vsui base-input": !0, [`base-input--${l.variant}`]: !0, [`base-input--${s.value}`]: s.value, "base-input--disabled": l.disabled, "base-input--focused": i.value, "base-input--with-prefix": l.prefixIcon || t.prefix, "base-input--with-suffix": l.suffixIcon || t.suffix })), V = { required: (n) => ({ valid: !!(n != null && n.toString().trim()), message: "This field is required" }), email: (n) => ({ valid: !n || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(n), message: "Please enter a valid email" }), min: (n, m) => ({ valid: !n || n.length >= m, message: `Must be at least ${m} characters` }), max: (n, m) => ({ valid: !n || n.length <= m, message: `Must be no more than ${m} characters` }), pattern: (n, m) => ({ valid: !n || new RegExp(m).test(n), message: "Invalid format" }) }, h = (n) => { if (!l.rules.length) return !0; for (const m of l.rules) { if (typeof m == "string") { const C = V[m]; if (C) { const F = C(n); if (!F.valid) return u.value = F.message, !1; } continue; } if (typeof m == "object") { const [C, F] = Object.entries(m)[0], D = V[C]; if (D) { const O = D(n, F); if (!O.valid) return u.value = m.message || O.message, !1; } if (typeof m.validator == "function" && !m.validator(n)) return u.value = m.message || "Invalid value", !1; } } return u.value = "", !0; }, x = S({ get: () => l.mask === "currency" && l.modelValue ? I.currency.format(l.modelValue) : l.modelValue, set: (n) => a("update:modelValue", n) }), I = { phone: { patterns: ["(##) ####-####", "(##) #####-####"], match: (n) => n.replace(/\D/g, "").length <= 10 ? 0 : 1 }, currency: { pattern: "currency", format: (n) => { if (!n) return ""; const m = typeof n == "string" ? parseFloat(n.replace(/\D/g, "")) / 100 : n; return new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL", minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(m); }, parse: (n) => { const m = n.replace(/[^\d]/g, ""); return parseFloat(m) / 100; } }, date: "##/##/####", cpf: "###.###.###-##", cnpj: "##.###.###/####-##", cep: "#####-###" }, M = (n, m) => { if (!n) return n; if (m === "currency" || m.pattern === "currency") { const C = I.currency.parse(n); return I.currency.format(C); } if (typeof m == "string") return L(n, m); if (m.patterns) { const C = m.match(n); return L(n, m.patterns[C]); } return n; }, L = (n, m) => { if (!m) return n; const F = n.replace(/\D/g, "").split(""); let D = "", O = 0; for (let K = 0; K < m.length && F[K]; K++) m[O] === "#" ? (D += F[K], O++) : (D += m[O], O++, K--); return D; }, H = (n) => { let m = n.target.value; if (l.mask) { const C = typeof l.mask == "string" ? I[l.mask] || l.mask : l.mask.pattern; m = M(m, C), c.value && (c.value.value = m); } if (l.mask === "currency") { const C = I.currency.parse(m); x.value = C, a("update:modelValue", C); } else x.value = m, a("update:modelValue", m); if (a("input", { ...n, target: { ...n.target, value: m } }), l.validateOnInput) { const C = h(x.value); a("validation", { valid: C, error: u.value }); } }, k = (n) => { i.value = !0, a("focus", n); }, w = (n) => { if (i.value = !1, a("blur", n), l.validateOnBlur) { const m = h(x.value); a("validation", { valid: m, error: u.value }); } }, g = () => { var n; (n = c.value) == null || n.focus(); }, s = S(() => u.value ? "error" : l.state), v = S(() => u.value ? u.value : l.errorMessage || l.helperText), E = () => { const n = h(x.value); return a("validation", { valid: n, error: u.value, name: l.name }), n; }, R = S(() => l.required ? !0 : l.rules.some((n) => n === "required" ? !0 : typeof n == "object" ? n.required || Object.keys(n)[0] === "required" : !1)), z = S(() => { if (!l.mask) return; const n = typeof l.mask == "string" ? I[l.mask] || l.mask : l.mask.pattern; if (typeof n == "string") return n.length; if (n.patterns) return Math.max(...n.patterns.map((m) => m.length)); }); return A(() => { a("mounted", { validate: E, focus: g }); }), (n, m) => (r(), d("div", { class: _(y.value) }, [ e.label ? (r(), d("label", De, [ X(T(e.label) + " ", 1), R.value ? (r(), d("span", He, "*")) : b("", !0) ])) : b("", !0), p("div", Ke, [ n.$slots.prefix || e.prefixIcon ? (r(), d("div", We, [ B(n.$slots, "prefix", {}, () => [ p("i", { class: _(e.prefixIcon) }, null, 2) ]) ])) : b("", !0), p("input", { id: q(o), ref_key: "inputRef", ref: c, type: e.type, value: x.value, placeholder: e.placeholder, disabled: e.disabled, readonly: e.readonly, required: R.value, "aria-required": R.value, maxlength: z.value, class: "base-input__field", onInput: H, onFocus: k, onBlur: w }, null, 40, Ue), n.$slots.suffix || e.suffixIcon ? (r(), d("div", Xe, [ B(n.$slots, "suffix", {}, () => [ p("i", { class: _(e.suffixIcon) }, null, 2) ]) ])) : b("", !0) ]), v.value ? (r(), d("div", { key: 1, class: _(["base-input__helper", { "base-input__helper--error": u.value }]) }, T(v.value), 3)) : b("", !0) ], 2)); } }, Je = { key: 0, class: "base-popup__header" }, Qe = { class: "base-popup__content" }, Ye = { key: 1, class: "base-popup__footer" }, Ze = { __name: "BasePopup", props: { modelValue: { type: Boolean, default: !1 }, variant: { type: String, default: "default", validator: (e) => ["default", "info", "success", "warning", "error"].includes(e) }, size: { type: String, default: "medium", validator: (e) => ["small", "medium", "large"].includes(e) }, position: { type: String, default: "center", validator: (e) => ["center", "top", "bottom", "left", "right"].includes(e) }, disableClickOutside: { type: Boolean, default: !1 }, closeOnEsc: { type: Boolean, default: !0 } }, emits: ["update:modelValue", "close"], setup(e, { emit: f }) { const t = e, l = f, o = $(null), a = (i) => { !t.disableClickOutside && o.value && !o.value.contains(i.target) && (i.target.closest(".base-popup") || (l("update:modelValue", !1), l("close"))); }, c = (i) => { t.closeOnEsc && i.key === "Escape" && (l("update:modelValue", !1), l("close")); }; return A(() => { document.addEventListener("mousedown", a), document.addEventListener("keydown", c); }), U(() => { document.removeEventListener("mousedown", a), document.removeEventListener("keydown", c); }), (i, u) => (r(), Z(ve, { to: "body" }, [ e.modelValue ? (r(), d("div", { key: 0, class: _(["vsui base-popup-overlay", [`base-popup-overlay--${e.position}`]]) }, [ p("div", { ref_key: "popupRef", ref: o, class: _(["base-popup", [`base-popup--${e.variant}`, `base-popup--${e.size}`, `base-popup--${e.position}`]]) }, [ i.$slots.header ? (r(), d("div", Je, [ B(i.$slots, "header") ])) : b("", !0), p("div", Qe, [ B(i.$slots, "default") ]), i.$slots.footer ? (r(), d("div", Ye, [ B(i.$slots, "footer") ])) : b("", !0), i.$slots.close ? (r(), d("button", { key: 2, class: "base-popup__close", onClick: u[0] || (u[0] = (y) => i.$emit("update:modelValue", !1)) }, [ B(i.$slots, "close") ])) : b("", !0) ], 2) ], 2)) : b("", !0) ])); } }, et = { __name: "BaseSkeleton", props: { variant: { type: String, default: "rectangle", validator: (e) => ["rectangle", "circle", "text", "heading", "button"].includes(e) }, width: { type: String, default: "100%" }, height: { type: String, default: null }, animated: { type: Boolean, default: !0 }, rounded: { type: Boolean, default: !1 } }, setup(e) { return (f, t) => (r(), d("div", { class: _(["vsui base-skeleton", [ `base-skeleton--${e.variant}`, { "base-skeleton--animated": e.animated, "base-skeleton--rounded": e.rounded } ]]), style: N({ width: e.width, height: e.height || null }) }, [ B(f.$slots, "default") ], 6)); } }, tt = ["for"], at = { key: 0, class: "base-slider__required" }, lt = { class: "base-slider__container" }, nt = { class: "base-slider__extremity-value base-slider__extremity-value--min" }, st = { key: 0, class: "base-slider__mark-label" }, ot = ["onMousedown", "onTouchstart", "onKeydown", "aria-valuemin", "aria-valuemax", "aria-valuenow", "aria-valuetext", "aria-disabled"], it = { key: 0, class: "base-slider__thumb-value" }, rt = { class: "base-slider__extremity-value base-slider__extremity-value--max" }, ut = { key: 1, class: "base-slider__helper" }, dt = { __name: "BaseSlider", props: { id: { type: String, default: "" }, modelValue: { type: [Number, Array], default: 0 }, min: { type: Number, default: 0 }, max: { type: Number, default: 100 }, step: { type: Number, default: 1 }, label: { type: String, default: null }, disabled: { type: Boolean, default: !1 }, required: { type: Boolean, default: !1 }, helperText: { type: String, default: null }, errorMessage: { type: String, default: null }, state: { type: String, default: null, validator: (e) => ["success", "error", "warning"].includes(e) }, showValue: { type: Boolean, default: !0 }, range: { type: Boolean, default: !1 }, variant: { type: String, default: "default", validator: (e) => ["default", "filled"].includes(e) }, marks: { type: Array, default: () => [] }, formatValue: { type: Function, default: null } }, emits: ["update:modelValue", "change", "mounted"], setup(e, { emit: f }) { const t = e, l = f, { autoId: o } = P("slider", t), a = $(t.modelValue), c = $(!1), i = $(null), u = $([]), y = S(() => t.range && Array.isArray(t.modelValue)), V = S(() => t.formatValue ? y.value ? a.value.map((k) => t.formatValue(k)) : t.formatValue(a.value) : a.value), h = S(() => { if (y.value) { const [k, w] = a.value, g = (k - t.min) / (t.max - t.min) * 100, s = (w - t.min) / (t.max - t.min) * 100; return { left: `${g}%`, width: `${s - g}%` }; } else return { width: `${(a.value - t.min) / (t.max - t.min) * 100}%` }; }), x = S(() => y.value ? a.value.map((k) => `${(k - t.min) / (t.max - t.min) * 100}%`) : [`${(a.value - t.min) / (t.max - t.min) * 100}%`]), I = S(() => ({ "base-slider--disabled": t.disabled, "base-slider--success": t.state === "success", "base-slider--error": t.state === "error", "base-slider--warning": t.state === "warning", "base-slider--filled": t.variant === "filled" })); W( () => t.modelValue, (k) => { a.value = k; } ), W(a, (k) => { l("update:modelValue", k); }); const M = (k, w = 0) => { if (t.disabled) return; const g = i.value.getBoundingClientRect(), s = k.clientX - g.left, v = Math.min(Math.max(s / g.width, 0), 1), E = t.min + v * (t.max - t.min), R = Math.round(E / t.step) * t.step, z = Math.min(Math.max(R, t.min), t.max); if (y.value) { const n = [...a.value]; n[w] = z, w === 0 && n[0] > n[1] ? n[0] = n[1] : w === 1 && n[1] < n[0] && (n[1] = n[0]), a.value = n; } else a.value = z; l("change", a.value); }, L = (k, w = 0) => { if (t.disabled) return; c.value = !0, M(k, w); const g = (v) => M(v, w), s = () => { c.value = !1, document.removeEventListener("mousemove", g), document.removeEventListener("mouseup", s), document.removeEventListener("touchmove", g), document.removeEventListener("touchend", s); }; document.addEventListener("mousemove", g), document.addEventListener("mouseup", s), document.addEventListener("touchmove", g), document.addEventListener("touchend", s); }, H = (k, w = 0) => { if (t.disabled) return; const g = y.value ? a.value[w] : a.value; let s = g; switch (k.key) { case "ArrowRight": case "ArrowUp": s = Math.min(g + t.step, t.max); break; case "ArrowLeft": case "ArrowDown": s = Math.max(g - t.step, t.min); break; case "Home": s = t.min; break; case "End": s = t.max; break; default: return; } if (y.value) { const v = [...a.value]; v[w] = s, w === 0 && v[0] > v[1] ? v[0] = v[1] : w === 1 && v[1] < v[0] && (v[1] = v[0]), a.value = v; } else a.value = s; l("change", a.value), k.preventDefault(); }; return A(() => { y.value && (!Array.isArray(a.value) || a.value.length !== 2) ? a.value = [t.min, t.max] : !y.value && Array.isArray(a.value) && (a.value = t.min), l("mounted", { id: o.value, getValue: () => a.value, setValue: (k) => { a.value = k; } }); }), (k, w) => (r(), d("div", { class: _(["vsui base-slider", I.value]) }, [ e.label ? (r(), d("label", { key: 0, for: q(o), class: "base-slider__label" }, [ X(T(e.label) + " ", 1), e.required ? (r(), d("span", at, "*")) : b("", !0) ], 8, tt)) : b("", !0), p("div", lt, [ p("div", nt, T(e.formatValue ? e.formatValue(e.min) : e.min), 1), p("div", { ref_key: "sliderTrack", ref: i, class: "base-slider__track", onMousedown: w[0] || (w[0] = (g) => M(g)), onTouchstart: w[1] || (w[1] = Y((g) => M(g.touches[0]), ["prevent"])) }, [ p("div", { class: "base-slider__track-fill", style: N(h.value) }, null, 4), (r(!0), d(j, null, J(e.marks, (g) => (r(), d("div", { key: g.value, class: _(["base-slider__mark", { "base-slider__mark--active": y.value ? g.value >= a.value[0] && g.value <= a.value[1] : g.value <= a.value }]), style: N({ left: `calc(${(g.value - e.min) / (e.max - e.min) * 100}%)` }) }, [ w[2] || (w[2] = p("div", { class: "base-slider__mark-dot" }, null, -1)), g.label ? (r(), d("div", st, T(g.label), 1)) : b("", !0) ], 6))), 128)), (r(!0), d(j, null, J(x.value, (g, s) => (r(), d("div", { key: s, ref_for: !0, ref_key: "thumbRefs", ref: u, class: "base-slider__thumb", style: N({ left: g }), onMousedown: Y((v) => L(v, s), ["stop"]), onTouchstart: Y((v) => L(v.touches[0], s), ["stop", "prevent"]), onKeydown: (v) => H(v, s), tabindex: "0", role: "slider", "aria-valuemin": e.min, "aria-valuemax": e.max, "aria-valuenow": y.value ? a.value[s] : a.value, "aria-valuetext": y.value ? V.value[s] : V.value, "aria-disabled": e.disabled }, [ e.showValue ? (r(), d("div", it, T(y.value ? V.value[s] : V.value), 1)) : b("", !0) ], 44, ot))), 128)) ], 544), p("div", rt, T(e.formatValue ? e.formatValue(e.max) : e.max), 1) ]), e.helperText || e.errorMessage ? (r(), d("div", ut, T(e.errorMessage || e.helperText), 1)) : b("", !0) ], 2)); } }, ct = { key: 0, class: "base-textarea__label" }, ft = { key: 0, class: "base-textarea__required", "aria-hidden": "true" }, mt = { class: "base-textarea__wrapper" }, vt = ["id", "value", "rows", "placeholder", "disabled", "readonly", "required", "aria-required"], pt = { __name: "BaseTextarea", props: { id: { type: String, default: "" }, modelValue: { type: String, default: "" }, variant: { type: String, default: "default", validator: (e) => ["default", "filled", "outlined"].includes(e) }, state: { type: String, default: null, validator: (e) => ["success", "error", "warning"].includes(e) }, label: { type: String, default: null }, placeholder: { type: String, default: "" }, rows: { type: [String, Number], default: 3 }, maxRows: { type: [String, Number], default: null }, disabled: { type: Boolean, default: !1 }, block: { type: Boolean, default: !1 }, readonly: { type: Boolean, default: !1 }, required: { type: Boolean, default: !1 }, helperText: { type: String, default: null }, errorMessage: { type: String, default: null }, rules: { type: Array, default: () => [] }, validateOnBlur: { type: Boolean, default: !0 }, validateOnInput: { type: Boolean, default: !1 }, name: { type: String, default: "" }, resize: { type: String, default: "vertical", validator: (e) => ["none", "both", "horizontal", "vertical"].includes(e) }, autoResize: { type: Boolean, default: !1 } }, emits: ["update:modelValue", "focus", "blur", "input", "validation", "mounted"], setup(e, { emit: f }) { const t = e, { autoId: l } = P("textarea", t), o = f, a = $(null), c = $(!1), i = $(""), u = S(() => ({ "vsui base-textarea": !0, [`base-textarea--${t.variant}`]: !0, [`base-textarea--${k.value}`]: k.value, "base-textarea--disabled": t.disabled, "base-textarea--focused": c.value, "base-textarea--block": t.block, [`base-textarea--resize-${t.resize}`]: !0 })), y = { required: (s) => ({ valid: !!(s != null && s.toString().trim()), message: "This field is required" }), min: (s, v) => ({ valid: !s || s.toString().length >= v, message: `Must be at least ${v} characters` }), max: (s, v) => ({ valid: !s || s.toString().length <= v, message: `Must be no more than ${v} characters` }) }, V = () => { const s = h(t.modelValue); return o("validation", { valid: s, error: i.value, name: t.name }), s; }, h = (s) => { if (!t.rules.length) return !0; for (const v of t.rules) { if (typeof v == "string") { const E = y[v]; if (E) { const R = E(s); if (!R.valid) return i.value = R.message, !1; } continue; } if (typeof v == "object") { const [E, R] = Object.entries(v)[0], z = y[E]; if (z) { const n = z(s, R); if (!n.valid) return i.value = v.message || n.message, !1; } if (typeof v.validator == "function" && !v.validator(s)) return i.value = v.message || "Invalid value", !1; } } return i.value = "", !0; }, x = (s) => { if (o("update:modelValue", s.target.value), o("input", s), t.validateOnInput) { const v = h(s.target.value); o("validation", { valid: v, error: i.value }); } t.autoResize && L(); }, I = (s) => { c.value = !0, o("focus", s); }, M = (s) => { if (c.value = !1, o("blur", s), t.validateOnBlur) { const v = h(s.target.value); o("validation", { valid: v, error: i.value }); } }, L = () => { if (!a.value) return; a.value.style.height = "auto"; let s = a.value.scrollHeight + 2; if (t.maxRows) { const E = parseInt(getComputedStyle(a.value).lineHeight) * t.maxRows; s = Math.min(s, E); } a.value.style.height = `${s}px`; }, H = () => { var s; (s = a.value) == null || s.focus(); }, k = S(() => i.value ? "error" : t.state), w = S(() => i.value ? i.value : t.errorMessage || t.helperText), g = S(() => t.required ? !0 : t.rules.some( (s) => s === "required" || typeof s == "object" && s.required )); return A(() => { t.autoResize && L(), o("mounted", { validate: V, focus: H }); }), (s, v) => (r(), d("div", { class: _(u.value) }, [ e.label ? (r(), d("label", ct, [ X(T(e.label) + " ", 1), g.value ? (r(), d("span", ft, "*")) : b("", !0) ])) : b("", !0), p("div", mt, [ p("textarea", { id: q(l), ref_key: "textareaRef", ref: a, value: e.modelValue, rows: e.rows, placeholder: e.placeholder, disabled: e.disabled, readonly: e.readonly, required: g.value, "aria-required": g.value, class: "base-textarea__field", onInput: x, onFocus: I, onBlur: M }, null, 40, vt) ]), w.value ? (r(), d("div", { key: 1, class: _(["base-textarea__helper", { "base-textarea__helper--error": i.value }]) }, T(w.value), 3)) : b("", !0) ], 2)); } }, Q = (e, f) => { const t = e.__vccOpts || e; for (const [l, o] of f) t[l] = o; return t; }, yt = {}, gt = { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }; function bt(e, f) { return r(), d("svg", gt, f[0] || (f[0] = [ p("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }, null, -1), p("polyline", { points: "22 4 12 14.01 9 11.01" }, null, -1) ])); } const ht = /* @__PURE__ */ Q(yt, [["render", bt]]), kt = {}, wt = { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }; function $t(e, f) { return r(), d("svg", wt, f[0] || (f[0] = [ p("circle", { cx: "12", cy: "12", r: "10" }, null, -1), p("line", { x1: "15", y1: "9", x2: "9", y2: "15" }, null, -1), p("line", { x1: "9", y1: "9", x2: "15", y2: "15" }, null, -1) ])); } const xt = /* @__PURE__ */ Q(kt, [["render", $t]]), Bt = {}, St = { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }; function Vt(e, f) { return r(), d("svg", St, f[0] || (f[0] = [ p("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }, null, -1), p("line", { x1: "12", y1: "9", x2: "12", y2: "13" }, null, -1), p("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" }, null, -1) ])); } const _t = /* @__PURE__ */ Q(Bt, [["render", Vt]]), It = {}, Ct = { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }; function Tt(e, f) { return r(), d("svg", Ct, f[0] || (f[0] = [ p("circle", { cx: "12", cy: "12", r: "10" }, null, -1), p("line", { x1: "12", y1: "16", x2: "12", y2: "12" }, null, -1), p("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" }, null, -1) ])); } const te = /* @__PURE__ */ Q(It, [["render", Tt]]), Mt = ["data-toast-id"], Et = { key: 0, class: "base-toast__icon" }, Rt = { class: "base-toast__content" }, qt = { key: 0, class: "base-toast__title" }, Lt = { class: "base-toast__message" }, se = { __name: "BaseToast", props: { id: { type: [String, Number], required: !0 }, variant: { type: String, default: "default", validator: (e) => ["default", "info", "success", "warning", "error"].includes(e) }, position: { type: String, default: "top-right", validator: (e) => [ "top-right", "top-left", "top-center", "bottom-right", "bottom-left", "bottom-center" ].includes(e) }, duration: { type: Number, default: 3e3 }, closable: { type: Boolean, default: !0 }, message: { type: String, required: !0 }, title: { type: String, default: "" }, simple: { type: Boolean, default: !1 } }, emits: ["close"], setup(e, { emit: f }) { const t = e, l = f, o = $(!1), a = $(null), c = $("100%"), i = () => { t.duration > 0 && (c.value = "100%", requestAnimationFrame(() => { requestAnimationFrame(() => { c.value = "0%"; }); })); }, u = () => { o.value = !1, setTimeout(() => { l("close"); }, 100); }, y = () => { a.value && (a.value.style.animationPlayState = "paused"); }, V = () => { a.value && (a.value.style.animationPlayState = "running"); }, h = { success: ht, error: xt, warning: _t, info: te, default: te }, x = S(() => h[t.variant] || h.default); return A(() => { var I; setTimeout(() => { o.value = !0; }, 100), t.duration > 0 && (t.simple ? setTimeout(u, t.duration) : (I = a.value) == null || I.addEventListener("animationend", u, { once: !0 })), i(); }), U(() => { a.value && a.value.removeEventListener("animationend", u); }), (I, M) => (r(), d("div", { "data-toast-id": e.id, class: _(["vsui base-toast", [ `base-toast--${e.variant}`, `base-toast--${e.position}`, { "base-toast--visible": o.value }, { "base-toast--simple": e.simple } ]]), onMouseenter: y, onMouseleave: V }, [ e.simple ? b("", !0) : (r(), d("div", Et, [ (r(), Z(pe(x.value), { class: "icon" })) ])), p("div", Rt, [ !e.simple && e.title ? (r(), d("div", qt, T(e.title), 1)) : b("", !0), p("div", Lt, T(e.message), 1) ]), e.closable ? (r(), d("button", { key: 1, class: "base-toast__close", onClick: u }, M[0] || (M[0] = [ p("span", null, "×", -1) ]))) : b("", !0), !e.simple && e.duration > 0 ? (r(), d("div", { key: 2, ref_key: "progressBarRef", ref: a, class: _(["progress-bar", `progress-bar--${e.variant}`]), style: N({ animationDuration: `${e.duration}ms` }) }, null, 6)) : b("", !0) ], 42, Mt)); } }, G = $([]); let Ot = 0, ae = null; function At() { const e = () => { if (ae) return; const l = document.createElement("div"); l.id = "toast-container", document.body.appendChild(l), ae = ye({ render: () => ge(oe) }).mount(l); }, f = ({ message: l, title: o = "", variant: a = "default", position: c = "top-right", duration: i = 3e3, closable: u = !0, simple: y = !1 }) => { e(); const V = ++Ot; return G.value.push({ id: V, message: l, title: o, variant: a, position: c, duration: i, closable: u, simple: y }), V; }; return { toasts: G, addToast: f, removeToast: (l) => { const o = G.value.findIndex((a) => a.id === l); o > -1 && G.value.splice(o, 1); }, // Convenience methods default: (l, o = {}) => f({ ...o, message: l, variant: "default" }), success: (l, o = {}) => f({ ...o, message: l, variant: "success" }), error: (l, o = {}) => f({ ...o, message: l, variant: "error" }), info: (l, o = {}) => f({ ...o, message: l, variant: "info" }), warning: (l, o = {}) => f({ ...o, message: l, variant: "warning" }) }; } const oe = { __name: "ToastsContainer", setup(e) { const { toasts: f, removeToast: t } = At(), l = S(() => { const o = { "top-right": [], "top-left": [], "top-center": [], "bottom-right": [], "bottom-left": [], "bottom-center": [] }; return f.value.forEach((a) => { o[a.position].push(a); }), o; }); return (o, a) => (r(!0), d(j, null, J(l.value, (c, i) => (r(), d(j, { key: i }, [ c.length ? (r(), d("div", { key: 0, class: _(["vsui toasts-container", `toasts-container--${i}`]) }, [ le(be, { name: "toast" }, { default: ne(() => [ (r(!0), d(j, null, J(c, (u) => (r(), Z(q(se), he({ key: u.id, ref_for: !0 }, u, { onClose: (y) => q(t)(u.id) }), null, 16, ["onClose"]))), 128)) ]), _: 2 }, 1024) ], 2)) : b("", !0) ], 64))), 128)); } }, Ft = { install(e) { e.component("BaseAccordion", we), e.component("BaseAccordionItem", Be), e.component("BaseButton", Ce), e.component("BaseCheckbox", Le), e.component("BaseDropdown", Ae), e.component("BaseInfiniteScroll", Pe), e.component("BaseInput", Ge), e.component("BasePopup", Ze), e.component("BaseSkeleton", et), e.component("BaseSlider", dt), e.component("BaseTextarea", pt), e.component("BaseToast", se), e.component("ToastsContainer", oe); } }; export { we as BaseAccordion, Be as BaseAccordionItem, Ce as BaseButton, Le as BaseCheckbox, Ae as BaseDropdown, Pe as BaseInfiniteScroll, Ge as BaseInput, Ze as BasePopup, et as BaseSkeleton, dt as BaseSlider, pt as BaseTextarea, se as BaseToast, oe as ToastsContainer, Ft as default, At as useToast };