/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { a as getOffset } from './dom.js';

/**
 * @returns the width of the document's scrollbar
 */
function getScrollLockSize() {
    const documentWidth = document.documentElement.clientWidth;
    const scrollbarWidth = Math.abs(window.innerWidth - documentWidth);
    const { paddingRight, paddingInlineEnd } = getComputedStyle(document.body);
    let docPadding = Number((paddingInlineEnd || paddingRight).replace(/px/, ''));
    if (!!docPadding || isNaN(docPadding)) {
        docPadding = 0;
    }
    return scrollbarWidth + docPadding;
}
const locks = new Set();
/**
 * Prevents body scrolling. Keeps track of which elements requested a lock so multiple levels of locking are possible
 * without premature unlocking.
 */
function lockBodyScrolling(lockingEl) {
    locks.add(lockingEl);
    if (document.documentElement.classList.contains('nano-scroll-lock'))
        return;
    // When the first lock is created,
    // set the scroll lock size to match the scrollbar's width to prevent content from shifting.
    const scrollbarWidth = getScrollLockSize(); // must be measured before the `sl-scroll-lock` class is applied
    let scrollbarGutterProperty = getComputedStyle(document.documentElement).scrollbarGutter;
    // default is auto, unsupported browsers is "undefined"
    if (!scrollbarGutterProperty || scrollbarGutterProperty === 'auto') {
        scrollbarGutterProperty = 'stable';
    }
    if (scrollbarWidth <= 0) {
        // if there's no scrollbar, just set it to "revert" so whatever the user has set gets used. This is useful is the page is not overflowing and showing a scrollbar, or if the user has overflow: hidden, or any other reason a scrollbar may not be showing.
        scrollbarGutterProperty = 'revert';
    }
    document.documentElement.style.setProperty('--nano-scroll-lock-gutter', scrollbarGutterProperty);
    document.documentElement.classList.add('nano-scroll-lock');
    document.documentElement.style.setProperty('--nano-scroll-lock-size', `${scrollbarWidth}px`);
}
/**
 * Unlocks body scrolling. Scrolling will only be unlocked once all elements that requested a lock call this method.
 */
function unlockBodyScrolling(lockingEl) {
    locks.delete(lockingEl);
    if (locks.size === 0) {
        document.documentElement.classList.remove('nano-scroll-lock');
        document.documentElement.style.removeProperty('--nano-scroll-lock-size');
    }
}
function scrollTo(element, scrollAmt, vertical = false) {
    if (!vertical) {
        try {
            element.scrollTo({ left: scrollAmt, behavior: 'smooth' });
        }
        catch (_e) {
            element.scrollLeft = scrollAmt;
        }
        return;
    }
    try {
        element.scrollTo({ top: scrollAmt, behavior: 'smooth' });
    }
    catch (_e) {
        element.scrollTop = scrollAmt;
    }
}
/**
 * Scrolls an element into view *of its parent container*.
 * If the element is already in view, nothing will happen.
 *
 * Note to future me - cannot use native `scrollIntoView`
 * 'cos it will move the whole window
 * (vertically even though we only care about parent).
 */
function scrollIntoView(element, container, direction = 'vertical', position = 'start') {
    if (!element)
        return;
    const offset = getOffset(element, container);
    const offsetTop = offset.top + container.scrollTop;
    const offsetLeft = offset.left + container.scrollLeft;
    const minX = container.scrollLeft;
    const maxX = container.scrollLeft + container.offsetWidth;
    const minY = container.scrollTop;
    const maxY = container.scrollTop + container.offsetHeight;
    if (direction === 'horizontal' || direction === 'both') {
        if (position === 'start') {
            if (offsetLeft < minX)
                scrollTo(container, offsetLeft);
            else if (offsetLeft + element.clientWidth > maxX)
                scrollTo(container, offsetLeft - container.offsetWidth + element.clientWidth);
        }
        else {
            scrollTo(container, container.scrollLeft +
                offset.left -
                (container.offsetWidth / 2 - element.offsetWidth / 2));
        }
    }
    if (direction === 'vertical' || direction === 'both') {
        if (position === 'start') {
            if (offsetTop < minY)
                scrollTo(container, offsetTop, true);
            else if (offsetTop + element.clientHeight > maxY) {
                scrollTo(container, offsetTop - container.offsetHeight + element.clientHeight, true);
            }
        }
        else {
            scrollTo(container, container.scrollTop +
                offset.top -
                (container.offsetHeight / 2 - element.offsetHeight / 2), true);
        }
    }
}
/**
 * Attempts to find the closest scrolling parental element
 * @param element - the element from which to traverse up the DOM
 * @returns - the closest scrolling parental element
 */
function findScrollParent(element) {
    let style = getComputedStyle(element);
    const excludeStaticParent = style.position === 'absolute';
    const overflowRegex = /(auto|scroll)/;
    if (style.position === 'fixed')
        return document.documentElement;
    for (let parent = element; (parent = parent.parentElement);) {
        style = getComputedStyle(parent);
        if (excludeStaticParent && style.position === 'static') {
            continue;
        }
        if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
            return parent;
        }
    }
    return document.documentElement;
}
/**
 * Checks whether an element is currently viewable within the viewport
 * @param el - element to check
 * @param percentVisible - the percentage of the element that should be within the viewport
 * @returns true if the element's area percentage is visible
 */
function isInViewport(el, percentVisible = 100, axis = 'y') {
    const r = el.getBoundingClientRect();
    const windowHeight = window.innerHeight || document.documentElement.clientHeight;
    const windowWidth = window.innerWidth || document.documentElement.clientWidth;
    if (!r.bottom &&
        !r.top &&
        !r.left &&
        !r.right &&
        !r.height &&
        !r.width &&
        !r.x &&
        !r.y)
        return false;
    let check = true;
    if (axis === 'y' || axis === 'both') {
        check = !(Math.floor(100 - ((r.top >= 0 ? 0 : r.top) / +-r.height) * 100) <
            percentVisible ||
            Math.floor(100 - ((r.bottom - windowHeight) / r.height) * 100) <
                percentVisible);
    }
    if (axis === 'x' || (axis === 'both' && check)) {
        check = !(Math.floor(100 - ((r.left >= 0 ? 0 : r.left) / +-r.width) * 100) <
            percentVisible ||
            Math.floor(100 - ((r.right - windowWidth) / r.width) * 100) <
                percentVisible);
    }
    return check;
}

export { findScrollParent as f, isInViewport as i, lockBodyScrolling as l, scrollIntoView as s, unlockBodyScrolling as u };
