@dialpad/dialtone
Version:
Dialpad's Dialtone design system monorepo
456 lines (455 loc) • 13.6 kB
JavaScript
import { validationMessageValidator as e } from "../../common/validators/index.js";
import { extractNonListeners as t, extractVueListeners as n, hasSlotContent as r, returnFirstEl as i } from "../../common/utils/index.js";
import { t as a } from "../../_plugin-vue_export-helper-BTgDAbhb.js";
import o from "../validation-messages/validation-messages.js";
import s from "../chip/chip.js";
import { POPOVER_APPEND_TO_VALUES as c } from "../popover/popover-constants.js";
import l from "../input/input.js";
import u from "../combobox-with-popover/combobox-with-popover.js";
import { CHIP_SIZES as d, CHIP_TOP_POSITION as f, MULTI_SELECT_SIZES as p } from "./combobox-multi-select-constants.js";
import { Fragment as m, createBlock as h, createElementBlock as g, createElementVNode as _, createSlots as v, createTextVNode as y, createVNode as b, mergeProps as x, normalizeClass as S, openBlock as C, renderList as w, renderSlot as T, resolveComponent as E, toDisplayString as D, toHandlers as O, withCtx as k, withKeys as A, withModifiers as j } from "vue";
//#region components/combobox_multi_select/combobox_multi_select.vue
var M = {
compatConfig: { MODE: 3 },
name: "DtComboboxMultiSelect",
components: {
DtComboboxWithPopover: u,
DtInput: l,
DtChip: s,
DtValidationMessages: o
},
inheritAttrs: !1,
props: {
label: {
type: String,
required: !0
},
labelVisible: {
type: Boolean,
default: !0
},
description: {
type: String,
default: ""
},
placeholder: {
type: String,
default: "Select one or start typing"
},
inputMessages: {
type: Array,
default: () => [],
validator: (t) => e(t)
},
showInputMessages: {
type: Boolean,
default: !0
},
loading: {
type: Boolean,
default: !1
},
loadingMessage: {
type: String,
default: "loading..."
},
showList: {
type: Boolean,
default: null
},
listMaxHeight: {
type: String,
default: "300px"
},
selectedItems: {
type: Array,
default: function() {
return [];
}
},
maxSelected: {
type: Number,
default: 0
},
maxSelectedMessage: {
type: Array,
default: function() {
return [];
}
},
hasSuggestionList: {
type: Boolean,
default: !0
},
size: {
type: String,
default: "md",
validator: (e) => Object.values(p).includes(e)
},
appendTo: {
type: [HTMLElement, String],
default: "body",
validator: (e) => c.includes(e) || e instanceof HTMLElement
},
transition: {
type: String,
default: "fade"
},
collapseOnFocusOut: {
type: Boolean,
default: !1
},
listMaxWidth: {
type: String,
default: ""
},
reservedRightSpace: {
type: Number,
default: 64
},
chipMaxWidth: {
type: String,
default: ""
},
inputClass: {
type: [
String,
Object,
Array
],
default: ""
},
inputWrapperClass: {
type: [
String,
Object,
Array
],
default: ""
},
disabled: {
type: Boolean,
default: !1
},
dialogClass: {
type: [
String,
Object,
Array
],
default: ""
}
},
emits: [
"input",
"select",
"remove",
"max-selected",
"keydown",
"chip-keydown",
"escape",
"enter",
"combobox-highlight"
],
data() {
return {
value: "",
popoverOffset: [0, 4],
showValidationMessages: !1,
resizeWindowObserver: null,
initialInputHeight: null,
CHIP_SIZES: d,
hasSlotContent: r,
inputFocused: !1,
hideInputText: !1
};
},
computed: {
inputPlaceHolder() {
return this.selectedItems?.length > 0 ? "" : this.placeholder;
},
chipListeners() {
return { keydown: (e) => {
this.disabled || (this.onChipKeyDown(e), this.$emit("chip-keydown", e));
} };
},
inputListeners() {
return {
...n(this.$attrs),
onInput: (e) => {
this.$emit("input", e), this.hasSuggestionList && this.showComboboxList();
},
onKeydown: (e) => {
if (this.disabled) return;
this.onInputKeyDown(e), this.$emit("keydown", e);
let t = e.key?.toLowerCase();
t === "escape" ? this.$emit("escape", e) : t === "enter" && this.$emit("enter", e);
},
onClick: () => {
this.hasSuggestionList && this.showComboboxList();
}
};
},
chipWrapperClass() {
return { [`d-recipe-combobox-multi-select__chip-wrapper-${this.size}--collapsed`]: !this.inputFocused && this.collapseOnFocusOut };
}
},
watch: {
selectedItems: {
deep: !0,
handler: async function() {
await this.initSelectedItems();
}
},
chipMaxWidth: { async handler() {
await this.initSelectedItems();
} },
async label() {
await this.$nextTick(), this.setChipsTopPosition();
},
async description() {
await this.$nextTick(), this.setChipsTopPosition();
},
size: { async handler() {
await this.$nextTick();
let e = this.getInput();
this.revertInputPadding(e), this.initialInputHeight = e.getBoundingClientRect().height, this.setInputPadding(), this.setChipsTopPosition();
} }
},
async mounted() {
this.setInitialInputHeight(), this.resizeWindowObserver = new ResizeObserver(async () => {
this.setChipsTopPosition(), this.setInputPadding();
}), this.resizeWindowObserver.observe(document.body), await this.initSelectedItems();
},
beforeUnmount() {
this.resizeWindowObserver?.unobserve(document.body);
},
methods: {
extractNonListeners: t,
comboboxHighlight(e) {
this.$emit("combobox-highlight", e);
},
async initSelectedItems() {
await this.$nextTick(), this.setInputPadding(), this.setChipsTopPosition(), this.setInputMinWidth(), this.checkMaxSelected();
},
onChipRemove(e) {
this.$emit("remove", e), this.$refs.input?.focus();
},
onComboboxSelect(e) {
this.loading || (this.value = "", this.$emit("select", e));
},
showComboboxList() {
this.showList ?? this.$refs.comboboxWithPopover?.showComboboxList();
},
closeComboboxList() {
this.showList ?? this.$refs.comboboxWithPopover?.closeComboboxList();
},
getChips() {
if (!this.selectedItems.length || !this.$refs.chips) return null;
let e = /* @__PURE__ */ new Set();
return this.selectedItems.map((t) => this.$refs.chips.find((n, r) => e.has(r) ? !1 : i(n.$el)?.querySelector(".d-chip__label")?.textContent?.trim() === t ? (e.add(r), !0) : !1)).filter(Boolean).map((e) => i(e.$el));
},
getChipButtons() {
let e = this.getChips();
return e && e.map((e) => i(e).querySelector("button"));
},
getLastChipButton() {
let e = this.getChipButtons();
return e && e[e.length - 1];
},
getLastChip() {
let e = this.getChips();
return e && e[e.length - 1];
},
getFirstChip() {
let e = this.getChips();
return e && e[0];
},
getInput() {
return this.$refs.input?.$refs.input;
},
onChipKeyDown(e) {
let t = e.code?.toLowerCase();
t === "arrowleft" ? this.navigateBetweenChips(e.target, !0) : t === "arrowright" && (e.target.id === this.getLastChipButton().id ? this.moveFromChipToInput() : this.navigateBetweenChips(e.target, !1));
},
onInputKeyDown(e) {
let t = e.key?.toLowerCase();
if (this.selectedItems.length > 0 && e.target.selectionStart === 0) {
if (e.target.selectionEnd !== e.target.selectionStart) return;
(t === "backspace" || t === "arrowleft") && this.moveFromInputToChip();
}
},
moveFromInputToChip() {
this.getLastChipButton().focus(), this.$refs.input?.blur(), this.closeComboboxList();
},
moveFromChipToInput() {
this.getLastChipButton().blur(), this.$refs.input?.focus(), this.showComboboxList();
},
navigateBetweenChips(e, t) {
let n = this.getChipButtons().indexOf(e), r = t ? n - 1 : n + 1;
r < 0 || r >= this.$refs.chips?.length || (this.getChipButtons()[n].blur(), this.getChipButtons()[r].focus(), this.closeComboboxList());
},
setChipsTopPosition() {
let e = this.getInput();
if (!e) return;
let t = this.$refs.inputSlotWrapper, n = e.getBoundingClientRect().top - t.getBoundingClientRect().top, r = this.$refs.chipsWrapper;
r.style.top = n - f[this.size] + "px";
},
setInputPadding() {
let e = this.getLastChip(), t = this.getInput(), n = this.$refs.chipsWrapper;
if (!t || (this.revertInputPadding(t), this.popoverOffset = [0, 4], !e) || this.collapseOnFocusOut && !this.inputFocused) return;
let r = e.offsetLeft + this.getFullWidth(e), i = t.getBoundingClientRect().width - r;
i > this.reservedRightSpace ? t.style.paddingLeft = r + "px" : t.style.paddingLeft = "4px";
let a = n.getBoundingClientRect().height - 4, o = e.getBoundingClientRect().height - 4, s = i > this.reservedRightSpace ? e.offsetTop + 2 : a + o - 9;
t.style.paddingTop = `${s}px`;
},
revertInputPadding(e) {
e.style.paddingLeft = "", e.style.paddingTop = "", e.style.paddingBottom = "";
},
getFullWidth(e) {
let t = window.getComputedStyle(e);
return e.offsetWidth + parseInt(t.marginLeft) + parseInt(t.marginRight);
},
setInputMinWidth() {
let e = this.getFirstChip(), t = this.getInput();
t && (e ? t.style.minWidth = this.getFullWidth(e) + 4 + "px" : t.style.minWidth = "");
},
checkMaxSelected() {
this.maxSelected !== 0 && (this.selectedItems.length > this.maxSelected ? (this.showValidationMessages = !0, this.$emit("max-selected")) : this.showValidationMessages = !1);
},
setInitialInputHeight() {
let e = this.getInput();
e && (this.initialInputHeight = e.getBoundingClientRect().height);
},
async handleInputFocusIn() {
this.inputFocused = !0, this.collapseOnFocusOut && (this.hideInputText = !1, await this.$nextTick(), this.setInputPadding());
},
async handleInputFocusOut() {
if (this.inputFocused = !1, this.collapseOnFocusOut) {
this.hideInputText = !0;
let e = this.getInput();
if (!e || !e.style.paddingTop) return;
this.revertInputPadding(e);
}
}
}
}, N = { ref: "header" }, P = {
key: 1,
class: "d-recipe-combobox-multi-select__list--loading"
}, F = { ref: "footer" };
function I(e, t, n, r, i, a) {
let o = E("dt-chip"), s = E("dt-input"), c = E("dt-validation-messages"), l = E("dt-combobox-with-popover");
return C(), h(l, x({
ref: "comboboxWithPopover",
label: n.label,
"show-list": n.showList,
"max-height": n.listMaxHeight,
"max-width": n.listMaxWidth,
"popover-offset": i.popoverOffset,
"has-suggestion-list": n.hasSuggestionList,
"content-width": "anchor",
"append-to": n.appendTo,
"dialog-class": n.dialogClass,
transition: n.transition
}, a.extractNonListeners(e.$attrs), {
onSelect: a.onComboboxSelect,
onHighlight: a.comboboxHighlight
}), v({
input: k(({ onInput: e }) => [_("span", {
ref: "inputSlotWrapper",
class: "d-recipe-combobox-multi-select__input-wrapper",
onFocusin: t[1] || (t[1] = (...e) => a.handleInputFocusIn && a.handleInputFocusIn(...e)),
onFocusout: t[2] || (t[2] = (...e) => a.handleInputFocusOut && a.handleInputFocusOut(...e))
}, [
_("span", {
ref: "chipsWrapper",
class: S(["d-recipe-combobox-multi-select__chip-wrapper", a.chipWrapperClass])
}, [(C(!0), g(m, null, w(n.selectedItems, (e, t) => (C(), h(o, x({
ref_for: !0,
ref: "chips",
key: `${t}-${e}`,
"label-class": ["d-chip__label"],
class: ["d-recipe-combobox-multi-select__chip", { "d-recipe-combobox-multi-select__chip--truncate": !!n.chipMaxWidth }],
style: { maxWidth: n.chipMaxWidth },
size: i.CHIP_SIZES[n.size],
disabled: n.disabled
}, O(a.chipListeners), {
onKeydown: A((t) => a.onChipRemove(e), ["backspace"]),
onClose: (t) => a.onChipRemove(e)
}), {
default: k(() => [y(D(e), 1)]),
_: 2
}, 1040, [
"class",
"style",
"size",
"disabled",
"onKeydown",
"onClose"
]))), 128))], 2),
b(s, x({
ref: "input",
modelValue: i.value,
"onUpdate:modelValue": t[0] || (t[0] = (e) => i.value = e),
class: "d-recipe-combobox-multi-select__input",
"input-class": [n.inputClass, { "d-recipe-combobox-multi-select__input--hidden": i.hideInputText }],
"input-wrapper-class": n.inputWrapperClass,
disabled: n.disabled,
"aria-label": n.label,
label: n.labelVisible ? n.label : "",
description: n.description,
placeholder: a.inputPlaceHolder,
"show-messages": n.showInputMessages,
messages: n.inputMessages,
size: n.size
}, a.inputListeners, { onInput: e }), null, 16, [
"modelValue",
"input-class",
"input-wrapper-class",
"disabled",
"aria-label",
"label",
"description",
"placeholder",
"show-messages",
"messages",
"size",
"onInput"
]),
b(c, {
"validation-messages": n.maxSelectedMessage,
"show-messages": i.showValidationMessages
}, null, 8, ["validation-messages", "show-messages"])
], 544)]),
list: k(() => [_("div", {
ref: "list",
class: "d-recipe-combobox-multi-select__list",
onMousedown: t[3] || (t[3] = j(() => {}, ["prevent"]))
}, [n.loading ? (C(), g("div", P, D(n.loadingMessage), 1)) : T(e.$slots, "list", { key: 0 })], 544)]),
_: 2
}, [i.hasSlotContent(e.$slots.header) ? {
name: "header",
fn: k(() => [_("div", N, [T(e.$slots, "header")], 512)]),
key: "0"
} : void 0, i.hasSlotContent(e.$slots.footer) ? {
name: "footer",
fn: k(() => [_("div", F, [T(e.$slots, "footer")], 512)]),
key: "1"
} : void 0]), 1040, [
"label",
"show-list",
"max-height",
"max-width",
"popover-offset",
"has-suggestion-list",
"append-to",
"dialog-class",
"transition",
"onSelect",
"onHighlight"
]);
}
var L = /* @__PURE__ */ a(M, [["render", I]]);
//#endregion
export { L as default };
//# sourceMappingURL=combobox-multi-select.js.map