@aotearoan/neon
Version:
Neon is a lightweight design library of Vue 3 components with minimal dependencies.
195 lines (194 loc) • 6.25 kB
JavaScript
import { defineComponent as B, useAttrs as L, ref as u, computed as c, onMounted as P, onUnmounted as D, watch as K } from "vue";
import { NeonSize as z } from "../../../common/enums/NeonSize.es.js";
import { NeonFunctionalColor as C } from "../../../common/enums/NeonFunctionalColor.es.js";
import E from "../../presentation/dropdown/NeonDropdown.vue.es.js";
import T from "../../presentation/icon/NeonIcon.vue.es.js";
import U from "../switch/NeonSwitch.vue.es.js";
import { NeonDropdownPlacement as s } from "../../../common/enums/NeonDropdownPlacement.es.js";
import { NeonScrollUtils as _ } from "../../../common/utils/NeonScrollUtils.es.js";
const W = B({
name: "NeonSelect",
components: {
NeonDropdown: E,
NeonIcon: T,
NeonSwitch: U
},
props: {
/**
* Id for the dropdown button
*/
id: { type: String },
/**
* Placeholder to display as button label when there is no option selected.
*/
placeholder: { type: String, required: !0 },
/**
* Display the placeholder as the first option in the select, this is useful as an alternative to a label.
*/
placeholderAsOption: { type: Boolean, default: !1 },
/**
* Optional placeholder icon.
*/
placeholderIcon: { type: String, required: !1 },
/**
* A list of options to render in the select.
*/
options: { type: Array, required: !1 },
/**
* A list of grouped options to render in the select.
*/
groupedOptions: { type: Array, required: !1 },
/**
* Either a single string, indicating the key of the selected option or an array of selected keys in the case
* multiple = true.
*/
modelValue: { type: [String, Array], required: !0 },
/**
* Allow multi-select.
*/
multiple: { type: Boolean, default: !1 },
/**
* Placeholder when multiple values are selected.
*/
multiselectPlaceholder: { type: String, required: !1 },
/**
* Disable the select
*/
disabled: { type: Boolean, default: !1 },
/**
* The size of the dropdown - Small, Medium or Large.
*/
size: { type: String, default: z.Medium },
/**
* The color of the select.
*/
color: { type: String, default: C.LowContrast },
/**
* Placement of the dropdown contents.
*/
placement: { type: String, default: s.BottomLeft }
},
emits: [
/**
* emitted when the user changes the selection.
* @type {string | string[]} either the selected option's key (single select) or an array of the selected keys
* (multi-select).
*/
"update:modelValue"
],
setup(t, { emit: k }) {
const w = L(), y = u(null), r = u(!1), p = u(t.placement), d = u(null), a = u(-1), n = c(() => {
var e;
return t.options ? t.options : t.groupedOptions ? (e = t.groupedOptions) == null ? void 0 : e.flatMap((l) => l.options) : [];
}), S = () => {
if (!t.groupedOptions)
switch (p.value) {
case s.TopLeft:
case s.TopRight:
case s.LeftBottom:
case s.RightBottom:
return !0;
}
return !1;
}, V = () => {
var l;
const e = (l = y.value) == null ? void 0 : l.querySelector(".neon-select__option--highlighted");
e && _.scrollIntoView(e);
}, v = (e, l) => {
const o = a.value + e;
o >= 0 && o <= n.value.length - 1 && (a.value = o, d.value = n.value[a.value].key, l.preventDefault(), setTimeout(V));
}, f = (e) => {
k("update:modelValue", e);
}, g = (e) => {
if (t.multiple) {
const l = [...t.modelValue], o = l.findIndex((m) => m === e.key);
o >= 0 ? l.splice(o, 1) : l.push(e.key), f(l);
} else
t.modelValue !== e.key && (r.value = !1, f(e.key));
}, h = (e) => {
if (r.value)
switch (e.code) {
case "ArrowUp":
case "ArrowDown":
{
const l = S() ? -1 : 1;
e.code === "ArrowUp" ? v(-1 * l, e) : v(1 * l, e);
}
break;
case "Enter":
case "Space":
n.value[a.value].disabled || (g(n.value[a.value]), e.preventDefault());
break;
case "Tab":
!e.ctrlKey && !e.metaKey && !e.altKey && (r.value = !1);
break;
}
}, O = c(() => t.groupedOptions || [
{
group: "",
options: t.options || []
}
]), b = c(() => {
const { ...e } = w;
return e;
}), A = c(() => {
if (t.multiple && t.modelValue.length > 0) {
if (t.multiselectPlaceholder)
return t.multiselectPlaceholder;
if (t.modelValue.length > 1)
return `${t.modelValue.length} items selected`;
{
const e = n.value.find((l) => l.key === t.modelValue[0]);
return (e == null ? void 0 : e.label) || "";
}
} else if (t.modelValue) {
const e = n.value.find((l) => l.key === t.modelValue);
if (e)
return e.label;
}
return t.placeholder;
}), I = c(() => {
if (t.modelValue) {
const e = n.value.find((l) => l.key === t.modelValue);
if (e)
return e.icon;
}
return t.placeholderIcon;
}), N = (e) => {
const l = Array.from(e.target.options).filter((i) => i.selected).map((i) => i.value), o = n.value.filter((i) => l.indexOf(i.key) >= 0), m = t.multiple ? o.map((i) => i.key) : o[0].key;
f(m);
}, q = (e) => {
d.value = e, a.value = n.value.findIndex((l) => l.key === e);
}, x = (e) => {
p.value = e;
};
return P(() => {
document.addEventListener("keydown", h);
}), D(() => {
document.removeEventListener("keydown", h);
}), K(
() => r.value,
(e) => {
e && (d.value = n.value[0].key, a.value = 0);
}
), {
dropdown: y,
open: r,
highlightedKey: d,
highlightedIndex: a,
flattenedOptions: n,
computedLabel: A,
sanitizedAttributes: b,
computedOptions: O,
computedIcon: I,
clickOption: g,
nativeSelectChange: N,
changeHighlighted: q,
onPlacement: x
};
}
});
export {
W as default
};
//# sourceMappingURL=NeonSelect.es.js.map