bootstrap-vue-next
Version:
Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development
501 lines (500 loc) • 18.5 kB
JavaScript
require("./chunk-CoQrYLCe.js");
const require_dist = require("./dist-B_c893QG.js");
const require_useDefaults = require("./useDefaults-DsLf4iRY.js");
const require_useId = require("./useId-DHrBgM7P.js");
const require_useColorVariantClasses = require("./useColorVariantClasses-CEfOwjPv.js");
const require_stringUtils = require("./stringUtils-BwKOASdU.js");
const require_BCloseButton = require("./BCloseButton-CN__Jjcj.js");
const require_useStateClass = require("./useStateClass-0b-hPufa.js");
let vue = require("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__ */ (0, vue.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 = require_useDefaults.useDefaults(__props, "BFormTag");
const emit = __emit;
const slots = (0, vue.useSlots)();
const computedId = require_useId.useId(() => props.id);
const tagText = (0, vue.computed)(() => ((slots.default?.({})[0].children ?? "").toString() || props.title) ?? "");
const taglabelId = (0, vue.computed)(() => `${computedId.value}taglabel__`);
const colorClasses = require_useColorVariantClasses.useColorVariantClasses(props);
const computedClasses = (0, vue.computed)(() => [colorClasses.value, {
"rounded-pill": props.pill,
"disabled": props.disabled
}]);
return (_ctx, _cache) => {
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(props).tag), {
id: (0, vue.unref)(computedId),
title: tagText.value,
class: (0, vue.normalizeClass)(["badge b-form-tag d-inline-flex align-items-center mw-100", computedClasses.value]),
"aria-labelledby": taglabelId.value
}, {
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("span", {
id: taglabelId.value,
class: "b-form-tag-content flex-grow-1 text-truncate"
}, [(0, vue.renderSlot)(_ctx.$slots, "default", {}, () => [(0, vue.createTextVNode)((0, vue.toDisplayString)(tagText.value), 1)])], 8, _hoisted_1$1), !(0, vue.unref)(props).disabled && !(0, vue.unref)(props).noRemove ? ((0, vue.openBlock)(), (0, vue.createBlock)(require_BCloseButton.BCloseButton_default, {
key: 0,
"aria-keyshortcuts": "Delete",
"aria-label": (0, vue.unref)(props).removeLabel,
class: "b-form-tag-remove",
"aria-describedby": taglabelId.value,
"aria-controls": (0, vue.unref)(props).id,
onClick: _cache[0] || (_cache[0] = ($event) => emit("remove", tagText.value))
}, null, 8, [
"aria-label",
"aria-describedby",
"aria-controls"
])) : (0, vue.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__ */ (0, vue.defineComponent)({
__name: "BFormTags",
props: /* @__PURE__ */ (0, vue.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__ */ (0, vue.mergeModels)([
"blur",
"focus",
"focusin",
"focusout",
"tag-state"
], ["update:modelValue"]),
setup(__props, { expose: __expose, emit: __emit }) {
const props = require_useDefaults.useDefaults(__props, "BFormTags");
const emit = __emit;
const modelValue = (0, vue.useModel)(__props, "modelValue");
const computedId = require_useId.useId();
const limitNumber = require_dist.useToNumber(() => props.limit ?? NaN);
const stateClass = require_useStateClass.useStateClass(() => props.state);
const input = (0, vue.useTemplateRef)("_input");
const { focused } = require_dist.useFocus(input, { initialValue: props.autofocus });
const _inputId = (0, vue.computed)(() => props.inputId || `${computedId.value}input__`);
const tags = (0, vue.ref)([...modelValue.value]);
const inputValue = (0, vue.ref)("");
const shouldRemoveOnDelete = (0, vue.ref)(modelValue.value.length > 0);
const lastRemovedTag = (0, vue.ref)("");
const validTags = (0, vue.ref)([]);
const invalidTags = (0, vue.ref)([]);
const duplicateTags = (0, vue.ref)([]);
require_dist.syncRef(modelValue, tags, {
direction: "ltr",
transform: { ltr: (v) => [...v] }
});
const computedClasses = (0, vue.computed)(() => [stateClass.value, {
[`form-control-${props.size}`]: props.size !== "md",
disabled: props.disabled,
focus: focused.value
}]);
const isDuplicate = (0, vue.computed)(() => tags.value.includes(inputValue.value));
const isInvalid = (0, vue.computed)(() => inputValue.value === "" ? false : !props.tagValidator(inputValue.value));
const isLimitReached = (0, vue.computed)(() => tags.value.length === limitNumber.value);
const disableAddButton = (0, vue.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;
};
require_dist.onKeyStroke(onKeydown, { target: input });
const separator = (0, vue.computed)(() => {
if (!props.separator) return;
return typeof props.separator === "string" ? props.separator : props.separator.join("");
});
const separatorRegExp = (0, vue.computed)(() => {
if (!separator.value) return;
return new RegExp(`[${require_stringUtils.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 (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
id: (0, vue.unref)(computedId),
class: (0, vue.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))
}, [
(0, vue.createElementVNode)("output", {
id: `${(0, vue.unref)(computedId)}selected_tags__`,
class: "visually-hidden",
for: _inputId.value,
"aria-live": (0, vue.unref)(focused) ? "polite" : "off",
"aria-atomic": "true",
"aria-relevant": "additions text"
}, (0, vue.toDisplayString)(tags.value.join(", ")), 9, _hoisted_2),
(0, vue.createElementVNode)("div", {
id: `${(0, vue.unref)(computedId)}removed_tags__`,
role: "status",
"aria-live": (0, vue.unref)(focused) ? "assertive" : "off",
"aria-atomic": "true",
class: "visually-hidden"
}, " (" + (0, vue.toDisplayString)((0, vue.unref)(props).tagRemovedLabel) + ") " + (0, vue.toDisplayString)(lastRemovedTag.value), 9, _hoisted_3),
(0, vue.renderSlot)(_ctx.$slots, "default", {
addButtonText: (0, vue.unref)(props).addButtonText,
addButtonVariant: (0, vue.unref)(props).addButtonVariant,
addTag,
disableAddButton: disableAddButton.value,
disabled: (0, vue.unref)(props).disabled,
duplicateTagText: (0, vue.unref)(props).duplicateTagText,
duplicateTags: duplicateTags.value,
form: (0, vue.unref)(props).form,
inputAttrs: {
...(0, vue.unref)(props).inputAttrs,
disabled: (0, vue.unref)(props).disabled,
form: (0, vue.unref)(props).form,
id: _inputId.value,
value: inputValue.value
},
inputClass: (0, vue.unref)(props).inputClass,
inputHandlers: {
input: onInput,
keydown: onKeydown,
change: onChange
},
inputId: _inputId.value,
inputType: (0, vue.unref)(props).inputType,
invalidTagText: (0, vue.unref)(props).invalidTagText,
invalidTags: invalidTags.value,
isDuplicate: isDuplicate.value,
isInvalid: isInvalid.value,
isLimitReached: isLimitReached.value,
limitTagsText: (0, vue.unref)(props).limitTagsText,
limit: (0, vue.unref)(limitNumber),
noTagRemove: (0, vue.unref)(props).noTagRemove,
placeholder: (0, vue.unref)(props).placeholder,
removeTag,
required: (0, vue.unref)(props).required,
separator: (0, vue.unref)(props).separator,
size: (0, vue.unref)(props).size,
state: (0, vue.unref)(props).state,
tagClass: (0, vue.unref)(props).tagClass,
tagPills: (0, vue.unref)(props).tagPills,
tagRemoveLabel: (0, vue.unref)(props).tagRemoveLabel,
tagVariant: (0, vue.unref)(props).tagVariant,
tags: tags.value
}, () => [(0, vue.createElementVNode)("ul", {
id: `${(0, vue.unref)(computedId)}tag_list__`,
class: "b-form-tags-list list-unstyled mb-0 d-flex flex-wrap align-items-center"
}, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(tags.value, (tag, index) => {
return (0, vue.renderSlot)(_ctx.$slots, "tag", {
key: index,
tag,
tagClass: (0, vue.unref)(props).tagClass,
tagVariant: (0, vue.unref)(props).tagVariant,
tagPills: (0, vue.unref)(props).tagPills,
removeTag
}, () => [((0, vue.openBlock)(), (0, vue.createBlock)(BFormTag_default, {
key: tag,
class: (0, vue.normalizeClass)((0, vue.unref)(props).tagClass),
tag: "li",
variant: (0, vue.unref)(props).tagVariant,
pill: (0, vue.unref)(props).tagPills,
"no-remove": (0, vue.unref)(props).noTagRemove,
disabled: (0, vue.unref)(props).disabled,
onRemove: removeTag
}, {
default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)(tag), 1)]),
_: 2
}, 1032, [
"class",
"variant",
"pill",
"no-remove",
"disabled"
]))]);
}), 128)), (0, vue.createElementVNode)("li", {
role: "none",
"aria-live": "off",
class: "b-from-tags-field flex-grow-1",
"aria-controls": `${(0, vue.unref)(computedId)}tag_list__`
}, [(0, vue.createElementVNode)("div", _hoisted_6, [(0, vue.createElementVNode)("input", (0, vue.mergeProps)({
id: _inputId.value,
ref: "_input",
disabled: (0, vue.unref)(props).disabled,
value: inputValue.value,
type: (0, vue.unref)(props).inputType,
placeholder: (0, vue.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"
}
}, (0, vue.unref)(props).inputAttrs, {
form: (0, vue.unref)(props).form,
required: (0, vue.unref)(props).required || void 0,
"aria-required": (0, vue.unref)(props).required || void 0,
onInput,
onChange,
onFocus,
onBlur
}), null, 16, _hoisted_7), disableAddButton.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
key: 0,
type: "button",
class: (0, vue.normalizeClass)(["btn b-form-tags-button py-0", [__props.inputClass, {
[`btn-${(0, vue.unref)(props).addButtonVariant}`]: (0, vue.unref)(props).addButtonVariant !== null,
"disabled invisible": inputValue.value.length === 0
}]]),
style: { "font-size": "90%" },
disabled: (0, vue.unref)(props).disabled || inputValue.value.length === 0 || isLimitReached.value,
onClick: _cache[0] || (_cache[0] = ($event) => addTag(inputValue.value))
}, [(0, vue.renderSlot)(_ctx.$slots, "add-button-text", {}, () => [(0, vue.createTextVNode)((0, vue.toDisplayString)((0, vue.unref)(props).addButtonText), 1)])], 10, _hoisted_8)) : (0, vue.createCommentVNode)("", true)])], 8, _hoisted_5)], 8, _hoisted_4), (0, vue.createElementVNode)("div", {
"aria-live": (0, vue.unref)(props).feedbackAriaLive,
"aria-atomic": "true"
}, [
isInvalid.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_10, (0, vue.toDisplayString)((0, vue.unref)(props).invalidTagText) + ": " + (0, vue.toDisplayString)(inputValue.value), 1)) : (0, vue.createCommentVNode)("", true),
isDuplicate.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("small", _hoisted_11, (0, vue.toDisplayString)((0, vue.unref)(props).duplicateTagText) + ": " + (0, vue.toDisplayString)(inputValue.value), 1)) : (0, vue.createCommentVNode)("", true),
tags.value.length === (0, vue.unref)(props).limit ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("small", _hoisted_12, (0, vue.toDisplayString)((0, vue.unref)(props).limitTagsText), 1)) : (0, vue.createCommentVNode)("", true)
], 8, _hoisted_9)]),
(0, vue.unref)(props).name ? ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, (0, vue.renderList)(tags.value, (tag, index) => {
return (0, vue.openBlock)(), (0, vue.createElementBlock)("input", {
key: index,
type: "hidden",
name: (0, vue.unref)(props).name,
value: tag
}, null, 8, _hoisted_13);
}), 128)) : (0, vue.createCommentVNode)("", true)
], 42, _hoisted_1);
};
}
});
//#endregion
Object.defineProperty(exports, "BFormTag_default", {
enumerable: true,
get: function() {
return BFormTag_default;
}
});
Object.defineProperty(exports, "BFormTags_default", {
enumerable: true,
get: function() {
return BFormTags_default;
}
});
//# sourceMappingURL=BFormTags-BUoQXBA9.js.map