bootstrap-vue-next
Version:
BootstrapVueNext is an early and lovely component library for Vue 3 & Nuxt 3 based on Bootstrap 5 and Typescript.
186 lines (185 loc) • 6.34 kB
JavaScript
import { f as useIntersectionObserver, g as useMutationObserver } from "../../../index-Cv338r2J.mjs";
import { toRef, ref, watch, getCurrentInstance, nextTick, onMounted, computed, readonly } from "vue";
import { g as getElement } from "../../../getElement-WfnRgCbF.mjs";
import { s as syncRef } from "../../../index-C4SnlHVo.mjs";
const useScrollspy = (content, target, options = {}) => {
const cont = toRef(content);
const tar = toRef(target);
const resolvedContent = ref(getElement(cont.value));
const resolvedTarget = ref(getElement(tar.value));
watch([cont, tar], () => {
updateList();
});
const {
contentQuery = ":scope > [id]",
targetQuery = "[href]",
manual = false,
root,
rootMargin = "0px 0px -25%",
threshold = [0.1, 0.5, 1],
watchChanges = true
} = options;
const current = ref(null);
const list = ref([]);
const nodeList = ref([]);
const ctx = getCurrentInstance();
if (!ctx) {
nextTick(() => {
updateList();
});
} else {
onMounted(() => {
syncRef(cont, resolvedContent, {
transform: {
ltr: (v) => getElement(v)
},
direction: "ltr",
immediate: true
});
syncRef(tar, resolvedTarget, {
transform: {
ltr: (v) => getElement(v)
},
direction: "ltr",
immediate: true
});
updateList();
});
}
const updateList = () => {
nodeList.value = resolvedContent.value ? Array.from(resolvedContent.value.querySelectorAll(contentQuery)) : [];
list.value = nodeList.value.map((el) => ({
id: el.id,
el,
visible: false,
text: el.textContent
}));
};
let isScrollingDown = true;
let previousScrollTop = 0;
const scrollRoot = computed(
() => resolvedContent.value && getComputedStyle(resolvedContent.value).overflowY === "visible" ? null : resolvedContent.value
);
const iobs = useIntersectionObserver(
nodeList,
(entries) => {
var _a, _b, _c, _d;
const scrollTop = (_a = scrollRoot.value || (document == null ? void 0 : document.documentElement)) == null ? void 0 : _a.scrollTop;
isScrollingDown = scrollTop > previousScrollTop;
previousScrollTop = scrollTop;
entries.forEach((entry) => {
if (entry.isIntersecting) {
list.value.forEach((node) => {
if (node.el === entry.target) {
node.visible = true;
}
});
return;
}
list.value.forEach((node) => {
if (node.el === entry.target) {
node.visible = false;
}
});
});
let newId = null;
if (isScrollingDown) {
newId = ((_b = [...list.value].reverse().find((node) => node.visible)) == null ? void 0 : _b.id) || null;
} else {
newId = ((_c = list.value.find((node) => node.visible)) == null ? void 0 : _c.id) || null;
}
if (newId !== null) {
current.value = newId;
}
if (!current.value) {
current.value = ((_d = list.value[0]) == null ? void 0 : _d.id) || null;
}
},
{
root: root ? getElement(root) : scrollRoot,
rootMargin,
threshold
}
);
watch(current, (newId) => {
var _a;
if (manual) return;
const nodes = (_a = resolvedTarget.value) == null ? void 0 : _a.querySelectorAll(targetQuery);
if (nodes === void 0) return;
let foundParent = false;
let activeElement = null;
nodes.forEach((node) => {
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
const parentDropdown = node.closest(".dropdown");
if ((_a2 = node.getAttribute("href")) == null ? void 0 : _a2.includes(`#${newId}`)) {
activeElement = node;
node.classList.add("active");
if (parentDropdown) {
(_b = parentDropdown == null ? void 0 : parentDropdown.querySelector(".dropdown-toggle")) == null ? void 0 : _b.classList.add("active");
foundParent = true;
}
let parentNav = (_c = node.closest(".nav")) == null ? void 0 : _c.previousSibling;
while ((_d = parentNav == null ? void 0 : parentNav.classList) == null ? void 0 : _d.contains("nav-item")) {
foundParent = true;
(_e = parentNav.querySelector(".nav-link")) == null ? void 0 : _e.classList.add("active");
parentNav = (_f = parentNav.closest(".nav")) == null ? void 0 : _f.previousSibling;
}
} else {
node.classList.remove("active");
if (parentDropdown && !foundParent) {
(_g = parentDropdown == null ? void 0 : parentDropdown.querySelector(".dropdown-toggle")) == null ? void 0 : _g.classList.remove("active");
}
if (!foundParent) {
let parentNav = (_h = node.closest(".nav")) == null ? void 0 : _h.previousSibling;
while ((_i = parentNav == null ? void 0 : parentNav.classList) == null ? void 0 : _i.contains("nav-item")) {
foundParent = true;
if (parentNav.querySelector(".nav-link") !== activeElement) {
(_j = parentNav.querySelector(".nav-link")) == null ? void 0 : _j.classList.remove("active");
}
parentNav = (_k = parentNav.closest(".nav")) == null ? void 0 : _k.previousSibling;
}
}
}
});
});
const mobs = !watchChanges ? { stop: () => {
} } : useMutationObserver(
resolvedContent,
() => {
updateList();
},
{
childList: true
}
);
const scrollIntoView = (event, smooth = false) => {
var _a, _b;
event.preventDefault();
const href = (_b = (_a = event.target) == null ? void 0 : _a.getAttribute) == null ? void 0 : _b.call(_a, "href");
const el = href ? document == null ? void 0 : document.querySelector(href) : null;
if (el && resolvedContent.value) {
if (resolvedContent.value.scrollTo) {
resolvedContent.value.scrollTo({ top: el.offsetTop, behavior: smooth ? "smooth" : "auto" });
} else {
resolvedContent.value.scrollTop = el.offsetTop;
}
}
};
const cleanup = () => {
iobs.stop();
mobs.stop();
};
return {
current: readonly(current),
list,
content: resolvedContent,
target: resolvedTarget,
scrollIntoView,
updateList,
cleanup
};
};
export {
useScrollspy
};
//# sourceMappingURL=index.mjs.map