bootstrap-vue-next
Version:
Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development
579 lines (578 loc) • 22.7 kB
JavaScript
require("./chunk-CoQrYLCe.js");
const require_keys = require("./keys-durSVUrO.js");
const require_dist = require("./dist-BJ15ThEs.js");
const require_dom = require("./dom-Bs6DzM72.js");
const require_useDefaults = require("./useDefaults-DsLf4iRY.js");
const require_useId = require("./useId-DHrBgM7P.js");
const require_flattenFragments = require("./flattenFragments-C1WWqm25.js");
const require_classes = require("./classes-D5wrmmVs.js");
const require_useAlignment = require("./useAlignment-D5xKBRez.js");
let vue = require("vue");
//#endregion
//#region src/components/BTabs/BTab.vue
var BTab_default = /* @__PURE__ */ (0, vue.defineComponent)({
inheritAttrs: false,
__name: "BTab",
props: /* @__PURE__ */ (0, vue.mergeModels)({
buttonId: { default: void 0 },
disabled: {
type: Boolean,
default: false
},
id: { default: void 0 },
lazy: {
type: Boolean,
default: void 0
},
unmountLazy: {
type: Boolean,
default: void 0
},
noBody: {
type: Boolean,
default: false
},
tag: { default: "div" },
title: { default: void 0 },
titleItemClass: { default: void 0 },
titleLinkAttrs: { default: void 0 },
titleLinkClass: { default: void 0 }
}, {
"active": {
type: Boolean,
default: false
},
"activeModifiers": {}
}),
emits: ["update:active"],
setup(__props, { expose: __expose }) {
const props = require_useDefaults.useDefaults(__props, "BTab");
const slots = (0, vue.useSlots)();
const attrs = (0, vue.useAttrs)();
const activeModel = (0, vue.useModel)(__props, "active");
const parentData = (0, vue.inject)(require_keys.tabsInjectionKey, null);
const localId = (0, vue.ref)(props.id);
const internalId = require_useId.useId("", "tabpane");
const computedId = (0, vue.computed)(() => props.id ?? localId.value ?? internalId.value);
const computedButtonId = require_useId.useId(() => props.buttonId, "tab");
const lazyRenderCompleted = (0, vue.ref)(false);
const el = (0, vue.useTemplateRef)("_el");
const processedAttrs = (0, vue.computed)(() => {
const { onClick: _, ...tabAttrs } = attrs;
return tabAttrs;
});
function updateTab() {
if (!parentData) return;
const newId = parentData.registerTab((0, vue.computed)(() => ({
internalId: internalId.value,
id: computedId.value,
active: activeModel.value,
buttonId: computedButtonId.value,
disabled: props.disabled,
title: props.title,
titleComponent: slots.title,
titleItemClass: props.titleItemClass,
titleLinkAttrs: props.titleLinkAttrs,
titleLinkClass: props.titleLinkClass,
onClick: attrs.onClick,
el
})));
if (newId !== localId.value) localId.value = newId;
}
if (parentData) {
updateTab();
if (activeModel.value) parentData.activateTab(internalId.value);
}
(0, vue.onUnmounted)(() => {
if (!parentData) return;
parentData.unregisterTab(internalId.value);
});
const isActive = (0, vue.computed)(() => parentData?.activeId.value === computedId.value);
const show = (0, vue.ref)(isActive.value);
const computedLazy = (0, vue.computed)(() => !!(parentData?.lazy.value || props.lazy));
const computedActive = (0, vue.computed)(() => isActive.value && !props.disabled);
const showSlot = (0, vue.computed)(() => computedActive.value || !computedLazy.value || computedLazy.value && !props.unmountLazy && lazyRenderCompleted.value);
(0, vue.watch)(showSlot, (shown) => {
if (shown && !lazyRenderCompleted.value) lazyRenderCompleted.value = true;
});
(0, vue.watch)(isActive, (active) => {
if (active) {
activeModel.value = true;
setTimeout(() => {
show.value = true;
}, 0);
return;
}
show.value = false;
activeModel.value = false;
});
(0, vue.watch)(activeModel, (active) => {
if (props.disabled) {
activeModel.value = false;
return;
}
if (!parentData) return;
if (!active) {
if (isActive.value) parentData.activateTab(void 0);
return;
}
if (!isActive.value) parentData.activateTab(internalId.value);
});
const computedClasses = (0, vue.computed)(() => [
{
"active": isActive.value,
"show": show.value,
"card-body": parentData?.card.value && props.noBody === false,
"fade": !parentData?.noFade.value
},
show.value ? parentData?.activeTabClass.value : parentData?.inactiveTabClass.value,
parentData?.tabClass.value
]);
__expose({
activate: () => {
activeModel.value = true;
},
deactivate: () => {
activeModel.value = false;
}
});
return (_ctx, _cache) => {
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(props).tag), (0, vue.mergeProps)({
id: computedId.value,
ref: "_el",
class: ["tab-pane", computedClasses.value],
role: "tabpanel",
"aria-labelledby": (0, vue.unref)(computedButtonId)
}, processedAttrs.value), {
default: (0, vue.withCtx)(() => [showSlot.value ? (0, vue.renderSlot)(_ctx.$slots, "default", { key: 0 }) : (0, vue.createCommentVNode)("", true)]),
_: 3
}, 16, [
"id",
"class",
"aria-labelledby"
]);
};
}
});
//#endregion
//#region src/components/BTabs/BTabs.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = ["aria-orientation"];
var _hoisted_2 = [
"id",
"aria-controls",
"aria-selected",
"disabled",
"tabindex",
"onClick"
];
//#endregion
//#region src/components/BTabs/BTabs.vue
var BTabs_default = /* @__PURE__ */ (0, vue.defineComponent)({
__name: "BTabs",
props: /* @__PURE__ */ (0, vue.mergeModels)({
activeNavItemClass: { default: void 0 },
activeTabClass: { default: void 0 },
align: { default: void 0 },
card: {
type: Boolean,
default: false
},
contentClass: { default: void 0 },
end: {
type: Boolean,
default: false
},
fill: {
type: Boolean,
default: false
},
id: { default: void 0 },
index: {},
inactiveNavItemClass: { default: void 0 },
inactiveTabClass: { default: void 0 },
justified: {
type: Boolean,
default: false
},
lazy: {
type: Boolean,
default: false
},
navClass: { default: void 0 },
navItemClass: { default: void 0 },
navWrapperClass: { default: void 0 },
noFade: {
type: Boolean,
default: false
},
noKeyNav: {
type: Boolean,
default: false
},
noNavStyle: {
type: Boolean,
default: false
},
pills: {
type: Boolean,
default: false
},
small: {
type: Boolean,
default: false
},
tag: { default: "div" },
tabClass: { default: void 0 },
underline: {
type: Boolean,
default: false
},
vertical: {
type: Boolean,
default: false
}
}, {
"index": { default: -1 },
"indexModifiers": {},
"modelValue": { default: void 0 },
"modelModifiers": {}
}),
emits: /* @__PURE__ */ (0, vue.mergeModels)(["activate-tab"], ["update:index", "update:modelValue"]),
setup(__props, { emit: __emit }) {
const props = require_useDefaults.useDefaults(__props, "BTabs");
const emit = __emit;
const slots = (0, vue.useSlots)();
const activeIndex = (0, vue.useModel)(__props, "index");
const activeId = (0, vue.useModel)(__props, "modelValue");
const ReusableEmptyTab = require_dist.createReusableTemplate();
const tabsInternal = (0, vue.ref)([]);
const tabElementsArray = (0, vue.ref)([]);
const isChildActive = (0, vue.ref)(false);
const initialIds = (0, vue.ref)([]);
const hasExplicitIds = (0, vue.ref)(false);
const updateTabElementsArray = () => {
const tabElements = require_flattenFragments.flattenFragments(slots.default?.({}) ?? []);
tabElementsArray.value = (Array.isArray(tabElements) ? tabElements : [tabElements]).filter((tab) => tab.type === BTab_default);
if (initialIds.value.length === 0) {
initialIds.value = tabElementsArray.value.map((tab) => (0, vue.unref)(require_useId.useId(() => tab.props?.id, "tabpane")));
hasExplicitIds.value = tabElementsArray.value.some((tab) => tab.props?.id !== void 0);
}
isChildActive.value = tabElementsArray.value.some((tab) => tab.props?.active !== void 0 && tab.props?.active !== false);
};
updateTabElementsArray();
(0, vue.watch)(() => slots.default?.({}), () => {
updateTabElementsArray();
(0, vue.nextTick)(() => {
sortTabs();
});
});
const tabs = (0, vue.computed)(() => {
if (tabsInternal.value.length === 0) {
const _activeIndex = tabElementsArray.value.findIndex((tab) => tab.props?.active !== void 0 && (tab.props.disabled === false || tab.props.disabled === void 0) || activeId.value && tab.props?.id === activeId.value);
return tabElementsArray.value.map((tab, index) => {
const active = _activeIndex !== -1 ? index === _activeIndex : activeIndex.value > -1 ? index === activeIndex.value : index === 0;
return {
id: tab.props?.id ?? initialIds.value[index],
internalId: `premount-${index}`,
buttonId: tab.props?.buttonId,
disabled: tab.props?.disabled,
title: tab.props?.title,
titleComponent: tab.children?.title,
titleItemClass: tab.props?.titleItemClass,
titleLinkAttrs: tab.props?.titleLinkAttrs,
titleLinkClass: tab.props?.titleLinkClass,
onClick: tab.props?.onClick,
active,
navItemClasses: [
{
active,
disabled: !(tab.props?.disabled === false || tab.props?.disabled === void 0)
},
active ? props.activeNavItemClass : props.inactiveNavItemClass,
props.navItemClass
]
};
});
}
return tabsInternal.value.map((_tab) => {
const tab = (0, vue.unref)(_tab);
const active = tab.id === activeId.value;
return {
...tab,
active,
navItemClasses: [
{
active,
disabled: tab.disabled
},
active ? props.activeNavItemClass : props.inactiveNavItemClass,
props.navItemClass
]
};
});
});
let initialized = false;
let updateInitialActiveIndex = false;
let updateInitialActiveId = false;
let delayedTabSelection = false;
if (activeIndex.value > -1 && !activeId.value && !hasExplicitIds.value && tabElementsArray.value.length > 0) {
delayedTabSelection = true;
updateInitialActiveId = true;
} else if (activeIndex.value === -1 && activeId.value) if (tabs.value.findIndex((t) => t.id === activeId.value) !== -1) activeIndex.value = tabs.value.findIndex((t) => t.id === activeId.value);
else updateInitialActiveIndex = true;
else if (activeIndex.value > -1 && !activeId.value) if (tabs.value[activeIndex.value]?.id) activeId.value = tabs.value[activeIndex.value]?.id;
else updateInitialActiveId = true;
else if (activeIndex.value === -1 && !activeId.value && !isChildActive.value) {
activeIndex.value = tabs.value.findIndex((t) => t.disabled === void 0 || t.disabled === false);
activeId.value = tabs.value[activeIndex.value]?.id;
} else if (activeIndex.value === -1 && !activeId.value && isChildActive.value) {
activeIndex.value = tabs.value.findIndex((t) => t.active !== void 0 && t.active !== false && (t.disabled === void 0 || t.disabled === false));
activeId.value = tabs.value[activeIndex.value]?.id;
}
function updateInitialIndexAndId() {
if (updateInitialActiveIndex) {
const index = tabs.value.findIndex((t) => t.id === activeId.value);
if (index !== -1) (0, vue.nextTick)(() => {
activeIndex.value = index;
updateInitialActiveIndex = false;
});
}
if (updateInitialActiveId) {
if (delayedTabSelection && tabsInternal.value.length === 0) return;
if (activeIndex.value > -1 && tabs.value[activeIndex.value]?.id) (0, vue.nextTick)(() => {
activeId.value = tabs.value[activeIndex.value]?.id;
updateInitialActiveId = false;
delayedTabSelection = false;
});
}
}
updateInitialIndexAndId();
const showEmpty = (0, vue.computed)(() => !(tabs?.value && tabs.value.length > 0));
const computedClasses = (0, vue.computed)(() => ({
"d-flex": props.vertical,
"align-items-start": props.vertical
}));
const alignment = require_useAlignment.useAlignment(() => props.align);
const navTabsClasses = (0, vue.computed)(() => ({
"nav-pills": props.pills,
"nav-underline": props.underline,
"flex-column me-3": props.vertical,
[alignment.value]: props.align !== void 0,
"nav-fill": props.fill,
"card-header-tabs": props.card && !props.pills && !props.underline,
"card-header-pills": props.card && props.pills,
"nav-justified": props.justified,
"nav-tabs": !props.noNavStyle && !props.pills && !props.underline,
"small": props.small
}));
const handleClick = (event, index) => {
if (index >= 0 && !tabs.value[index]?.disabled && tabs.value[index]?.onClick && typeof tabs.value[index].onClick === "function") {
tabs.value[index].onClick?.(event);
if (event.defaultPrevented) {
require_dom.getSafeDocument()?.getElementById(tabs.value[index].buttonId)?.blur();
return;
}
}
activeIndex.value = index;
};
const keynav = (e, direction) => {
if (tabs.value.length <= 0 || props.noKeyNav) return;
e.preventDefault();
e.stopPropagation();
activeIndex.value = nextIndex(activeIndex.value + direction, direction);
(0, vue.nextTick)(() => {
if (activeIndex.value >= 0) require_dom.getSafeDocument()?.getElementById(tabs.value[activeIndex.value]?.buttonId)?.focus();
});
};
const nextIndex = (start, direction) => {
let index = start;
let minIdx = -1;
let maxIdx = -1;
for (let i = 0; i < tabs.value.length; i++) if (!tabs.value[i]?.disabled) {
if (minIdx === -1) minIdx = i;
maxIdx = i;
}
while (index >= minIdx && index <= maxIdx && tabs.value[index]?.disabled) index += direction;
if (index < minIdx) index = minIdx;
if (index > maxIdx) index = maxIdx;
return index;
};
let previousIndex;
let isReverting = false;
(0, vue.watch)(activeIndex, (newValue, oldValue) => {
if (tabs.value.length <= 0 || tabs.value.filter((t) => !t.disabled).length <= 0) return;
if (isReverting) {
isReverting = false;
return;
}
const index = nextIndex(newValue, newValue > oldValue ? 1 : -1);
if (index !== newValue) {
previousIndex = oldValue;
activeIndex.value = index;
return;
}
const tabEvent = new require_classes.BvEvent("activate-tab", { cancelable: true });
emit("activate-tab", {
newTabId: tabs.value[index]?.id,
prevTabId: tabs.value[previousIndex ?? oldValue]?.id,
newTabIndex: index,
prevTabIndex: previousIndex ?? oldValue,
event: tabEvent
});
if (tabEvent.defaultPrevented) {
isReverting = true;
const prev = previousIndex ?? oldValue ?? nextIndex(0, 1);
previousIndex = void 0;
if (activeId.value !== tabs.value[prev]?.id) activeId.value = tabs.value[prev]?.id;
(0, vue.nextTick)(() => {
if (prev >= 0) require_dom.getSafeDocument()?.getElementById(tabs.value[prev]?.buttonId)?.focus();
});
return;
}
if (activeId.value !== tabs.value[index]?.id) activeId.value = tabs.value[index]?.id;
previousIndex = void 0;
});
(0, vue.watch)(activeId, (newValue, oldValue) => {
if (tabs.value.length <= 0 || tabs.value.filter((t) => !t.disabled).length <= 0) return;
const index = tabs.value.findIndex((t) => t.id === newValue);
if (index === activeIndex.value) return;
const oldIndex = tabs.value.findIndex((t) => t.id === oldValue);
if (tabs.value[index]?.disabled) {
activeIndex.value = nextIndex(index, index > oldIndex ? 1 : -1);
return;
}
if (index === -1) {
activeIndex.value = nextIndex(0, 1);
(0, vue.nextTick)(() => {
activeId.value = tabs.value[activeIndex.value]?.id;
});
return;
}
activeIndex.value = index;
});
const registerTab = (tab) => {
const idx = tabsInternal.value.findIndex((t) => t.value.internalId === tab.value.internalId);
if (idx === -1) {
tabsInternal.value.push(tab);
if (initialized) (0, vue.nextTick)(() => {
sortTabs();
});
else if (delayedTabSelection) (0, vue.nextTick)(() => {
updateInitialIndexAndId();
});
} else {
tabsInternal.value[idx] = tab;
if (initialized) sortTabs();
}
const idx2 = tabsInternal.value.findIndex((t) => t.value.internalId === tab.value.internalId);
return tab.value.id ?? (!initialized ? initialIds.value[idx2] : tab.value.internalId);
};
(0, vue.onMounted)(() => {
updateInitialIndexAndId();
sortTabs();
initialized = true;
});
const sortTabs = () => {
tabsInternal.value.sort((a, b) => require_dom.sortSlotElementsByPosition(a.value.el.value, b.value.el.value));
if (activeId.value && activeIndex.value !== tabs.value.findIndex((t) => t.id === activeId.value)) activeIndex.value = tabs.value.findIndex((t) => t.id === activeId.value);
};
const unregisterTab = (id) => {
tabsInternal.value = tabsInternal.value.filter((t) => t.value.internalId !== id);
};
(0, vue.provide)(require_keys.tabsInjectionKey, {
lazy: (0, vue.toRef)(() => props.lazy),
card: (0, vue.toRef)(() => props.card),
noFade: (0, vue.toRef)(() => props.noFade),
activeTabClass: (0, vue.toRef)(() => props.activeTabClass),
inactiveTabClass: (0, vue.toRef)(() => props.inactiveTabClass),
tabClass: (0, vue.toRef)(() => props.tabClass),
registerTab,
unregisterTab,
activeId,
activateTab: (internalId) => {
const idx = tabs.value.findIndex((t) => t.internalId === internalId);
if (internalId === void 0 || idx === -1) {
activeIndex.value = nextIndex(0, 1);
return;
}
activeIndex.value = idx;
}
});
return (_ctx, _cache) => {
return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(props).tag), {
id: (0, vue.unref)(props).id,
class: (0, vue.normalizeClass)(["tabs", computedClasses.value])
}, {
default: (0, vue.withCtx)(() => [
(0, vue.createVNode)((0, vue.unref)(ReusableEmptyTab).define, null, {
default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)(["tab-content", (0, vue.unref)(props).contentClass]) }, [(0, vue.renderSlot)(_ctx.$slots, "default"), showEmpty.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
key: "bv-empty-tab",
class: (0, vue.normalizeClass)(["tab-pane active", { "card-body": (0, vue.unref)(props).card }])
}, [(0, vue.renderSlot)(_ctx.$slots, "empty")], 2)) : (0, vue.createCommentVNode)("", true)], 2)]),
_: 3
}),
(0, vue.unref)(props).end ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(ReusableEmptyTab).reuse, { key: 0 })) : (0, vue.createCommentVNode)("", true),
(0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)([(0, vue.unref)(props).navWrapperClass, {
"card-header": (0, vue.unref)(props).card,
"ms-auto": __props.vertical && (0, vue.unref)(props).end
}]) }, [(0, vue.createElementVNode)("ul", {
class: (0, vue.normalizeClass)(["nav", [navTabsClasses.value, (0, vue.unref)(props).navClass]]),
role: "tablist",
"aria-orientation": (0, vue.unref)(props).vertical ? "vertical" : "horizontal"
}, [
(0, vue.renderSlot)(_ctx.$slots, "tabs-start"),
((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(tabs.value, (tab, idx) => {
return (0, vue.openBlock)(), (0, vue.createElementBlock)("li", {
key: tab.id ?? tab.internalId,
class: (0, vue.normalizeClass)(["nav-item", tab.titleItemClass]),
role: "presentation"
}, [(0, vue.createElementVNode)("button", (0, vue.mergeProps)({
id: tab.buttonId,
class: ["nav-link", [tab.navItemClasses, tab.titleLinkClass]],
role: "tab",
"aria-controls": tab.id,
"aria-selected": tab.active,
disabled: tab.disabled,
tabindex: (0, vue.unref)(props).noKeyNav ? void 0 : tab.active ? void 0 : -1,
type: "button"
}, { ref_for: true }, tab.titleLinkAttrs, {
onKeydown: [
_cache[0] || (_cache[0] = (0, vue.withKeys)((0, vue.withModifiers)(($event) => !(0, vue.unref)(props).vertical && keynav($event, -1), ["exact"]), ["left"])),
_cache[1] || (_cache[1] = (0, vue.withKeys)((0, vue.withModifiers)(($event) => !(0, vue.unref)(props).vertical && keynav($event, -999), ["shift"]), ["left"])),
_cache[2] || (_cache[2] = (0, vue.withKeys)((0, vue.withModifiers)(($event) => (0, vue.unref)(props).vertical && keynav($event, -1), ["exact"]), ["up"])),
_cache[3] || (_cache[3] = (0, vue.withKeys)((0, vue.withModifiers)(($event) => (0, vue.unref)(props).vertical && keynav($event, -999), ["shift"]), ["up"])),
_cache[4] || (_cache[4] = (0, vue.withKeys)((0, vue.withModifiers)(($event) => !(0, vue.unref)(props).vertical && keynav($event, 1), ["exact"]), ["right"])),
_cache[5] || (_cache[5] = (0, vue.withKeys)((0, vue.withModifiers)(($event) => !(0, vue.unref)(props).vertical && keynav($event, 999), ["shift"]), ["right"])),
_cache[6] || (_cache[6] = (0, vue.withKeys)((0, vue.withModifiers)(($event) => (0, vue.unref)(props).vertical && keynav($event, 1), ["exact"]), ["down"])),
_cache[7] || (_cache[7] = (0, vue.withKeys)((0, vue.withModifiers)(($event) => (0, vue.unref)(props).vertical && keynav($event, 999), ["shift"]), ["down"])),
_cache[8] || (_cache[8] = (0, vue.withKeys)(($event) => keynav($event, -999), ["page-up"])),
_cache[9] || (_cache[9] = (0, vue.withKeys)(($event) => keynav($event, 999), ["page-down"])),
_cache[10] || (_cache[10] = (0, vue.withKeys)(($event) => keynav($event, -999), ["home"])),
_cache[11] || (_cache[11] = (0, vue.withKeys)(($event) => keynav($event, 999), ["end"]))
],
onClick: (0, vue.withModifiers)((e) => handleClick(e, idx), ["stop"])
}), [tab.titleComponent ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tab.titleComponent), { key: 0 })) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [(0, vue.createTextVNode)((0, vue.toDisplayString)(tab.title), 1)], 64))], 16, _hoisted_2)], 2);
}), 128)),
(0, vue.renderSlot)(_ctx.$slots, "tabs-end")
], 10, _hoisted_1)], 2),
!(0, vue.unref)(props).end ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(ReusableEmptyTab).reuse, { key: 1 })) : (0, vue.createCommentVNode)("", true)
]),
_: 3
}, 8, ["id", "class"]);
};
}
});
//#endregion
Object.defineProperty(exports, "BTab_default", {
enumerable: true,
get: function() {
return BTab_default;
}
});
Object.defineProperty(exports, "BTabs_default", {
enumerable: true,
get: function() {
return BTabs_default;
}
});
//# sourceMappingURL=BTabs-DiYaJi22.js.map