bootstrap-vue-next
Version:
Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development
398 lines (397 loc) • 13.6 kB
JavaScript
import { a as buttonGroupKey, p as inputGroupKey, u as dropdownInjectionKey } from "./keys-CQKrwmvN.mjs";
import { a as onClickOutside, o as onKeyStroke, z as useToNumber } from "./dist-B10a-gZ8.mjs";
import { i as getSafeDocument } from "./dom-AhkaSoh8.mjs";
import { t as useDefaults } from "./useDefaults-BKgBaqOV.mjs";
import { t as useId$1 } from "./useId-BKZFSYm8.mjs";
import { t as useShowHide } from "./useShowHide-yAK5dhPT.mjs";
import { t as BButton_default } from "./BButton-BRvIFnRm.mjs";
import { t as ConditionalTeleport_default } from "./ConditionalTeleport-BNsziElf.mjs";
import { a as flip, d as size, i as autoUpdate, l as offset, n as useFloating, u as shift } from "./floating-ui.vue-CAMaNcqI.mjs";
import { t as ConditionalWrapper_default } from "./ConditionalWrapper-D9ovtbHB.mjs";
import { a as resolveBootstrapCaret, n as isBoundary, r as isRootBoundary } from "./floatingUi-DHMrP__c.mjs";
import { t as getElement } from "./getElement-0_htvrFw.mjs";
import { Transition, computed, createBlock, createCommentVNode, createElementVNode, createTextVNode, createVNode, defineComponent, inject, mergeModels, mergeProps, nextTick, normalizeClass, normalizeStyle, openBlock, provide, readonly, ref, renderSlot, toDisplayString, toRef, unref, useModel, useTemplateRef, vShow, watch, withCtx, withDirectives } from "vue";
//#region src/components/BDropdown/BDropdown.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = { class: "visually-hidden" };
var _hoisted_2 = [
"id",
"aria-labelledby",
"role"
];
//#endregion
//#region src/components/BDropdown/BDropdown.vue
var BDropdown_default = /* @__PURE__ */ defineComponent({
__name: "BDropdown",
props: /* @__PURE__ */ mergeModels({
ariaLabel: { default: void 0 },
autoClose: {
type: [Boolean, String],
default: true
},
boundary: { default: "clippingAncestors" },
boundaryPadding: { default: void 0 },
disabled: {
type: Boolean,
default: false
},
floatingMiddleware: { default: void 0 },
icon: {
type: Boolean,
default: false
},
id: { default: void 0 },
isNav: {
type: Boolean,
default: false
},
menuClass: { default: void 0 },
noCaret: {
type: Boolean,
default: false
},
noFlip: {
type: Boolean,
default: false
},
noShift: {
type: Boolean,
default: false
},
noSize: {
type: Boolean,
default: false
},
offset: { default: 0 },
role: { default: "menu" },
size: { default: "md" },
noWrapper: {
type: Boolean,
default: false
},
split: {
type: Boolean,
default: false
},
splitButtonType: { default: "button" },
splitClass: { default: void 0 },
splitDisabled: {
type: Boolean,
default: void 0
},
splitHref: { default: void 0 },
splitTo: { default: void 0 },
splitVariant: { default: void 0 },
strategy: { default: "absolute" },
text: { default: void 0 },
toggleClass: { default: void 0 },
toggleText: { default: "Toggle dropdown" },
variant: { default: "secondary" },
wrapperClass: { default: void 0 },
placement: { default: "bottom-start" },
teleportDisabled: {
type: Boolean,
default: false
},
teleportTo: { default: void 0 },
initialAnimation: {
type: Boolean,
default: false
},
noAnimation: { type: Boolean },
noFade: {
type: Boolean,
default: false
},
lazy: {
type: Boolean,
default: false
},
unmountLazy: {
type: Boolean,
default: false
},
show: {
type: Boolean,
default: false
},
transProps: { default: void 0 },
visible: {
type: Boolean,
default: false
}
}, {
"modelValue": {
type: Boolean,
default: false
},
"modelModifiers": {}
}),
emits: /* @__PURE__ */ mergeModels([
"split-click",
"hide",
"hide-prevented",
"hidden",
"show",
"show-prevented",
"shown",
"toggle",
"toggle-prevented"
], ["update:modelValue"]),
setup(__props, { expose: __expose, emit: __emit }) {
const props = useDefaults(__props, "BDropdown");
const emit = __emit;
const computedId = useId$1(() => props.id, "dropdown");
const modelValue = useModel(__props, "modelValue");
const inInputGroup = inject(inputGroupKey, false);
const inButtonGroup = inject(buttonGroupKey, false);
const offsetToNumber = useToNumber(computed(() => typeof props.offset === "string" || typeof props.offset === "number" ? props.offset : NaN));
const floatingElement = useTemplateRef("_floating");
const button = useTemplateRef("_button");
const splitButton = useTemplateRef("_splitButton");
const boundary = computed(() => isBoundary(props.boundary) ? props.boundary : void 0);
const rootBoundary = computed(() => isRootBoundary(props.boundary) ? props.boundary : void 0);
const referenceElement = computed(() => !props.split ? splitButton.value : button.value);
let cleanup;
const { showRef, renderRef, hide, show, toggle, computedNoAnimation, transitionProps, contentShowing, isVisible, isActive } = useShowHide(modelValue, props, emit, referenceElement, computedId, {
showFn: () => {
update();
nextTick(() => {
cleanup = autoUpdate(referenceElement.value, floatingElement.value, update, { animationFrame: false });
});
},
hideFn: () => {
if (cleanup) {
cleanup();
cleanup = void 0;
}
}
});
const computedMenuClasses = computed(() => [{
show: isVisible.value,
fade: !computedNoAnimation.value
}]);
onKeyStroke("Escape", () => {
hide();
getElement(referenceElement.value)?.focus();
}, { target: referenceElement });
onKeyStroke("Escape", () => {
hide();
getElement(referenceElement.value)?.focus();
}, {
target: floatingElement,
passive: true
});
const keynav = (e, v) => {
if (floatingElement.value?.contains(e.target?.closest("form"))) return;
if (/input|select|option|textarea|form/i.test(e.target?.tagName)) return;
e.preventDefault();
if (!showRef.value) {
show();
const loop = setInterval(() => {
if (isVisible.value) {
clearInterval(loop);
nextTick(() => keynav(e, v));
}
}, 16);
return;
}
const list = floatingElement.value?.querySelectorAll(".dropdown-item:not(.disabled):not(:disabled)");
const doc = getSafeDocument();
if (!list || !doc) return;
if (floatingElement.value?.contains(doc.activeElement)) {
const active = floatingElement.value.querySelector(".dropdown-item:focus");
const index = Array.prototype.indexOf.call(list, active) + v;
if (index >= 0 && index < list?.length) list[index]?.focus();
} else list[v === -1 ? list.length - 1 : 0]?.focus();
};
onKeyStroke("ArrowUp", (e) => keynav(e, -1), { target: referenceElement });
onKeyStroke("ArrowDown", (e) => keynav(e, 1), { target: referenceElement });
onKeyStroke("ArrowUp", (e) => keynav(e, -1), { target: floatingElement });
onKeyStroke("ArrowDown", (e) => keynav(e, 1), { target: floatingElement });
const sizeStyles = ref({});
const { update, floatingStyles } = useFloating(referenceElement, floatingElement, {
placement: () => props.placement,
middleware: computed(() => {
if (props.floatingMiddleware !== void 0) return props.floatingMiddleware;
const arr = [offset(typeof props.offset === "string" || typeof props.offset === "number" ? offsetToNumber.value : props.offset)];
if (props.noFlip === false) arr.push(flip({
boundary: boundary.value,
rootBoundary: rootBoundary.value,
padding: props.boundaryPadding
}));
if (props.noShift === false) arr.push(shift({
boundary: boundary.value,
rootBoundary: rootBoundary.value,
padding: props.boundaryPadding
}));
if (props.noSize === false) arr.push(size({
boundary: boundary.value,
rootBoundary: rootBoundary.value,
padding: props.boundaryPadding,
apply({ availableWidth, availableHeight }) {
sizeStyles.value = {
"--bv-floating-max-height": availableHeight >= (floatingElement.value?.scrollHeight ?? 0) ? void 0 : availableHeight ? `${Math.max(0, availableHeight)}px` : void 0,
"--bv-floating-max-width": availableWidth >= (floatingElement.value?.scrollWidth ?? 0) ? void 0 : availableWidth ? `${Math.max(0, availableWidth)}px` : void 0
};
}
}));
return arr;
}),
strategy: toRef(() => props.strategy)
});
const inButtonGroupAttributes = inButtonGroup ? {
class: "btn-group",
role: "group"
} : void 0;
const computedClasses = computed(() => [
inButtonGroupAttributes?.class,
props.wrapperClass,
{
"btn-group": !props.wrapperClass && props.split,
[`drop${resolveBootstrapCaret(props.placement)}`]: !props.wrapperClass,
"position-static": props.boundary !== "clippingAncestors" && !props.isNav
}
]);
const buttonClasses = computed(() => [props.split ? props.splitClass : props.toggleClass, {
"nav-link": props.isNav,
"dropdown-toggle": !props.split,
"dropdown-toggle-no-caret": props.noCaret && !props.split,
"show": props.split ? void 0 : showRef.value
}]);
const onButtonClick = () => {
toggle();
};
const onSplitClick = (event) => {
if (props.split) {
emit("split-click", event);
return;
}
onButtonClick();
};
onClickOutside(floatingElement, () => {
if (showRef.value && (props.autoClose === true || props.autoClose === "outside")) hide();
}, { ignore: [button, splitButton] });
const onClickInside = () => {
if (showRef.value && (props.autoClose === true || props.autoClose === "inside")) hide();
};
watch(isVisible, () => {
update();
});
__expose({
hide,
show,
toggle
});
provide(dropdownInjectionKey, {
id: computedId,
show,
hide,
toggle,
visible: readonly(showRef),
isNav: toRef(() => props.isNav)
});
return (_ctx, _cache) => {
return openBlock(), createBlock(ConditionalWrapper_default, {
skip: unref(inInputGroup) || unref(props).noWrapper,
class: normalizeClass(computedClasses.value),
role: unref(inButtonGroupAttributes)?.role
}, {
default: withCtx(() => [
createVNode(BButton_default, {
id: unref(computedId),
ref: "_splitButton",
variant: unref(props).splitVariant || unref(props).variant,
size: unref(props).size,
class: normalizeClass(buttonClasses.value),
disabled: unref(props).splitDisabled || unref(props).disabled,
type: unref(props).splitButtonType,
"aria-label": unref(props).ariaLabel,
"aria-expanded": unref(props).split ? void 0 : unref(showRef),
"aria-haspopup": unref(props).split ? void 0 : "menu",
href: unref(props).split ? unref(props).splitHref : void 0,
icon: unref(props).icon,
to: unref(props).split && unref(props).splitTo ? unref(props).splitTo : void 0,
onClick: onSplitClick
}, {
default: withCtx(() => [renderSlot(_ctx.$slots, "button-content", {}, () => [createTextVNode(toDisplayString(unref(props).text), 1)])]),
_: 3
}, 8, [
"id",
"variant",
"size",
"class",
"disabled",
"type",
"aria-label",
"aria-expanded",
"aria-haspopup",
"href",
"icon",
"to"
]),
unref(props).split ? (openBlock(), createBlock(BButton_default, {
key: 0,
id: unref(computedId) + "-split",
ref: "_button",
variant: unref(props).variant,
size: unref(props).size,
disabled: unref(props).disabled,
class: normalizeClass([[unref(props).toggleClass, { show: unref(showRef) }], "dropdown-toggle-split dropdown-toggle"]),
"aria-expanded": unref(showRef),
"aria-haspopup": "menu",
onClick: onButtonClick
}, {
default: withCtx(() => [createElementVNode("span", _hoisted_1, [renderSlot(_ctx.$slots, "toggle-text", {}, () => [createTextVNode(toDisplayString(unref(props).toggleText), 1)])])]),
_: 3
}, 8, [
"id",
"variant",
"size",
"disabled",
"class",
"aria-expanded"
])) : createCommentVNode("", true),
createVNode(ConditionalTeleport_default, {
to: unref(props).teleportTo,
disabled: !unref(props).teleportTo || unref(props).teleportDisabled
}, {
default: withCtx(() => [unref(renderRef) || unref(contentShowing) ? (openBlock(), createBlock(Transition, mergeProps({ key: 0 }, unref(transitionProps), { appear: modelValue.value || unref(props).visible }), {
default: withCtx(() => [withDirectives(createElementVNode("ul", {
id: unref(computedId) + "-menu",
ref: "_floating",
style: normalizeStyle([
unref(floatingStyles),
sizeStyles.value,
{ display: unref(showRef) || unref(isActive) ? "block" : "none" }
]),
class: normalizeClass(["dropdown-menu overflow-auto b-floating-size", [unref(props).menuClass, computedMenuClasses.value]]),
"aria-labelledby": unref(computedId),
role: unref(props).role,
onClick: onClickInside
}, [unref(contentShowing) ? renderSlot(_ctx.$slots, "default", {
key: 0,
id: unref(computedId),
hide: unref(hide),
show: unref(show),
visible: unref(showRef),
click: onClickInside,
toggle: onButtonClick,
active: unref(showRef)
}) : createCommentVNode("", true)], 14, _hoisted_2), [[vShow, unref(showRef)]])]),
_: 3
}, 16, ["appear"])) : createCommentVNode("", true)]),
_: 3
}, 8, ["to", "disabled"])
]),
_: 3
}, 8, [
"skip",
"class",
"role"
]);
};
}
});
//#endregion
export { BDropdown_default as t };
//# sourceMappingURL=BDropdown-DAHnN54Z.mjs.map