@gits-id/multi-select
Version:
Vue Multi Select Component
461 lines (460 loc) • 14.4 kB
JavaScript
import { defineComponent as he, toRefs as Se, ref as p, computed as j, onBeforeUpdate as ke, openBlock as i, createElementBlock as u, Fragment as D, unref as e, normalizeClass as c, toDisplayString as m, createCommentVNode as v, createElementVNode as r, mergeProps as T, renderList as ae, renderSlot as y, createVNode as f, withCtx as h, createTextVNode as E, withKeys as B, withModifiers as V, createBlock as se, toHandlers as Ce, Transition as be, nextTick as we } from "vue";
import R from "@gits-id/badge";
import xe from "@gits-id/tooltip";
import { useDebounceFn as Be, onClickOutside as Ve } from "@vueuse/core";
import { ErrorMessage as Me } from "vee-validate";
import I from "@gits-id/icon";
import { useFormValue as $e } from "@gits-id/forms";
const ze = ["for"], Ae = { class: "v-multi-select-panel" }, De = { class: "v-multi-select-badges" }, Te = ["id", "placeholder", "name", "readonly", "disabled", "onKeydown"], Ee = { class: "v-multi-select-action" }, Ie = /* @__PURE__ */ r("span", null, "Clear", -1), Ne = {
key: 0,
class: "v-multi-select-item-check"
}, Oe = /* @__PURE__ */ r("div", { class: "border-b h-1" }, null, -1), Fe = ["onClick", "onMouseover"], Pe = { class: "v-multi-select-item-text" }, Ke = {
key: 1,
class: "v-multi-select-hint"
}, Le = {
inheritAttrs: !1
}, Je = /* @__PURE__ */ he({
...Le,
__name: "VMultiSelect",
props: {
modelValue: {
type: Array,
default: () => []
},
items: {
type: Array,
default: () => []
},
itemText: {
type: String,
default: "text"
},
itemValue: {
type: String,
default: "value"
},
searchBy: {
type: [String, Function],
default: "text"
},
maxBadge: {
type: Number,
default: 0
},
placeholder: {
type: String,
default: "Search..."
},
delay: {
type: Number,
default: 500
},
id: {
type: String,
default: ""
},
name: {
type: String,
default: ""
},
inputProps: {
type: Object,
default: () => ({})
},
selectAll: {
type: Boolean,
default: !1
},
loading: {
type: Boolean,
default: !1
},
error: {
type: Boolean,
default: !1
},
errorMessages: {
type: Array,
default: () => []
},
wrapperClass: {
type: String,
default: ""
},
inputClass: {
type: String,
default: ""
},
badgeColor: {
type: String,
default: "primary"
},
badgeClass: {
type: String,
default: ""
},
badgeProps: {
type: Object,
default: () => ({})
},
dropdownClass: {
type: String,
default: ""
},
itemClass: {
type: String,
default: ""
},
checkWrapperClass: {
type: String,
default: ""
},
checkIconClass: {
type: String,
default: ""
},
noDataClass: {
type: String,
default: ""
},
loadingClass: {
type: String,
default: ""
},
label: {
type: String,
default: ""
},
labelClass: {
type: String,
default: "mb-2 block"
},
rules: {
type: String,
default: ""
},
errorClass: {
type: String,
default: "text-error-600 mt-1 text-sm"
},
transition: {
type: String,
default: "fade"
},
iconSize: {
type: String,
default: "sm"
},
readonly: {
type: Boolean,
default: !1
},
disabled: {
type: Boolean,
default: !1
},
validationMode: {
type: String,
default: "aggressive"
},
fieldOptions: {
type: Object,
default: () => ({})
},
hideError: {
type: Boolean,
default: !1
},
hint: {
type: String,
default: ""
}
},
emits: [
"click:outside",
"update:modelValue",
"search",
"selected",
"clear"
],
setup(l, { emit: S }) {
const N = l, {
maxBadge: k,
items: M,
placeholder: ne,
id: H,
delay: oe,
name: O,
inputProps: ie,
itemText: C,
itemValue: F,
searchBy: $,
selectAll: re,
loading: ue,
disabled: U,
readonly: W
} = Se(N), q = p(null), d = p(!1), b = p(""), n = p(-1), P = p([]), K = p(null), { errorMessage: z, uncontrolledValue: o } = $e(N, S, N.fieldOptions), ce = (t, a) => String(t?.[a])?.toLowerCase()?.includes(b.value.toLowerCase()), de = (t) => b.value ? [
typeof $.value == "string" ? $.value : "",
C.value,
F.value
].filter(Boolean).some((a) => typeof $.value == "function" ? $.value(t, b.value) : ce(t, a)) : !0, L = j(() => M.value.filter(de)), ve = j(
() => k.value > 0 ? o.value.slice(0, k.value) : o.value
), fe = (t, a) => {
t && (P.value[a] = t);
};
ke(() => {
P.value = [];
});
const G = (t) => {
const a = A(t);
a > -1 ? o.value.splice(a, 1) : o.value.push(t), S("selected", o);
}, A = (t) => o.value?.findIndex(
(a) => a[F.value] === t?.[F.value]
), me = (t) => A(t) > -1, J = (t, a) => t.selected || me(t), Q = () => {
o.value = [], n.value = -1, S("clear");
}, X = (t) => {
const a = A(t);
a > -1 && o.value.splice(a, 1);
}, Y = Be((t) => {
d.value = !0, b.value = t.target.value, n.value = 0, S("search", b);
}, oe.value), w = j(
() => o.value.length === M.value.length
), Z = () => {
w.value ? Q() : M.value.forEach((t) => {
A(t) < 0 && o.value.push(t);
});
}, _ = () => {
!W.value && !U.value && (d.value = !0);
};
Ve(q, () => {
S("click:outside"), d.value = !1;
});
const ye = () => {
const t = L.value[n.value];
t && G(t);
}, ee = () => {
d.value || (d.value = !0), n.value === null ? n.value = 0 : n.value < M.value.length - 1 && n.value++, le();
}, te = () => {
d.value || (d.value = !0), n.value === null ? n.value = 0 : n.value === 0 ? n.value = -1 : n.value--, le();
}, ge = (t) => {
t.shiftKey ? te() : ee();
}, pe = () => {
d.value = !1;
}, le = () => {
we(() => {
const t = n.value, s = P.value[t]?.offsetTop - (K.value.offsetHeight - 100);
K.value?.scrollTo({ top: s, behavior: "smooth" });
});
};
return (t, a) => (i(), u(D, null, [
l.label ? (i(), u("label", {
key: 0,
for: e(H) || e(O),
class: c(["v-multi-select-label", l.labelClass])
}, m(l.label), 11, ze)) : v("", !0),
r("div", T({
ref_key: "target",
ref: q,
class: ["v-multi-select", {
"v-multi-select--error": l.error || l.errorMessages.length > 0 || !!e(z)
}]
}, t.$attrs), [
r("div", null, [
r("div", Ae, [
r("div", {
class: c(["v-multi-select-input", [
{
"v-multi-select-normal": l.error || !!e(z)
},
l.wrapperClass
]]),
onClick: _
}, [
r("div", De, [
e(o).length ? (i(!0), u(D, { key: 0 }, ae(e(ve), (s, g) => y(t.$slots, "selection", {
key: s.value,
index: g,
item: s,
value: s[e(C)],
onRemove: () => X(s)
}, () => [
f(e(R), T({
color: l.badgeColor,
dismissable: "",
class: ["truncate", l.badgeClass],
onDismiss: (x) => X(s)
}, l.badgeProps), {
default: h(() => [
E(m(s[e(C)]), 1)
]),
_: 2
}, 1040, ["color", "class", "onDismiss"])
])), 128)) : v("", !0),
e(k) > 0 && e(o).length > e(k) ? y(t.$slots, "max-selection", { key: 1 }, () => [
f(e(R), { small: "" }, {
default: h(() => [
E(m(e(o).length - e(k)) + " more", 1)
]),
_: 1
})
]) : v("", !0),
r("input", T({
id: e(H),
type: "text",
class: ["v-multi-select-input-control", l.inputClass],
autofill: "false",
autocomplete: "off",
placeholder: e(ne),
name: e(O)
}, e(ie), {
readonly: e(W),
disabled: e(U),
onInput: a[0] || (a[0] = (...s) => e(Y) && e(Y)(...s)),
onFocus: _,
onKeydown: [
B(V(ye, ["prevent"]), ["enter"]),
B(V(ee, ["prevent"]), ["down"]),
B(V(te, ["prevent"]), ["up"]),
B(V(ge, ["prevent"]), ["tab"]),
B(V(pe, ["prevent"]), ["esc"])
]
}), null, 16, Te)
]),
r("div", Ee, [
e(o).length > 1 ? (i(), se(e(xe), { key: 0 }, {
activator: h(({ on: s }) => [
f(e(R), T({
circle: "",
class: "!p-1 !bg-transparent",
onClick: Q
}, Ce(s)), {
default: h(() => [
f(e(I), {
name: "ri:close-line",
size: l.iconSize,
class: "v-multi-select-icon",
"aria-hidden": "true"
}, null, 8, ["size"])
]),
_: 2
}, 1040)
]),
default: h(() => [
Ie
]),
_: 1
})) : v("", !0),
f(e(I), {
name: "heroicons:chevron-down",
size: l.iconSize,
class: "v-multi-select-icon",
"aria-hidden": "true"
}, null, 8, ["size"])
])
], 2),
f(be, { name: l.transition }, {
default: h(() => [
d.value ? (i(), u("div", {
key: 0,
ref_key: "dropdown",
ref: K,
class: c(["v-multi-select-dropdown", l.dropdownClass])
}, [
e(ue) ? (i(), u("div", {
key: 0,
class: c(["v-multi-select-dropdown-loading", l.loadingClass])
}, " Loading... ", 2)) : e(L).length ? (i(), u(D, { key: 1 }, [
e(re) ? y(t.$slots, "select-all", {
key: 0,
onClick: Z,
isSelected: e(w)
}, () => [
r("div", {
class: "v-multi-select-item",
onClick: Z
}, [
r("div", {
class: c([
e(w) ? "font-medium" : "font-normal",
"block truncate"
])
}, m(e(w) ? "Deselect All" : "Select All"), 3),
e(w) ? (i(), u("div", Ne, [
f(e(I), {
name: "heroicons:check",
class: "w-5 h-5",
"aria-hidden": "true"
})
])) : v("", !0)
]),
Oe
]) : v("", !0),
y(t.$slots, "prepend.item"),
(i(!0), u(D, null, ae(e(L), (s, g) => (i(), u("div", {
key: s.value,
ref_for: !0,
ref: (x) => fe(x, g),
onClick: (x) => G(s),
onMouseover: (x) => n.value = g,
onMouseout: a[1] || (a[1] = (x) => n.value = -1),
class: c(["v-multi-select-item group", [
l.itemClass,
{
"v-multi-select-item--focused": n.value === g,
"v-multi-select-item--active": J(s)
}
]])
}, [
r("div", {
class: c(["v-multi-select-item-check", l.checkWrapperClass])
}, [
f(e(I), {
name: "heroicons:check",
size: l.iconSize,
class: c(["v-multi-select-check-icon", l.checkIconClass]),
"aria-hidden": "true"
}, null, 8, ["size", "class"])
], 2),
r("div", Pe, [
y(t.$slots, "item.label", {
index: g,
item: s,
value: s[e(C)],
isSelected: J(s)
}, () => [
E(m(s[e(C)]), 1)
])
])
], 42, Fe))), 128)),
y(t.$slots, "append.item")
], 64)) : (i(), u("div", {
key: 2,
class: c(["pl-6 pr-4 py-2 text-gray-600", l.noDataClass])
}, " No Data ", 2))
], 2)) : v("", !0)
]),
_: 3
}, 8, ["name"])
])
])
], 16),
l.hint ? (i(), u("p", Ke, [
y(t.$slots, "hint", {}, () => [
E(m(l.hint), 1)
])
])) : v("", !0),
l.errorMessages.length && !l.hideError ? (i(), se(e(Me), {
key: 2,
class: "text-error-500 text-sm",
name: e(O)
}, null, 8, ["name"])) : e(z) ? (i(), u("div", {
key: 3,
class: c(l.errorClass)
}, m(e(z)), 3)) : v("", !0)
], 64));
}
});
export {
Je as VMultiSelect,
Je as default
};