UNPKG

@financial-times/o-header

Version:

Responsive Financial Times page header with primary and secondary navigation, a drop down mega menu, and a collapsible drawer

103 lines (81 loc) 3 kB
import viewport from '@financial-times/o-viewport'; import * as oUtils from '@financial-times/o-utils'; import { initSubnavDropdowns } from './subnavDropdown.js'; function init(headerEl) { const subnav = headerEl.querySelector('[data-o-header-subnav]'); if (subnav === null) { return; } setupSubnav(subnav) } function setupSubnav(subnav) { // Looks like we can't remove this on destroy, // as another component may be using it. viewport.listenTo('resize'); const directionButtons = Array .from(subnav.getElementsByTagName('button')) .filter(btn => btn.className.includes('left') || btn.className.includes('right')); const wrapper = subnav.querySelector('[data-o-header-subnav-wrapper]'); function checkCurrentPosition() { const wrapperWidth = wrapper.clientWidth; const currentSelection = wrapper.querySelector('[aria-current]'); if (currentSelection) { const wrapperRect = wrapper.getBoundingClientRect(); const currentSelectionRect = currentSelection.getBoundingClientRect(); const currentSelectionEnd = currentSelectionRect.right - wrapperRect.left; //if the current selection is wider than the end of the wrapper if (currentSelectionEnd > wrapperWidth) { const RIGHT_ARROW_BUTTON_OFFSET = 25; //calculate offscreen distance of the selected item and include buffer for the right arrow button const scrollDistance = currentSelectionEnd - wrapperWidth + RIGHT_ARROW_BUTTON_OFFSET; wrapper.scrollTo(scrollDistance, 0); } } scrollable(); } function direction(button) { return button.className.match(/left|right/).pop(); } function scrollable() { const scrollWidth = wrapper.scrollWidth; const wrapperWidth = wrapper.clientWidth; directionButtons.forEach(button => { if (direction(button) === 'left') { button.disabled = wrapper.scrollLeft === 0; } else { const remaining = scrollWidth - wrapperWidth - wrapper.scrollLeft; // Allow a little difference as scrollWidth is fast, not accurate. button.disabled = remaining <= 1; } }); } function scroll(e) { let distance = 100; const scrollWidth = wrapper.scrollWidth; const wrapperWidth = wrapper.clientWidth; if (direction(e.currentTarget) === 'left') { distance = (wrapper.scrollLeft > distance ? distance : wrapper.scrollLeft) * -1; } else { const remaining = scrollWidth - wrapperWidth - wrapper.scrollLeft; distance = remaining > distance ? distance : remaining; } wrapper.scrollLeft = wrapper.scrollLeft + distance; scrollable(); } wrapper.addEventListener('scroll', oUtils.throttle(scrollable, 100)); window.addEventListener('oViewport.resize', scrollable); const observer = new MutationObserver(checkCurrentPosition); observer.observe(wrapper, { attributes: false, childList: true, subtree: true }); directionButtons.forEach(button => { button.onclick = scroll; }); initSubnavDropdowns(subnav); checkCurrentPosition(); } export { init, setupSubnav }; export default { init };