bootstrap-vue-next
Version:
Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development
489 lines (488 loc) • 17 kB
JavaScript
import { L as useToNumber, h as useFocus, j as syncRef, o as onKeyStroke } from "./dist-Dn5blevd.mjs";
import { t as useId$1 } from "./useId-CCwnEmGh.mjs";
import { t as useDefaults } from "./useDefaults-CCWS15M8.mjs";
import { t as useColorVariantClasses } from "./useColorVariantClasses-GuDw8a_O.mjs";
import { t as escapeRegExpChars } from "./stringUtils-BP8rZgjn.mjs";
import { t as BCloseButton_default } from "./BCloseButton-DrD0tpan.mjs";
import { t as useStateClass } from "./useStateClass-DKjpw1Pn.mjs";
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, mergeModels, mergeProps, normalizeClass, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useModel, useSlots, useTemplateRef, withCtx } from "vue";
//#region src/components/BFormTags/BFormTag.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1$1 = ["id"];
//#endregion
//#region src/components/BFormTags/BFormTag.vue
var BFormTag_default = /* @__PURE__ */ defineComponent({
__name: "BFormTag",
props: {
disabled: {
type: Boolean,
default: false
},
id: { default: void 0 },
noRemove: {
type: Boolean,
default: false
},
pill: {
type: Boolean,
default: false
},
removeLabel: { default: "Remove tag" },
tag: { default: "span" },
title: { default: void 0 },
variant: { default: "secondary" }
},
emits: ["remove"],
setup(__props, { emit: __emit }) {
const props = useDefaults(__props, "BFormTag");
const emit = __emit;
const slots = useSlots();
const computedId = useId$1(() => props.id);
const tagText = computed(() => ((slots.default?.({})[0].children ?? "").toString() || props.title) ?? "");
const taglabelId = computed(() => `${computedId.value}taglabel__`);
const colorClasses = useColorVariantClasses(props);
const computedClasses = computed(() => [colorClasses.value, {
"rounded-pill": props.pill,
"disabled": props.disabled
}]);
return (_ctx, _cache) => {
return openBlock(), createBlock(resolveDynamicComponent(unref(props).tag), {
id: unref(computedId),
title: tagText.value,
class: normalizeClass(["badge b-form-tag d-inline-flex align-items-center mw-100", computedClasses.value]),
"aria-labelledby": taglabelId.value
}, {
default: withCtx(() => [createElementVNode("span", {
id: taglabelId.value,
class: "b-form-tag-content flex-grow-1 text-truncate"
}, [renderSlot(_ctx.$slots, "default", {}, () => [createTextVNode(toDisplayString(tagText.value), 1)])], 8, _hoisted_1$1), !unref(props).disabled && !unref(props).noRemove ? (openBlock(), createBlock(BCloseButton_default, {
key: 0,
"aria-keyshortcuts": "Delete",
"aria-label": unref(props).removeLabel,
class: "b-form-tag-remove",
"aria-describedby": taglabelId.value,
"aria-controls": unref(props).id,
onClick: _cache[0] || (_cache[0] = ($event) => emit("remove", tagText.value))
}, null, 8, [
"aria-label",
"aria-describedby",
"aria-controls"
])) : createCommentVNode("", true)]),
_: 3
}, 8, [
"id",
"title",
"class",
"aria-labelledby"
]);
};
}
});
//#endregion
//#region src/components/BFormTags/BFormTags.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = ["id"];
var _hoisted_2 = [
"id",
"for",
"aria-live"
];
var _hoisted_3 = ["id", "aria-live"];
var _hoisted_4 = ["id"];
var _hoisted_5 = ["aria-controls"];
var _hoisted_6 = {
role: "group",
class: "d-flex"
};
var _hoisted_7 = [
"id",
"disabled",
"value",
"type",
"placeholder",
"form",
"required",
"aria-required"
];
var _hoisted_8 = ["disabled"];
var _hoisted_9 = ["aria-live"];
var _hoisted_10 = {
key: 0,
class: "d-block invalid-feedback"
};
var _hoisted_11 = {
key: 1,
class: "form-text text-body-secondary"
};
var _hoisted_12 = {
key: 2,
class: "form-text text-body-secondary"
};
var _hoisted_13 = ["name", "value"];
//#endregion
//#region src/components/BFormTags/BFormTags.vue
var BFormTags_default = /* @__PURE__ */ defineComponent({
__name: "BFormTags",
props: /* @__PURE__ */ mergeModels({
addButtonText: { default: "Add" },
addButtonVariant: { default: "outline-secondary" },
addOnChange: {
type: Boolean,
default: false
},
autofocus: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
duplicateTagText: { default: "Duplicate tag(s)" },
feedbackAriaLive: { default: "assertive" },
form: { default: void 0 },
ignoreInputFocusSelector: { default: () => [
".b-form-tag",
"button",
"input",
"select"
] },
inputAttrs: { default: void 0 },
inputClass: { default: void 0 },
inputId: { default: void 0 },
inputType: { default: "text" },
invalidTagText: { default: "Invalid tag(s)" },
limit: { default: void 0 },
limitTagsText: { default: "Tag limit reached" },
name: { default: void 0 },
noAddOnEnter: {
type: Boolean,
default: false
},
noOuterFocus: {
type: Boolean,
default: false
},
noTagRemove: {
type: Boolean,
default: false
},
placeholder: { default: "Add tag..." },
removeOnDelete: {
type: Boolean,
default: false
},
required: {
type: Boolean,
default: false
},
separator: { default: void 0 },
size: { default: "md" },
state: {
type: [Boolean, null],
default: null
},
tagClass: { default: void 0 },
tagPills: {
type: Boolean,
default: false
},
tagRemoveLabel: { default: void 0 },
tagRemovedLabel: { default: "Tag removed" },
tagValidator: {
type: Function,
default: () => true
},
tagVariant: { default: "secondary" }
}, {
"modelValue": { default: () => [] },
"modelModifiers": {}
}),
emits: /* @__PURE__ */ mergeModels([
"blur",
"focus",
"focusin",
"focusout",
"tag-state"
], ["update:modelValue"]),
setup(__props, { expose: __expose, emit: __emit }) {
const props = useDefaults(__props, "BFormTags");
const emit = __emit;
const modelValue = useModel(__props, "modelValue");
const computedId = useId$1();
const limitNumber = useToNumber(() => props.limit ?? NaN);
const stateClass = useStateClass(() => props.state);
const input = useTemplateRef("_input");
const { focused } = useFocus(input, { initialValue: props.autofocus });
const _inputId = computed(() => props.inputId || `${computedId.value}input__`);
const tags = ref([...modelValue.value]);
const inputValue = ref("");
const shouldRemoveOnDelete = ref(modelValue.value.length > 0);
const lastRemovedTag = ref("");
const validTags = ref([]);
const invalidTags = ref([]);
const duplicateTags = ref([]);
syncRef(modelValue, tags, {
direction: "ltr",
transform: { ltr: (v) => [...v] }
});
const computedClasses = computed(() => [stateClass.value, {
[`form-control-${props.size}`]: props.size !== "md",
disabled: props.disabled,
focus: focused.value
}]);
const isDuplicate = computed(() => tags.value.includes(inputValue.value));
const isInvalid = computed(() => inputValue.value === "" ? false : !props.tagValidator(inputValue.value));
const isLimitReached = computed(() => tags.value.length === limitNumber.value);
const disableAddButton = computed(() => !isInvalid.value && !isDuplicate.value);
const onFocusin = (e) => {
if (props.disabled) {
e.target.blur();
return;
}
emit("focusin", e);
};
const onClick = (e) => {
if (props.disabled || props.noOuterFocus) return;
const { target } = e;
const ignoreSelectors = props.ignoreInputFocusSelector;
if (ignoreSelectors && target instanceof Element) {
const selector = typeof ignoreSelectors === "string" ? ignoreSelectors : ignoreSelectors.join(",");
if (selector && target.closest(selector)) return;
}
focused.value = true;
};
const onFocus = (e) => {
if (props.disabled || props.noOuterFocus) return;
focused.value = true;
emit("focus", e);
};
const onBlur = (e) => {
focused.value = false;
emit("blur", e);
};
const onInput = (e) => {
const value = typeof e === "string" ? e : e.target.value;
shouldRemoveOnDelete.value = false;
if (props.separator?.includes(value.charAt(0)) && value.length > 0) {
if (input.value) input.value.value = "";
return;
}
inputValue.value = value;
if (props.separator?.includes(value.charAt(value.length - 1))) {
addTag(value.slice(0, value.length - 1));
return;
}
validTags.value = props.tagValidator(value) && !isDuplicate.value ? [value] : [];
invalidTags.value = props.tagValidator(value) ? [] : [value];
duplicateTags.value = isDuplicate.value ? [value] : [];
emit("tag-state", validTags.value, invalidTags.value, duplicateTags.value);
};
const onChange = (e) => {
if (props.addOnChange) {
onInput(e);
if (!isDuplicate.value) addTag(inputValue.value);
}
};
const onKeydown = (e) => {
if ((e.key === "Enter" || e.code === "NumpadEnter") && !props.noAddOnEnter) {
addTag(inputValue.value);
return;
}
if ((e.key === "Backspace" || e.key === "Delete") && props.removeOnDelete && inputValue.value === "" && shouldRemoveOnDelete.value && tags.value.length > 0) removeTag(tags.value[tags.value.length - 1]);
else shouldRemoveOnDelete.value = true;
};
onKeyStroke(onKeydown, { target: input });
const separator = computed(() => {
if (!props.separator) return;
return typeof props.separator === "string" ? props.separator : props.separator.join("");
});
const separatorRegExp = computed(() => {
if (!separator.value) return;
return new RegExp(`[${escapeRegExpChars(separator.value)}]+`);
});
const addTag = (tag) => {
tag = (tag ?? inputValue.value).trim();
const newTags = separatorRegExp.value ? tag.split(separatorRegExp.value).map((t) => t.trim()) : [tag];
const validTags = [];
for (const newTag of newTags) {
if (newTag === "" || isDuplicate.value || !props.tagValidator(newTag)) continue;
if (limitNumber.value && isLimitReached.value) break;
validTags.push(newTag);
}
const newValue = [...modelValue.value, ...validTags];
inputValue.value = "";
shouldRemoveOnDelete.value = true;
modelValue.value = newValue;
focused.value = true;
};
const removeTag = (tag) => {
const tagIndex = tags.value.indexOf(tag?.toString() ?? "");
if (tagIndex === -1) return;
lastRemovedTag.value = tags.value.splice(tagIndex, 1).toString();
modelValue.value = tags.value;
};
__expose({
blur: () => {
focused.value = false;
},
element: input,
focus: () => {
focused.value = true;
},
inputValue
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
id: unref(computedId),
class: normalizeClass(["b-form-tags form-control h-auto", computedClasses.value]),
role: "group",
tabindex: "-1",
onClick,
onFocusin,
onFocusout: _cache[1] || (_cache[1] = ($event) => emit("focusout", $event))
}, [
createElementVNode("output", {
id: `${unref(computedId)}selected_tags__`,
class: "visually-hidden",
for: _inputId.value,
"aria-live": unref(focused) ? "polite" : "off",
"aria-atomic": "true",
"aria-relevant": "additions text"
}, toDisplayString(tags.value.join(", ")), 9, _hoisted_2),
createElementVNode("div", {
id: `${unref(computedId)}removed_tags__`,
role: "status",
"aria-live": unref(focused) ? "assertive" : "off",
"aria-atomic": "true",
class: "visually-hidden"
}, " (" + toDisplayString(unref(props).tagRemovedLabel) + ") " + toDisplayString(lastRemovedTag.value), 9, _hoisted_3),
renderSlot(_ctx.$slots, "default", {
addButtonText: unref(props).addButtonText,
addButtonVariant: unref(props).addButtonVariant,
addTag,
disableAddButton: disableAddButton.value,
disabled: unref(props).disabled,
duplicateTagText: unref(props).duplicateTagText,
duplicateTags: duplicateTags.value,
form: unref(props).form,
inputAttrs: {
...unref(props).inputAttrs,
disabled: unref(props).disabled,
form: unref(props).form,
id: _inputId.value,
value: inputValue.value
},
inputClass: unref(props).inputClass,
inputHandlers: {
input: onInput,
keydown: onKeydown,
change: onChange
},
inputId: _inputId.value,
inputType: unref(props).inputType,
invalidTagText: unref(props).invalidTagText,
invalidTags: invalidTags.value,
isDuplicate: isDuplicate.value,
isInvalid: isInvalid.value,
isLimitReached: isLimitReached.value,
limitTagsText: unref(props).limitTagsText,
limit: unref(limitNumber),
noTagRemove: unref(props).noTagRemove,
placeholder: unref(props).placeholder,
removeTag,
required: unref(props).required,
separator: unref(props).separator,
size: unref(props).size,
state: unref(props).state,
tagClass: unref(props).tagClass,
tagPills: unref(props).tagPills,
tagRemoveLabel: unref(props).tagRemoveLabel,
tagVariant: unref(props).tagVariant,
tags: tags.value
}, () => [createElementVNode("ul", {
id: `${unref(computedId)}tag_list__`,
class: "b-form-tags-list list-unstyled mb-0 d-flex flex-wrap align-items-center"
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(tags.value, (tag, index) => {
return renderSlot(_ctx.$slots, "tag", {
key: index,
tag,
tagClass: unref(props).tagClass,
tagVariant: unref(props).tagVariant,
tagPills: unref(props).tagPills,
removeTag
}, () => [(openBlock(), createBlock(BFormTag_default, {
key: tag,
class: normalizeClass(unref(props).tagClass),
tag: "li",
variant: unref(props).tagVariant,
pill: unref(props).tagPills,
"no-remove": unref(props).noTagRemove,
disabled: unref(props).disabled,
onRemove: removeTag
}, {
default: withCtx(() => [createTextVNode(toDisplayString(tag), 1)]),
_: 2
}, 1032, [
"class",
"variant",
"pill",
"no-remove",
"disabled"
]))]);
}), 128)), createElementVNode("li", {
role: "none",
"aria-live": "off",
class: "b-from-tags-field flex-grow-1",
"aria-controls": `${unref(computedId)}tag_list__`
}, [createElementVNode("div", _hoisted_6, [createElementVNode("input", mergeProps({
id: _inputId.value,
ref: "_input",
disabled: unref(props).disabled,
value: inputValue.value,
type: unref(props).inputType,
placeholder: unref(props).placeholder,
class: "b-form-tags-input w-100 flex-grow-1 p-0 m-0 bg-transparent border-0",
style: {
"outline": "currentcolor none 0px",
"min-width": "5rem"
}
}, unref(props).inputAttrs, {
form: unref(props).form,
required: unref(props).required || void 0,
"aria-required": unref(props).required || void 0,
onInput,
onChange,
onFocus,
onBlur
}), null, 16, _hoisted_7), disableAddButton.value ? (openBlock(), createElementBlock("button", {
key: 0,
type: "button",
class: normalizeClass(["btn b-form-tags-button py-0", [__props.inputClass, {
[`btn-${unref(props).addButtonVariant}`]: unref(props).addButtonVariant !== null,
"disabled invisible": inputValue.value.length === 0
}]]),
style: { "font-size": "90%" },
disabled: unref(props).disabled || inputValue.value.length === 0 || isLimitReached.value,
onClick: _cache[0] || (_cache[0] = ($event) => addTag(inputValue.value))
}, [renderSlot(_ctx.$slots, "add-button-text", {}, () => [createTextVNode(toDisplayString(unref(props).addButtonText), 1)])], 10, _hoisted_8)) : createCommentVNode("", true)])], 8, _hoisted_5)], 8, _hoisted_4), createElementVNode("div", {
"aria-live": unref(props).feedbackAriaLive,
"aria-atomic": "true"
}, [
isInvalid.value ? (openBlock(), createElementBlock("div", _hoisted_10, toDisplayString(unref(props).invalidTagText) + ": " + toDisplayString(inputValue.value), 1)) : createCommentVNode("", true),
isDuplicate.value ? (openBlock(), createElementBlock("small", _hoisted_11, toDisplayString(unref(props).duplicateTagText) + ": " + toDisplayString(inputValue.value), 1)) : createCommentVNode("", true),
tags.value.length === unref(props).limit ? (openBlock(), createElementBlock("small", _hoisted_12, toDisplayString(unref(props).limitTagsText), 1)) : createCommentVNode("", true)
], 8, _hoisted_9)]),
unref(props).name ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(tags.value, (tag, index) => {
return openBlock(), createElementBlock("input", {
key: index,
type: "hidden",
name: unref(props).name,
value: tag
}, null, 8, _hoisted_13);
}), 128)) : createCommentVNode("", true)
], 42, _hoisted_1);
};
}
});
//#endregion
export { BFormTag_default as n, BFormTags_default as t };
//# sourceMappingURL=BFormTags-Cobh04P9.mjs.map