function run(fn) {
    return fn();
}
function run_all(fns) {
    fns.forEach(run);
}

const dirty_components = [];
const binding_callbacks = [];
const render_callbacks = [];
const flush_callbacks = [];
const resolved_promise = Promise.resolve();
let update_scheduled = false;
function schedule_update() {
    if (!update_scheduled) {
        update_scheduled = true;
        resolved_promise.then(flush);
    }
}
function tick() {
    schedule_update();
    return resolved_promise;
}
function add_render_callback(fn) {
    render_callbacks.push(fn);
}
// flush() calls callbacks in this order:
// 1. All beforeUpdate callbacks, in order: parents before children
// 2. All bind:this callbacks, in reverse order: children before parents.
// 3. All afterUpdate callbacks, in order: parents before children. EXCEPT
//    for afterUpdates called during the initial onMount, which are called in
//    reverse order: children before parents.
// Since callbacks might update component values, which could trigger another
// call to flush(), the following steps guard against this:
// 1. During beforeUpdate, any updated components will be added to the
//    dirty_components array and will cause a reentrant call to flush(). Because
//    the flush index is kept outside the function, the reentrant call will pick
//    up where the earlier call left off and go through all dirty components. The
//    current_component value is saved and restored so that the reentrant call will
//    not interfere with the "parent" flush() call.
// 2. bind:this callbacks cannot trigger new flush() calls.
// 3. During afterUpdate, any updated components will NOT have their afterUpdate
//    callback called a second time; the seen_callbacks set, outside the flush()
//    function, guarantees this behavior.
const seen_callbacks = new Set();
let flushidx = 0; // Do *not* move this inside the flush() function
function flush() {
    do {
        // first, call beforeUpdate functions
        // and update components
        while (flushidx < dirty_components.length) {
            const component = dirty_components[flushidx];
            flushidx++;
            update(component.$$);
        }
        dirty_components.length = 0;
        flushidx = 0;
        while (binding_callbacks.length)
            binding_callbacks.pop()();
        // then, once components are updated, call
        // afterUpdate functions. This may cause
        // subsequent updates...
        for (let i = 0; i < render_callbacks.length; i += 1) {
            const callback = render_callbacks[i];
            if (!seen_callbacks.has(callback)) {
                // ...so guard against infinite loops
                seen_callbacks.add(callback);
                callback();
            }
        }
        render_callbacks.length = 0;
    } while (dirty_components.length);
    while (flush_callbacks.length) {
        flush_callbacks.pop()();
    }
    update_scheduled = false;
    seen_callbacks.clear();
}
function update($$) {
    if ($$.fragment !== null) {
        $$.update();
        run_all($$.before_update);
        const dirty = $$.dirty;
        $$.dirty = [-1];
        $$.fragment && $$.fragment.p($$.ctx, dirty);
        $$.after_update.forEach(add_render_callback);
    }
}

const defaultOptions = {
    root: null,
    rootMargin: '0px',
    threshold: 0,
    unobserveOnEnter: false,
};
const createEvent = (name, detail) => new CustomEvent(name, { detail });
function inview(node, options = {}) {
    const { root, rootMargin, threshold, unobserveOnEnter } = Object.assign(Object.assign({}, defaultOptions), options);
    let prevPos = {
        x: undefined,
        y: undefined,
    };
    let scrollDirection = {
        vertical: undefined,
        horizontal: undefined,
    };
    if (typeof IntersectionObserver !== 'undefined' && node) {
        const observer = new IntersectionObserver((entries, _observer) => {
            entries.forEach((singleEntry) => {
                if (prevPos.y > singleEntry.boundingClientRect.y) {
                    scrollDirection.vertical = 'up';
                }
                else {
                    scrollDirection.vertical = 'down';
                }
                if (prevPos.x > singleEntry.boundingClientRect.x) {
                    scrollDirection.horizontal = 'left';
                }
                else {
                    scrollDirection.horizontal = 'right';
                }
                prevPos = {
                    y: singleEntry.boundingClientRect.y,
                    x: singleEntry.boundingClientRect.x,
                };
                const detail = {
                    inView: singleEntry.isIntersecting,
                    entry: singleEntry,
                    scrollDirection,
                    node,
                    observer: _observer,
                };
                node.dispatchEvent(createEvent('inview_change', detail));
                //@ts-expect-error only for backward compatibility
                node.dispatchEvent(createEvent('change', detail));
                if (singleEntry.isIntersecting) {
                    node.dispatchEvent(createEvent('inview_enter', detail));
                    //@ts-expect-error only for backward compatibility
                    node.dispatchEvent(createEvent('enter', detail));
                    unobserveOnEnter && _observer.unobserve(node);
                }
                else {
                    node.dispatchEvent(createEvent('inview_leave', detail));
                    //@ts-expect-error only for backward compatibility
                    node.dispatchEvent(createEvent('leave', detail));
                }
            });
        }, {
            root,
            rootMargin,
            threshold,
        });
        tick().then(() => {
            node.dispatchEvent(createEvent('inview_init', { observer, node }));
            node.dispatchEvent(
            //@ts-expect-error only for backward compatibility
            createEvent('init', { observer, node }));
        });
        observer.observe(node);
        return {
            destroy() {
                observer.unobserve(node);
            },
        };
    }
}

export { inview };
