bootstrap-vue-next
Version:
BootstrapVueNext is an early and lovely component library for Vue 3 & Nuxt 3 based on Bootstrap 5 and Typescript.
1 lines • 10.8 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../../../../src/composables/useScrollspy/index.ts"],"sourcesContent":["import {syncRef, useIntersectionObserver, useMutationObserver} from '@vueuse/core'\nimport {\n type ComponentPublicInstance,\n computed,\n getCurrentInstance,\n type MaybeRefOrGetter,\n nextTick,\n onMounted,\n readonly,\n type Ref,\n ref,\n toRef,\n watch,\n} from 'vue'\nimport {getElement} from '../../utils/getElement'\n\ntype ScrollspyList = {\n id: string | null\n el: HTMLElement | null\n visible: boolean\n text: string | null\n}[]\n\ninterface ScrollspyReturn {\n current: Readonly<Ref<string | null>>\n list: Readonly<Ref<ScrollspyList>>\n content: Ref<HTMLElement | undefined>\n target: Ref<HTMLElement | undefined>\n scrollIntoView: (event: MouseEvent) => void\n updateList: () => void\n cleanup: () => void\n}\n\ninterface ScrollspyOptions {\n contentQuery: string\n targetQuery: string\n manual: boolean\n root: string | ComponentPublicInstance | HTMLElement | null\n rootMargin: string\n threshold: number | number[]\n watchChanges: boolean\n}\n\nexport const useScrollspy = (\n content: MaybeRefOrGetter<string | ComponentPublicInstance | HTMLElement | null>,\n target: MaybeRefOrGetter<string | ComponentPublicInstance | HTMLElement | null>,\n options: Readonly<Partial<ScrollspyOptions>> = {}\n): ScrollspyReturn => {\n const cont = toRef(content)\n const tar = toRef(target)\n\n const resolvedContent = ref(getElement(cont.value))\n const resolvedTarget = ref(getElement(tar.value))\n\n watch([cont, tar], () => {\n updateList()\n })\n const {\n contentQuery = ':scope > [id]',\n targetQuery = '[href]',\n manual = false,\n root,\n rootMargin = '0px 0px -25%',\n threshold = [0.1, 0.5, 1],\n watchChanges = true,\n } = options\n const current = ref<string | null>(null)\n const list = ref<ScrollspyList>([])\n const nodeList = ref<HTMLElement[]>([])\n\n // are we called in directive?\n const ctx = getCurrentInstance()\n if (!ctx) {\n nextTick(() => {\n updateList()\n })\n } else {\n onMounted(() => {\n syncRef(cont, resolvedContent, {\n transform: {\n ltr: (v) => getElement(v),\n },\n direction: 'ltr',\n immediate: true,\n })\n syncRef(tar, resolvedTarget, {\n transform: {\n ltr: (v) => getElement(v),\n },\n direction: 'ltr',\n immediate: true,\n })\n updateList()\n })\n }\n\n const updateList = () => {\n nodeList.value = resolvedContent.value\n ? (Array.from(resolvedContent.value.querySelectorAll(contentQuery)) as HTMLElement[])\n : []\n list.value = nodeList.value.map((el) => ({\n id: el.id,\n el,\n visible: false,\n text: el.textContent,\n }))\n }\n\n let isScrollingDown = true\n let previousScrollTop = 0\n const scrollRoot = computed(() =>\n resolvedContent.value && getComputedStyle(resolvedContent.value).overflowY === 'visible'\n ? null\n : resolvedContent.value\n )\n\n const iobs = useIntersectionObserver(\n nodeList,\n (entries) => {\n const scrollTop = (scrollRoot.value || document?.documentElement)?.scrollTop\n isScrollingDown = scrollTop > previousScrollTop\n previousScrollTop = scrollTop\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n list.value.forEach((node) => {\n if (node.el === entry.target) {\n node.visible = true\n }\n })\n return\n }\n list.value.forEach((node) => {\n if (node.el === entry.target) {\n node.visible = false\n }\n })\n })\n let newId: string | null = null\n if (isScrollingDown) {\n newId = [...list.value].reverse().find((node) => node.visible)?.id || null\n } else {\n newId = list.value.find((node) => node.visible)?.id || null\n }\n if (newId !== null) {\n current.value = newId\n }\n if (!current.value) {\n current.value = list.value[0]?.id || null\n }\n },\n {\n root: root ? getElement(root) : scrollRoot,\n rootMargin,\n threshold,\n }\n )\n watch(current, (newId) => {\n if (manual) return\n const nodes = resolvedTarget.value?.querySelectorAll(targetQuery)\n if (nodes === undefined) return\n let foundParent = false\n let activeElement: HTMLElement | null = null\n nodes.forEach((node) => {\n const parentDropdown = node.closest('.dropdown')\n\n if (node.getAttribute('href')?.includes(`#${newId}`)) {\n activeElement = node as HTMLElement\n node.classList.add('active')\n if (parentDropdown) {\n parentDropdown?.querySelector('.dropdown-toggle')?.classList.add('active')\n foundParent = true\n }\n let parentNav = node.closest('.nav')?.previousSibling as HTMLElement\n while (parentNav?.classList?.contains('nav-item')) {\n foundParent = true\n parentNav.querySelector('.nav-link')?.classList.add('active')\n parentNav = parentNav.closest('.nav')?.previousSibling as HTMLElement\n }\n } else {\n node.classList.remove('active')\n if (parentDropdown && !foundParent) {\n parentDropdown?.querySelector('.dropdown-toggle')?.classList.remove('active')\n }\n\n if (!foundParent) {\n let parentNav = node.closest('.nav')?.previousSibling as HTMLElement\n while (parentNav?.classList?.contains('nav-item')) {\n foundParent = true\n if (parentNav.querySelector('.nav-link') !== activeElement) {\n parentNav.querySelector('.nav-link')?.classList.remove('active')\n }\n parentNav = parentNav.closest('.nav')?.previousSibling as HTMLElement\n }\n }\n }\n })\n })\n\n const mobs = !watchChanges\n ? {stop: () => {}}\n : useMutationObserver(\n resolvedContent,\n () => {\n updateList()\n },\n {\n childList: true,\n }\n )\n const scrollIntoView = (event: Readonly<MouseEvent>, smooth: boolean = false) => {\n event.preventDefault()\n const href = (event.target as HTMLElement)?.getAttribute?.('href')\n const el: HTMLElement | null = href ? document?.querySelector(href) : null\n // console.log('scrollIntoView', event, el, content.value.$el)\n if (el && resolvedContent.value) {\n if (resolvedContent.value.scrollTo) {\n resolvedContent.value.scrollTo({top: el.offsetTop, behavior: smooth ? 'smooth' : 'auto'})\n } else {\n resolvedContent.value.scrollTop = el.offsetTop\n }\n }\n }\n const cleanup = () => {\n iobs.stop()\n mobs.stop()\n }\n return {\n current: readonly(current),\n list,\n content: resolvedContent,\n target: resolvedTarget,\n scrollIntoView,\n updateList,\n cleanup,\n }\n}\n"],"names":["_a"],"mappings":"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"}