UNPKG

uikit

Version:

UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.

105 lines (86 loc) 2.82 kB
import { $$, getCoveringElement, getTargetedElement, hasClass, isSameSiteAnchor, isVisible, offset, offsetViewport, scrollParent, toggleClass, trigger, } from 'uikit-util'; import { intersection, scroll } from '../api/observables'; export default { props: { cls: String, closest: Boolean, scroll: Boolean, overflow: Boolean, offset: Number, }, data: { cls: 'uk-active', closest: false, scroll: false, overflow: true, offset: 0, }, computed: { links: (_, $el) => $$('a[href*="#"]', $el).filter((el) => el.hash && isSameSiteAnchor(el)), elements({ closest: selector }) { return this.links.map((el) => el.closest(selector || '*')); }, }, watch: { links(links) { if (this.scroll) { this.$create('scroll', links, { offset: this.offset }); } }, }, observe: [intersection(), scroll()], update: [ { read() { const targets = this.links.map(getTargetedElement).filter(Boolean); const { length } = targets; if (!length || !isVisible(this.$el)) { return false; } const scrollElement = scrollParent(targets, true); const { scrollTop, scrollHeight } = scrollElement; const viewport = offsetViewport(scrollElement); const max = scrollHeight - viewport.height; let active = false; if (scrollTop === max) { active = length - 1; } else { const offsetBy = this.offset + offset(getCoveringElement()).height; for (let i = 0; i < targets.length; i++) { if (offset(targets[i]).top - viewport.top - offsetBy > 0) { break; } active = +i; } if (active === false && this.overflow) { active = 0; } } return { active }; }, write({ active }) { const changed = active !== false && !hasClass(this.elements[active], this.cls); this.links.forEach((el) => el.blur()); for (let i = 0; i < this.elements.length; i++) { toggleClass(this.elements[i], this.cls, +i === active); } if (changed) { trigger(this.$el, 'active', [active, this.elements[active]]); } }, events: ['scroll', 'resize'], }, ], };