UNPKG

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
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