UNPKG

baseframe-js

Version:

Baseframe JS is a comprehensive suite of modular plugins and utilities designed for front-end development

116 lines (115 loc) 4.52 kB
import $be from "base-elem-js"; import { getDataOptions, setParams } from "./util/helpers"; import Store from "./core/Store"; const VERSION = "2.0.0", DATA_NAME = 'NavDesktop', EVENT_NAME = 'navDesktop', DEFAULTS = { stopWidth: 768, delay: 800, navLeavingDelay: 800, outerElem: document.body, cssPrefix: 'menu', hoverCss: 'hover' }; export default class NavDesktop { element; params; cssList; stayHover; navLeaving; static defaults = DEFAULTS; static version = VERSION; static pluginName = DATA_NAME; constructor(element, options) { const s = this; s.stayHover; s.navLeaving; s.element = element; const dataOptions = getDataOptions(element, EVENT_NAME); s.params = setParams(NavDesktop.defaults, options, dataOptions); const { cssPrefix } = s.params; s.cssList = { hasUL: `${cssPrefix}__has-ul`, noUl: `${cssPrefix}__no-ul`, elemEdge: `${cssPrefix}__on-edge`, hovered: `${cssPrefix}--hover`, leaving: `${cssPrefix}--leaving`, }; s.#addCssToElems(); s.#handleEvents(); return s; } static remove(element, plugin) { $be(element).each((elem) => { const s = plugin || Store(elem, DATA_NAME); const $el = $be(s.element); $el.find('ul').off([`mouseover.${EVENT_NAME}`, `focusin.${EVENT_NAME}`, `focusout.${EVENT_NAME}`]); $el.off(`mouseout.${EVENT_NAME}`); Store(elem, DATA_NAME, null); }); } #addCssToElems() { const s = this; const css = s.cssList; const $els = $be('li', s.element); $els.each((elem, i) => { const $el = $be(elem); const $uls = $el.find('ul'); const ulCss = $uls.hasEls ? css.hasUL : css.noUl; $el.addClass(ulCss); }); } #handleEvents() { const s = this, css = s.cssList, p = s.params, $rootUl = $be(s.element).findOne('ul'), $outerElem = $be(p.outerElem), $element = $be(s.element), $allEls = $element.find('li, ul'), allEls = $allEls.toArray(); let prevEvent = null; const evtTracker = (elem, e, cb) => { const currEvent = e.type; const target = e.target; const containsOrISElem = elem.isSameNode(target) || elem.contains(target); if (!prevEvent || (prevEvent !== currEvent && containsOrISElem)) { prevEvent = currEvent; cb(); } }; $rootUl.on([`mouseover.${EVENT_NAME}`, `focusin.${EVENT_NAME}`], (ev, elem) => { evtTracker(elem, ev, () => { const $li = $be(elem); const $liParents = $li.parents('li'); $allEls.rmClass([p.hoverCss, css.elemEdge]); $liParents.addClass(p.hoverCss); $li.addClass(p.hoverCss); s.#edgeDetector(ev.target); s.navLeaving && clearTimeout(s.navLeaving); s.stayHover && clearTimeout(s.stayHover); $outerElem.addClass(css.hovered).rmClass(css.leaving); }); }, allEls); $rootUl.on([`mouseout.${EVENT_NAME}`, `focusout.${EVENT_NAME}`], (ev, elem) => { evtTracker(elem, ev, () => { s.stayHover = setTimeout(() => { $element.find(`.${p.hoverCss}`).rmClass([p.hoverCss, css.elemEdge]); $element.find(`.${css.elemEdge}`).rmClass(css.elemEdge); $outerElem .rmClass(css.hovered) .addClass(css.leaving); s.navLeaving = setTimeout(() => { $outerElem.rmClass(css.leaving); }, p.navLeavingDelay); }, p.delay); }); }, allEls); } #edgeDetector(elem) { const s = this; const css = s.cssList; const li = elem.closest('li'); const { innerWidth, pageXOffset } = window; if (s.params.stopWidth < innerWidth) { const ul = $be.findOne('ul', s.element); if (ul) { const ulRects = $be.elemRects(ul), offsetLeft = ulRects.left + pageXOffset, ulWidth = ul.scrollWidth, fullyVisible = (offsetLeft + ulWidth <= innerWidth); if (!fullyVisible) { li.classList.add(css.elemEdge); } } } } }