UNPKG

dockview-react

Version:

Zero dependency layout manager supporting tabs, grids and splitviews

11,659 lines 493 kB
/**
 * dockview-react
 * @version 4.2.1
 * @link https://github.com/mathuo/dockview
 * @license MIT
 */
define(['exports', 'react', 'react-dom'], (function (exports, React, ReactDOM) { 'use strict';

    class TransferObject {
    }
    class PanelTransfer extends TransferObject {
        constructor(viewId, groupId, panelId) {
            super();
            this.viewId = viewId;
            this.groupId = groupId;
            this.panelId = panelId;
        }
    }
    class PaneTransfer extends TransferObject {
        constructor(viewId, paneId) {
            super();
            this.viewId = viewId;
            this.paneId = paneId;
        }
    }
    /**
     * A singleton to store transfer data during drag & drop operations that are only valid within the application.
     */
    class LocalSelectionTransfer {
        constructor() {
            // protect against external instantiation
        }
        static getInstance() {
            return LocalSelectionTransfer.INSTANCE;
        }
        hasData(proto) {
            return proto && proto === this.proto;
        }
        clearData(proto) {
            if (this.hasData(proto)) {
                this.proto = undefined;
                this.data = undefined;
            }
        }
        getData(proto) {
            if (this.hasData(proto)) {
                return this.data;
            }
            return undefined;
        }
        setData(data, proto) {
            if (proto) {
                this.data = data;
                this.proto = proto;
            }
        }
    }
    LocalSelectionTransfer.INSTANCE = new LocalSelectionTransfer();
    function getPanelData() {
        const panelTransfer = LocalSelectionTransfer.getInstance();
        const isPanelEvent = panelTransfer.hasData(PanelTransfer.prototype);
        if (!isPanelEvent) {
            return undefined;
        }
        return panelTransfer.getData(PanelTransfer.prototype)[0];
    }
    function getPaneData() {
        const paneTransfer = LocalSelectionTransfer.getInstance();
        const isPanelEvent = paneTransfer.hasData(PaneTransfer.prototype);
        if (!isPanelEvent) {
            return undefined;
        }
        return paneTransfer.getData(PaneTransfer.prototype)[0];
    }

    exports.DockviewEvent = void 0;
    (function (Event) {
        Event.any = (...children) => {
            return (listener) => {
                const disposables = children.map((child) => child(listener));
                return {
                    dispose: () => {
                        disposables.forEach((d) => {
                            d.dispose();
                        });
                    },
                };
            };
        };
    })(exports.DockviewEvent || (exports.DockviewEvent = {}));
    class DockviewEvent {
        constructor() {
            this._defaultPrevented = false;
        }
        get defaultPrevented() {
            return this._defaultPrevented;
        }
        preventDefault() {
            this._defaultPrevented = true;
        }
    }
    class AcceptableEvent {
        constructor() {
            this._isAccepted = false;
        }
        get isAccepted() {
            return this._isAccepted;
        }
        accept() {
            this._isAccepted = true;
        }
    }
    class LeakageMonitor {
        constructor() {
            this.events = new Map();
        }
        get size() {
            return this.events.size;
        }
        add(event, stacktrace) {
            this.events.set(event, stacktrace);
        }
        delete(event) {
            this.events.delete(event);
        }
        clear() {
            this.events.clear();
        }
    }
    class Stacktrace {
        static create() {
            var _a;
            return new Stacktrace((_a = new Error().stack) !== null && _a !== void 0 ? _a : '');
        }
        constructor(value) {
            this.value = value;
        }
        print() {
            console.warn('dockview: stacktrace', this.value);
        }
    }
    class Listener {
        constructor(callback, stacktrace) {
            this.callback = callback;
            this.stacktrace = stacktrace;
        }
    }
    // relatively simple event emitter taken from https://github.com/microsoft/vscode/blob/master/src/vs/base/common/event.ts
    class Emitter {
        static setLeakageMonitorEnabled(isEnabled) {
            if (isEnabled !== Emitter.ENABLE_TRACKING) {
                Emitter.MEMORY_LEAK_WATCHER.clear();
            }
            Emitter.ENABLE_TRACKING = isEnabled;
        }
        get value() {
            return this._last;
        }
        constructor(options) {
            this.options = options;
            this._listeners = [];
            this._disposed = false;
        }
        get event() {
            if (!this._event) {
                this._event = (callback) => {
                    var _a;
                    if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.replay) && this._last !== undefined) {
                        callback(this._last);
                    }
                    const listener = new Listener(callback, Emitter.ENABLE_TRACKING ? Stacktrace.create() : undefined);
                    this._listeners.push(listener);
                    return {
                        dispose: () => {
                            const index = this._listeners.indexOf(listener);
                            if (index > -1) {
                                this._listeners.splice(index, 1);
                            }
                            else if (Emitter.ENABLE_TRACKING) ;
                        },
                    };
                };
                if (Emitter.ENABLE_TRACKING) {
                    Emitter.MEMORY_LEAK_WATCHER.add(this._event, Stacktrace.create());
                }
            }
            return this._event;
        }
        fire(e) {
            this._last = e;
            for (const listener of this._listeners) {
                listener.callback(e);
            }
        }
        dispose() {
            if (!this._disposed) {
                this._disposed = true;
                if (this._listeners.length > 0) {
                    if (Emitter.ENABLE_TRACKING) {
                        queueMicrotask(() => {
                            var _a;
                            // don't check until stack of execution is completed to allow for out-of-order disposals within the same execution block
                            for (const listener of this._listeners) {
                                console.warn('dockview: stacktrace', (_a = listener.stacktrace) === null || _a === void 0 ? void 0 : _a.print());
                            }
                        });
                    }
                    this._listeners = [];
                }
                if (Emitter.ENABLE_TRACKING && this._event) {
                    Emitter.MEMORY_LEAK_WATCHER.delete(this._event);
                }
            }
        }
    }
    Emitter.ENABLE_TRACKING = false;
    Emitter.MEMORY_LEAK_WATCHER = new LeakageMonitor();
    function addDisposableListener(element, type, listener, options) {
        element.addEventListener(type, listener, options);
        return {
            dispose: () => {
                element.removeEventListener(type, listener, options);
            },
        };
    }
    /**
     *
     * Event Emitter that fires events from a Microtask callback, only one event will fire per event-loop cycle.
     *
     * It's kind of like using an `asapScheduler` in RxJs with additional logic to only fire once per event-loop cycle.
     * This implementation exists to avoid external dependencies.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask
     * @see https://rxjs.dev/api/index/const/asapScheduler
     */
    class AsapEvent {
        constructor() {
            this._onFired = new Emitter();
            this._currentFireCount = 0;
            this._queued = false;
            this.onEvent = (e) => {
                /**
                 * when the event is first subscribed to take note of the current fire count
                 */
                const fireCountAtTimeOfEventSubscription = this._currentFireCount;
                return this._onFired.event(() => {
                    /**
                     * if the current fire count is greater than the fire count at event subscription
                     * then the event has been fired since we subscribed and it's ok to "on_next" the event.
                     *
                     * if the count is not greater then what we are recieving is an event from the microtask
                     * queue that was triggered before we actually subscribed and therfore we should ignore it.
                     */
                    if (this._currentFireCount > fireCountAtTimeOfEventSubscription) {
                        e();
                    }
                });
            };
        }
        fire() {
            this._currentFireCount++;
            if (this._queued) {
                return;
            }
            this._queued = true;
            queueMicrotask(() => {
                this._queued = false;
                this._onFired.fire();
            });
        }
        dispose() {
            this._onFired.dispose();
        }
    }

    exports.DockviewDisposable = void 0;
    (function (Disposable) {
        Disposable.NONE = {
            dispose: () => {
                // noop
            },
        };
        function from(func) {
            return {
                dispose: () => {
                    func();
                },
            };
        }
        Disposable.from = from;
    })(exports.DockviewDisposable || (exports.DockviewDisposable = {}));
    class CompositeDisposable {
        get isDisposed() {
            return this._isDisposed;
        }
        constructor(...args) {
            this._isDisposed = false;
            this._disposables = args;
        }
        addDisposables(...args) {
            args.forEach((arg) => this._disposables.push(arg));
        }
        dispose() {
            if (this._isDisposed) {
                return;
            }
            this._isDisposed = true;
            this._disposables.forEach((arg) => arg.dispose());
            this._disposables = [];
        }
    }
    class MutableDisposable {
        constructor() {
            this._disposable = exports.DockviewDisposable.NONE;
        }
        set value(disposable) {
            if (this._disposable) {
                this._disposable.dispose();
            }
            this._disposable = disposable;
        }
        dispose() {
            if (this._disposable) {
                this._disposable.dispose();
                this._disposable = exports.DockviewDisposable.NONE;
            }
        }
    }

    class OverflowObserver extends CompositeDisposable {
        constructor(el) {
            super();
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            this._value = null;
            this.addDisposables(this._onDidChange, watchElementResize(el, (entry) => {
                const hasScrollX = entry.target.scrollWidth > entry.target.clientWidth;
                const hasScrollY = entry.target.scrollHeight > entry.target.clientHeight;
                this._value = { hasScrollX, hasScrollY };
                this._onDidChange.fire(this._value);
            }));
        }
    }
    function watchElementResize(element, cb) {
        const observer = new ResizeObserver((entires) => {
            /**
             * Fast browser window resize produces Error: ResizeObserver loop limit exceeded.
             * The error isn't visible in browser console, doesn't affect functionality, but degrades performance.
             * See https://stackoverflow.com/questions/49384120/resizeobserver-loop-limit-exceeded/58701523#58701523
             */
            requestAnimationFrame(() => {
                const firstEntry = entires[0];
                cb(firstEntry);
            });
        });
        observer.observe(element);
        return {
            dispose: () => {
                observer.unobserve(element);
                observer.disconnect();
            },
        };
    }
    const removeClasses = (element, ...classes) => {
        for (const classname of classes) {
            if (element.classList.contains(classname)) {
                element.classList.remove(classname);
            }
        }
    };
    const addClasses = (element, ...classes) => {
        for (const classname of classes) {
            if (!element.classList.contains(classname)) {
                element.classList.add(classname);
            }
        }
    };
    const toggleClass = (element, className, isToggled) => {
        const hasClass = element.classList.contains(className);
        if (isToggled && !hasClass) {
            element.classList.add(className);
        }
        if (!isToggled && hasClass) {
            element.classList.remove(className);
        }
    };
    function isAncestor(testChild, testAncestor) {
        while (testChild) {
            if (testChild === testAncestor) {
                return true;
            }
            testChild = testChild.parentNode;
        }
        return false;
    }
    function trackFocus(element) {
        return new FocusTracker(element);
    }
    /**
     * Track focus on an element. Ensure tabIndex is set when an HTMLElement is not focusable by default
     */
    class FocusTracker extends CompositeDisposable {
        constructor(element) {
            super();
            this._onDidFocus = new Emitter();
            this.onDidFocus = this._onDidFocus.event;
            this._onDidBlur = new Emitter();
            this.onDidBlur = this._onDidBlur.event;
            this.addDisposables(this._onDidFocus, this._onDidBlur);
            let hasFocus = isAncestor(document.activeElement, element);
            let loosingFocus = false;
            const onFocus = () => {
                loosingFocus = false;
                if (!hasFocus) {
                    hasFocus = true;
                    this._onDidFocus.fire();
                }
            };
            const onBlur = () => {
                if (hasFocus) {
                    loosingFocus = true;
                    window.setTimeout(() => {
                        if (loosingFocus) {
                            loosingFocus = false;
                            hasFocus = false;
                            this._onDidBlur.fire();
                        }
                    }, 0);
                }
            };
            this._refreshStateHandler = () => {
                const currentNodeHasFocus = isAncestor(document.activeElement, element);
                if (currentNodeHasFocus !== hasFocus) {
                    if (hasFocus) {
                        onBlur();
                    }
                    else {
                        onFocus();
                    }
                }
            };
            this.addDisposables(addDisposableListener(element, 'focus', onFocus, true));
            this.addDisposables(addDisposableListener(element, 'blur', onBlur, true));
        }
        refreshState() {
            this._refreshStateHandler();
        }
    }
    // quasi: apparently, but not really; seemingly
    const QUASI_PREVENT_DEFAULT_KEY = 'dv-quasiPreventDefault';
    // mark an event directly for other listeners to check
    function quasiPreventDefault(event) {
        event[QUASI_PREVENT_DEFAULT_KEY] = true;
    }
    // check if this event has been marked
    function quasiDefaultPrevented(event) {
        return event[QUASI_PREVENT_DEFAULT_KEY];
    }
    function addStyles(document, styleSheetList) {
        const styleSheets = Array.from(styleSheetList);
        for (const styleSheet of styleSheets) {
            if (styleSheet.href) {
                const link = document.createElement('link');
                link.href = styleSheet.href;
                link.type = styleSheet.type;
                link.rel = 'stylesheet';
                document.head.appendChild(link);
            }
            let cssTexts = [];
            try {
                if (styleSheet.cssRules) {
                    cssTexts = Array.from(styleSheet.cssRules).map((rule) => rule.cssText);
                }
            }
            catch (err) {
                // security errors (lack of permissions), ignore
            }
            for (const rule of cssTexts) {
                const style = document.createElement('style');
                style.appendChild(document.createTextNode(rule));
                document.head.appendChild(style);
            }
        }
    }
    function getDomNodePagePosition(domNode) {
        const { left, top, width, height } = domNode.getBoundingClientRect();
        return {
            left: left + window.scrollX,
            top: top + window.scrollY,
            width: width,
            height: height,
        };
    }
    /**
     * Check whether an element is in the DOM (including the Shadow DOM)
     * @see https://terodox.tech/how-to-tell-if-an-element-is-in-the-dom-including-the-shadow-dom/
     */
    function isInDocument(element) {
        let currentElement = element;
        while (currentElement === null || currentElement === void 0 ? void 0 : currentElement.parentNode) {
            if (currentElement.parentNode === document) {
                return true;
            }
            else if (currentElement.parentNode instanceof DocumentFragment) {
                // handle shadow DOMs
                currentElement = currentElement.parentNode.host;
            }
            else {
                currentElement = currentElement.parentNode;
            }
        }
        return false;
    }
    function addTestId(element, id) {
        element.setAttribute('data-testid', id);
    }
    /**
     * Should be more efficient than element.querySelectorAll("*") since there
     * is no need to store every element in-memory using this approach
     */
    function allTagsNamesInclusiveOfShadowDoms(tagNames) {
        const iframes = [];
        function findIframesInNode(node) {
            if (node.nodeType === Node.ELEMENT_NODE) {
                if (tagNames.includes(node.tagName)) {
                    iframes.push(node);
                }
                if (node.shadowRoot) {
                    findIframesInNode(node.shadowRoot);
                }
                for (const child of node.children) {
                    findIframesInNode(child);
                }
            }
        }
        findIframesInNode(document.documentElement);
        return iframes;
    }
    function disableIframePointEvents(rootNode = document) {
        const iframes = allTagsNamesInclusiveOfShadowDoms(['IFRAME', 'WEBVIEW']);
        const original = new WeakMap(); // don't hold onto HTMLElement references longer than required
        for (const iframe of iframes) {
            original.set(iframe, iframe.style.pointerEvents);
            iframe.style.pointerEvents = 'none';
        }
        return {
            release: () => {
                var _a;
                for (const iframe of iframes) {
                    iframe.style.pointerEvents = (_a = original.get(iframe)) !== null && _a !== void 0 ? _a : 'auto';
                }
                iframes.splice(0, iframes.length); // don't hold onto HTMLElement references longer than required
            },
        };
    }
    function getDockviewTheme(element) {
        function toClassList(element) {
            const list = [];
            for (let i = 0; i < element.classList.length; i++) {
                list.push(element.classList.item(i));
            }
            return list;
        }
        let theme = undefined;
        let parent = element;
        while (parent !== null) {
            theme = toClassList(parent).find((cls) => cls.startsWith('dockview-theme-'));
            if (typeof theme === 'string') {
                break;
            }
            parent = parent.parentElement;
        }
        return theme;
    }
    class Classnames {
        constructor(element) {
            this.element = element;
            this._classNames = [];
        }
        setClassNames(classNames) {
            for (const className of this._classNames) {
                toggleClass(this.element, className, false);
            }
            this._classNames = classNames
                .split(' ')
                .filter((v) => v.trim().length > 0);
            for (const className of this._classNames) {
                toggleClass(this.element, className, true);
            }
        }
    }
    const DEBOUCE_DELAY = 100;
    function isChildEntirelyVisibleWithinParent(child, parent) {
        //
        const childPosition = getDomNodePagePosition(child);
        const parentPosition = getDomNodePagePosition(parent);
        if (childPosition.left < parentPosition.left) {
            return false;
        }
        if (childPosition.left + childPosition.width >
            parentPosition.left + parentPosition.width) {
            return false;
        }
        return true;
    }
    function onDidWindowMoveEnd(window) {
        const emitter = new Emitter();
        let previousScreenX = window.screenX;
        let previousScreenY = window.screenY;
        let timeout;
        const checkMovement = () => {
            if (window.closed) {
                return;
            }
            const currentScreenX = window.screenX;
            const currentScreenY = window.screenY;
            if (currentScreenX !== previousScreenX ||
                currentScreenY !== previousScreenY) {
                clearTimeout(timeout);
                timeout = setTimeout(() => {
                    emitter.fire();
                }, DEBOUCE_DELAY);
                previousScreenX = currentScreenX;
                previousScreenY = currentScreenY;
            }
            requestAnimationFrame(checkMovement);
        };
        checkMovement();
        return emitter;
    }
    function onDidWindowResizeEnd(element, cb) {
        let resizeTimeout;
        const disposable = new CompositeDisposable(addDisposableListener(element, 'resize', () => {
            clearTimeout(resizeTimeout);
            resizeTimeout = setTimeout(() => {
                cb();
            }, DEBOUCE_DELAY);
        }));
        return disposable;
    }

    function tail(arr) {
        if (arr.length === 0) {
            throw new Error('Invalid tail call');
        }
        return [arr.slice(0, arr.length - 1), arr[arr.length - 1]];
    }
    function sequenceEquals(arr1, arr2) {
        if (arr1.length !== arr2.length) {
            return false;
        }
        for (let i = 0; i < arr1.length; i++) {
            if (arr1[i] !== arr2[i]) {
                return false;
            }
        }
        return true;
    }
    /**
     * Pushes an element to the start of the array, if found.
     */
    function pushToStart(arr, value) {
        const index = arr.indexOf(value);
        if (index > -1) {
            arr.splice(index, 1);
            arr.unshift(value);
        }
    }
    /**
     * Pushes an element to the end of the array, if found.
     */
    function pushToEnd(arr, value) {
        const index = arr.indexOf(value);
        if (index > -1) {
            arr.splice(index, 1);
            arr.push(value);
        }
    }
    function firstIndex(array, fn) {
        for (let i = 0; i < array.length; i++) {
            const element = array[i];
            if (fn(element)) {
                return i;
            }
        }
        return -1;
    }
    function remove(array, value) {
        const index = array.findIndex((t) => t === value);
        if (index > -1) {
            array.splice(index, 1);
            return true;
        }
        return false;
    }

    const clamp = (value, min, max) => {
        if (min > max) {
            /**
             * caveat: an error should be thrown here if this was a proper `clamp` function but we need to handle
             * cases where `min` > `max` and in those cases return `min`.
             */
            return min;
        }
        return Math.min(max, Math.max(value, min));
    };
    const sequentialNumberGenerator = () => {
        let value = 1;
        return { next: () => (value++).toString() };
    };
    const range = (from, to) => {
        const result = [];
        if (typeof to !== 'number') {
            to = from;
            from = 0;
        }
        if (from <= to) {
            for (let i = from; i < to; i++) {
                result.push(i);
            }
        }
        else {
            for (let i = from; i > to; i--) {
                result.push(i);
            }
        }
        return result;
    };

    class ViewItem {
        set size(size) {
            this._size = size;
        }
        get size() {
            return this._size;
        }
        get cachedVisibleSize() {
            return this._cachedVisibleSize;
        }
        get visible() {
            return typeof this._cachedVisibleSize === 'undefined';
        }
        get minimumSize() {
            return this.visible ? this.view.minimumSize : 0;
        }
        get viewMinimumSize() {
            return this.view.minimumSize;
        }
        get maximumSize() {
            return this.visible ? this.view.maximumSize : 0;
        }
        get viewMaximumSize() {
            return this.view.maximumSize;
        }
        get priority() {
            return this.view.priority;
        }
        get snap() {
            return !!this.view.snap;
        }
        set enabled(enabled) {
            this.container.style.pointerEvents = enabled ? '' : 'none';
        }
        constructor(container, view, size, disposable) {
            this.container = container;
            this.view = view;
            this.disposable = disposable;
            this._cachedVisibleSize = undefined;
            if (typeof size === 'number') {
                this._size = size;
                this._cachedVisibleSize = undefined;
                container.classList.add('visible');
            }
            else {
                this._size = 0;
                this._cachedVisibleSize = size.cachedVisibleSize;
            }
        }
        setVisible(visible, size) {
            var _a;
            if (visible === this.visible) {
                return;
            }
            if (visible) {
                this.size = clamp((_a = this._cachedVisibleSize) !== null && _a !== void 0 ? _a : 0, this.viewMinimumSize, this.viewMaximumSize);
                this._cachedVisibleSize = undefined;
            }
            else {
                this._cachedVisibleSize =
                    typeof size === 'number' ? size : this.size;
                this.size = 0;
            }
            this.container.classList.toggle('visible', visible);
            if (this.view.setVisible) {
                this.view.setVisible(visible);
            }
        }
        dispose() {
            this.disposable.dispose();
            return this.view;
        }
    }

    /*---------------------------------------------------------------------------------------------
     * Accreditation: This file is largly based upon the MIT licenced VSCode sourcecode found at:
     * https://github.com/microsoft/vscode/tree/main/src/vs/base/browser/ui/splitview
     *--------------------------------------------------------------------------------------------*/
    exports.Orientation = void 0;
    (function (Orientation) {
        Orientation["HORIZONTAL"] = "HORIZONTAL";
        Orientation["VERTICAL"] = "VERTICAL";
    })(exports.Orientation || (exports.Orientation = {}));
    exports.SashState = void 0;
    (function (SashState) {
        SashState[SashState["MAXIMUM"] = 0] = "MAXIMUM";
        SashState[SashState["MINIMUM"] = 1] = "MINIMUM";
        SashState[SashState["DISABLED"] = 2] = "DISABLED";
        SashState[SashState["ENABLED"] = 3] = "ENABLED";
    })(exports.SashState || (exports.SashState = {}));
    exports.LayoutPriority = void 0;
    (function (LayoutPriority) {
        LayoutPriority["Low"] = "low";
        LayoutPriority["High"] = "high";
        LayoutPriority["Normal"] = "normal";
    })(exports.LayoutPriority || (exports.LayoutPriority = {}));
    exports.Sizing = void 0;
    (function (Sizing) {
        Sizing.Distribute = { type: 'distribute' };
        function Split(index) {
            return { type: 'split', index };
        }
        Sizing.Split = Split;
        function Invisible(cachedVisibleSize) {
            return { type: 'invisible', cachedVisibleSize };
        }
        Sizing.Invisible = Invisible;
    })(exports.Sizing || (exports.Sizing = {}));
    class Splitview {
        get contentSize() {
            return this._contentSize;
        }
        get size() {
            return this._size;
        }
        set size(value) {
            this._size = value;
        }
        get orthogonalSize() {
            return this._orthogonalSize;
        }
        set orthogonalSize(value) {
            this._orthogonalSize = value;
        }
        get length() {
            return this.viewItems.length;
        }
        get proportions() {
            return this._proportions ? [...this._proportions] : undefined;
        }
        get orientation() {
            return this._orientation;
        }
        set orientation(value) {
            this._orientation = value;
            const tmp = this.size;
            this.size = this.orthogonalSize;
            this.orthogonalSize = tmp;
            removeClasses(this.element, 'dv-horizontal', 'dv-vertical');
            this.element.classList.add(this.orientation == exports.Orientation.HORIZONTAL
                ? 'dv-horizontal'
                : 'dv-vertical');
        }
        get minimumSize() {
            return this.viewItems.reduce((r, item) => r + item.minimumSize, 0);
        }
        get maximumSize() {
            return this.length === 0
                ? Number.POSITIVE_INFINITY
                : this.viewItems.reduce((r, item) => r + item.maximumSize, 0);
        }
        get startSnappingEnabled() {
            return this._startSnappingEnabled;
        }
        set startSnappingEnabled(startSnappingEnabled) {
            if (this._startSnappingEnabled === startSnappingEnabled) {
                return;
            }
            this._startSnappingEnabled = startSnappingEnabled;
            this.updateSashEnablement();
        }
        get endSnappingEnabled() {
            return this._endSnappingEnabled;
        }
        set endSnappingEnabled(endSnappingEnabled) {
            if (this._endSnappingEnabled === endSnappingEnabled) {
                return;
            }
            this._endSnappingEnabled = endSnappingEnabled;
            this.updateSashEnablement();
        }
        get disabled() {
            return this._disabled;
        }
        set disabled(value) {
            this._disabled = value;
            toggleClass(this.element, 'dv-splitview-disabled', value);
        }
        get margin() {
            return this._margin;
        }
        set margin(value) {
            this._margin = value;
            toggleClass(this.element, 'dv-splitview-has-margin', value !== 0);
        }
        constructor(container, options) {
            var _a, _b;
            this.container = container;
            this.viewItems = [];
            this.sashes = [];
            this._size = 0;
            this._orthogonalSize = 0;
            this._contentSize = 0;
            this._proportions = undefined;
            this._startSnappingEnabled = true;
            this._endSnappingEnabled = true;
            this._disabled = false;
            this._margin = 0;
            this._onDidSashEnd = new Emitter();
            this.onDidSashEnd = this._onDidSashEnd.event;
            this._onDidAddView = new Emitter();
            this.onDidAddView = this._onDidAddView.event;
            this._onDidRemoveView = new Emitter();
            this.onDidRemoveView = this._onDidRemoveView.event;
            this.resize = (index, delta, sizes = this.viewItems.map((x) => x.size), lowPriorityIndexes, highPriorityIndexes, overloadMinDelta = Number.NEGATIVE_INFINITY, overloadMaxDelta = Number.POSITIVE_INFINITY, snapBefore, snapAfter) => {
                if (index < 0 || index > this.viewItems.length) {
                    return 0;
                }
                const upIndexes = range(index, -1);
                const downIndexes = range(index + 1, this.viewItems.length);
                //
                if (highPriorityIndexes) {
                    for (const i of highPriorityIndexes) {
                        pushToStart(upIndexes, i);
                        pushToStart(downIndexes, i);
                    }
                }
                if (lowPriorityIndexes) {
                    for (const i of lowPriorityIndexes) {
                        pushToEnd(upIndexes, i);
                        pushToEnd(downIndexes, i);
                    }
                }
                //
                const upItems = upIndexes.map((i) => this.viewItems[i]);
                const upSizes = upIndexes.map((i) => sizes[i]);
                //
                const downItems = downIndexes.map((i) => this.viewItems[i]);
                const downSizes = downIndexes.map((i) => sizes[i]);
                //
                const minDeltaUp = upIndexes.reduce((_, i) => _ + this.viewItems[i].minimumSize - sizes[i], 0);
                const maxDeltaUp = upIndexes.reduce((_, i) => _ + this.viewItems[i].maximumSize - sizes[i], 0);
                //
                const maxDeltaDown = downIndexes.length === 0
                    ? Number.POSITIVE_INFINITY
                    : downIndexes.reduce((_, i) => _ + sizes[i] - this.viewItems[i].minimumSize, 0);
                const minDeltaDown = downIndexes.length === 0
                    ? Number.NEGATIVE_INFINITY
                    : downIndexes.reduce((_, i) => _ + sizes[i] - this.viewItems[i].maximumSize, 0);
                //
                const minDelta = Math.max(minDeltaUp, minDeltaDown);
                const maxDelta = Math.min(maxDeltaDown, maxDeltaUp);
                //
                let snapped = false;
                if (snapBefore) {
                    const snapView = this.viewItems[snapBefore.index];
                    const visible = delta >= snapBefore.limitDelta;
                    snapped = visible !== snapView.visible;
                    snapView.setVisible(visible, snapBefore.size);
                }
                if (!snapped && snapAfter) {
                    const snapView = this.viewItems[snapAfter.index];
                    const visible = delta < snapAfter.limitDelta;
                    snapped = visible !== snapView.visible;
                    snapView.setVisible(visible, snapAfter.size);
                }
                if (snapped) {
                    return this.resize(index, delta, sizes, lowPriorityIndexes, highPriorityIndexes, overloadMinDelta, overloadMaxDelta);
                }
                //
                const tentativeDelta = clamp(delta, minDelta, maxDelta);
                let actualDelta = 0;
                //
                let deltaUp = tentativeDelta;
                for (let i = 0; i < upItems.length; i++) {
                    const item = upItems[i];
                    const size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize);
                    const viewDelta = size - upSizes[i];
                    actualDelta += viewDelta;
                    deltaUp -= viewDelta;
                    item.size = size;
                }
                //
                let deltaDown = actualDelta;
                for (let i = 0; i < downItems.length; i++) {
                    const item = downItems[i];
                    const size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize);
                    const viewDelta = size - downSizes[i];
                    deltaDown += viewDelta;
                    item.size = size;
                }
                //
                return delta;
            };
            this._orientation = (_a = options.orientation) !== null && _a !== void 0 ? _a : exports.Orientation.VERTICAL;
            this.element = this.createContainer();
            this.margin = (_b = options.margin) !== null && _b !== void 0 ? _b : 0;
            this.proportionalLayout =
                options.proportionalLayout === undefined
                    ? true
                    : !!options.proportionalLayout;
            this.viewContainer = this.createViewContainer();
            this.sashContainer = this.createSashContainer();
            this.element.appendChild(this.sashContainer);
            this.element.appendChild(this.viewContainer);
            this.container.appendChild(this.element);
            this.style(options.styles);
            // We have an existing set of view, add them now
            if (options.descriptor) {
                this._size = options.descriptor.size;
                options.descriptor.views.forEach((viewDescriptor, index) => {
                    const sizing = viewDescriptor.visible === undefined ||
                        viewDescriptor.visible
                        ? viewDescriptor.size
                        : {
                            type: 'invisible',
                            cachedVisibleSize: viewDescriptor.size,
                        };
                    const view = viewDescriptor.view;
                    this.addView(view, sizing, index, true
                    // true skip layout
                    );
                });
                // Initialize content size and proportions for first layout
                this._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
                this.saveProportions();
            }
        }
        style(styles) {
            if ((styles === null || styles === void 0 ? void 0 : styles.separatorBorder) === 'transparent') {
                removeClasses(this.element, 'dv-separator-border');
                this.element.style.removeProperty('--dv-separator-border');
            }
            else {
                addClasses(this.element, 'dv-separator-border');
                if (styles === null || styles === void 0 ? void 0 : styles.separatorBorder) {
                    this.element.style.setProperty('--dv-separator-border', styles.separatorBorder);
                }
            }
        }
        isViewVisible(index) {
            if (index < 0 || index >= this.viewItems.length) {
                throw new Error('Index out of bounds');
            }
            const viewItem = this.viewItems[index];
            return viewItem.visible;
        }
        setViewVisible(index, visible) {
            if (index < 0 || index >= this.viewItems.length) {
                throw new Error('Index out of bounds');
            }
            const viewItem = this.viewItems[index];
            viewItem.setVisible(visible, viewItem.size);
            this.distributeEmptySpace(index);
            this.layoutViews();
            this.saveProportions();
        }
        getViewSize(index) {
            if (index < 0 || index >= this.viewItems.length) {
                return -1;
            }
            return this.viewItems[index].size;
        }
        resizeView(index, size) {
            if (index < 0 || index >= this.viewItems.length) {
                return;
            }
            const indexes = range(this.viewItems.length).filter((i) => i !== index);
            const lowPriorityIndexes = [
                ...indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.Low),
                index,
            ];
            const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.High);
            const item = this.viewItems[index];
            size = Math.round(size);
            size = clamp(size, item.minimumSize, Math.min(item.maximumSize, this._size));
            item.size = size;
            this.relayout(lowPriorityIndexes, highPriorityIndexes);
        }
        getViews() {
            return this.viewItems.map((x) => x.view);
        }
        onDidChange(item, size) {
            const index = this.viewItems.indexOf(item);
            if (index < 0 || index >= this.viewItems.length) {
                return;
            }
            size = typeof size === 'number' ? size : item.size;
            size = clamp(size, item.minimumSize, item.maximumSize);
            item.size = size;
            const indexes = range(this.viewItems.length).filter((i) => i !== index);
            const lowPriorityIndexes = [
                ...indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.Low),
                index,
            ];
            const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.High);
            /**
             * add this view we are changing to the low-index list since we have determined the size
             * here and don't want it changed
             */
            this.relayout([...lowPriorityIndexes, index], highPriorityIndexes);
        }
        addView(view, size = { type: 'distribute' }, index = this.viewItems.length, skipLayout) {
            const container = document.createElement('div');
            container.className = 'dv-view';
            container.appendChild(view.element);
            let viewSize;
            if (typeof size === 'number') {
                viewSize = size;
            }
            else if (size.type === 'split') {
                viewSize = this.getViewSize(size.index) / 2;
            }
            else if (size.type === 'invisible') {
                viewSize = { cachedVisibleSize: size.cachedVisibleSize };
            }
            else {
                viewSize = view.minimumSize;
            }
            const disposable = view.onDidChange((newSize) => this.onDidChange(viewItem, newSize.size));
            const viewItem = new ViewItem(container, view, viewSize, {
                dispose: () => {
                    disposable.dispose();
                    this.viewContainer.removeChild(container);
                },
            });
            if (index === this.viewItems.length) {
                this.viewContainer.appendChild(container);
            }
            else {
                this.viewContainer.insertBefore(container, this.viewContainer.children.item(index));
            }
            this.viewItems.splice(index, 0, viewItem);
            if (this.viewItems.length > 1) {
                //add sash
                const sash = document.createElement('div');
                sash.className = 'dv-sash';
                const onPointerStart = (event) => {
                    for (const item of this.viewItems) {
                        item.enabled = false;
                    }
                    const iframes = disableIframePointEvents();
                    const start = this._orientation === exports.Orientation.HORIZONTAL
                        ? event.clientX
                        : event.clientY;
                    const sashIndex = firstIndex(this.sashes, (s) => s.container === sash);
                    //
                    const sizes = this.viewItems.map((x) => x.size);
                    //
                    let snapBefore;
                    let snapAfter;
                    const upIndexes = range(sashIndex, -1);
                    const downIndexes = range(sashIndex + 1, this.viewItems.length);
                    const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);
                    const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].viewMaximumSize - sizes[i]), 0);
                    const maxDeltaDown = downIndexes.length === 0
                        ? Number.POSITIVE_INFINITY
                        : downIndexes.reduce((r, i) => r +
                            (sizes[i] - this.viewItems[i].minimumSize), 0);
                    const minDeltaDown = downIndexes.length === 0
                        ? Number.NEGATIVE_INFINITY
                        : downIndexes.reduce((r, i) => r +
                            (sizes[i] -
                                this.viewItems[i].viewMaximumSize), 0);
                    const minDelta = Math.max(minDeltaUp, minDeltaDown);
                    const maxDelta = Math.min(maxDeltaDown, maxDeltaUp);
                    const snapBeforeIndex = this.findFirstSnapIndex(upIndexes);
                    const snapAfterIndex = this.findFirstSnapIndex(downIndexes);
                    if (typeof snapBeforeIndex === 'number') {
                        const snappedViewItem = this.viewItems[snapBeforeIndex];
                        const halfSize = Math.floor(snappedViewItem.viewMinimumSize / 2);
                        snapBefore = {
                            index: snapBeforeIndex,
                            limitDelta: snappedViewItem.visible
                                ? minDelta - halfSize
                                : minDelta + halfSize,
                            size: snappedViewItem.size,
                        };
                    }
                    if (typeof snapAfterIndex === 'number') {
                        const snappedViewItem = this.viewItems[snapAfterIndex];
                        const halfSize = Math.floor(snappedViewItem.viewMinimumSize / 2);
                        snapAfter = {
                            index: snapAfterIndex,
                            limitDelta: snappedViewItem.visible
                                ? maxDelta + halfSize
                                : maxDelta - halfSize,
                            size: snappedViewItem.size,
                        };
                    }
                    const onPointerMove = (event) => {
                        const current = this._orientation === exports.Orientation.HORIZONTAL
                            ? event.clientX
                            : event.clientY;
                        const delta = current - start;
                        this.resize(sashIndex, delta, sizes, undefined, undefined, minDelta, maxDelta, snapBefore, snapAfter);
                        this.distributeEmptySpace();
                        this.layoutViews();
                    };
                    const end = () => {
                        for (const item of this.viewItems) {
                            item.enabled = true;
                        }
                        iframes.release();
                        this.saveProportions();
                        document.removeEventListener('pointermove', onPointerMove);
                        document.removeEventListener('pointerup', end);
                        document.removeEventListener('pointercancel', end);
                        this._onDidSashEnd.fire(undefined);
                    };
                    document.addEventListener('pointermove', onPointerMove);
                    document.addEventListener('pointerup', end);
                    document.addEventListener('pointercancel', end);
                };
                sash.addEventListener('pointerdown', onPointerStart);
                const sashItem = {
                    container: sash,
                    disposable: () => {
                        sash.removeEventListener('pointerdown', onPointerStart);
                        this.sashContainer.removeChild(sash);
                    },
                };
                this.sashContainer.appendChild(sash);
                this.sashes.push(sashItem);
            }
            if (!skipLayout) {
                this.relayout([index]);
            }
            if (!skipLayout &&
                typeof size !== 'number' &&
                size.type === 'distribute') {
                this.distributeViewSizes();
            }
            this._onDidAddView.fire(view);
        }
        distributeViewSizes() {
            const flexibleViewItems = [];
            let flexibleSize = 0;
            for (const item of this.viewItems) {
                if (item.maximumSize - item.minimumSize > 0) {
                    flexibleViewItems.push(item);
                    flexibleSize += item.size;
                }
            }
            const size = Math.floor(flexibleSize / flexibleViewItems.length);
            for (const item of flexibleViewItems) {
                item.size = clamp(size, item.minimumSize, item.maximumSize);
            }
            const indexes = range(this.viewItems.length);
            const lowPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.Low);
            const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.High);
            this.relayout(lowPriorityIndexes, highPriorityIndexes);
        }
        removeView(index, sizing, skipLayout = false) {
            // Remove view
            const viewItem = this.viewItems.splice(index, 1)[0];
            viewItem.dispose();
            // Remove sash
            if (this.viewItems.length >= 1) {
                const sashIndex = Math.max(index - 1, 0);
                const sashItem = this.sashes.splice(sashIndex, 1)[0];
                sashItem.disposable();
            }
            if (!skipLayout) {
                this.relayout();
            }
            if (sizing && sizing.type === 'distribute') {
                this.distributeViewSizes();
            }
            this._onDidRemoveView.fire(viewItem.view);
            return viewItem.view;
        }
        getViewCachedVisibleSize(index) {
            if (index < 0 || index >= this.viewItems.length) {
                throw new Error('Index out of bounds');
            }
            const viewItem = this.viewItems[index];
            return viewItem.cachedVisibleSize;
        }
        moveView(from, to) {
            const cachedVisibleSize = this.getViewCachedVisibleSize(from);
            const sizing = typeof cachedVisibleSize === 'undefined'
                ? this.getViewSize(from)
                : exports.Sizing.Invisible(cachedVisibleSize);
            const view = this.removeView(from, undefined, true);
            this.addView(view, sizing, to);
        }
        layout(size, orthogonalSize) {
            const previousSize = Math.max(this.size, this._contentSize);
            this.size = size;
            this.orthogonalSize = orthogonalSize;
            if (!this.proportions) {
                const indexes = range(this.viewItems.length);
                const lowPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.Low);
                const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.High);
                this.resize(this.viewItems.length - 1, size - previousSize, undefined, lowPriorityIndexes, highPriorityIndexes);
            }
            else {
                let total = 0;
                for (let i = 0; i < this.viewItems.length; i++) {
                    const item = this.viewItems[i];
                    const proportion = this.proportions[i];
                    if (typeof proportion === 'number') {
                        total += proportion;
                    }
                    else {
                        size -= item.size;
                    }
                }
                for (let i = 0; i < this.viewItems.length; i++) {
                    const item = this.viewItems[i];
                    const proportion = this.proportions[i];
                    if (typeof proportion === 'number' && total > 0) {
                        item.size = clamp(Math.round((proportion * size) / total), item.minimumSize, item.maximumSize);
                    }
                }
            }
            this.distributeEmptySpace();
            this.layoutViews();
        }
        relayout(lowPriorityIndexes, highPriorityIndexes) {
            const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
            this.resize(this.viewItems.length - 1, this._size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes);
            this.distributeEmptySpace();
            this.layoutViews();
            this.saveProportions();
        }
        distributeEmptySpace(lowPriorityIndex) {
            const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
            let emptyDelta = this.size - contentSize;
            const indexes = range(this.viewItems.length - 1, -1);
            const lowPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.Low);
            const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.High);
            for (const index of highPriorityIndexes) {
                pushToStart(indexes, index);
            }
            for (const index of lowPriorityIndexes) {
                pushToEnd(indexes, index);
            }
            if (typeof lowPriorityIndex === 'number') {
                pushToEnd(indexes, lowPriorityIndex);
            }
            for (let i = 0; emptyDelta !== 0 && i < indexes.length; i++) {
                const item = this.viewItems[indexes[i]];
                const size = clamp(item.size + emptyDelta, item.minimumSize, item.maximumSize);
                const viewDelta = size - item.size;
                emptyDelta -= viewDelta;
                item.size = size;
            }
        }
        saveProportions() {
            if (this.proportionalLayout && this._contentSize > 0) {
                this._proportions = this.viewItems.map((i) => i.visible ? i.size / this._contentSize : undefined);
            }
        }
        /**
         * Margin explain:
         *
         * For `n` views in a splitview there will be `n-1` margins `m`.
         *
         * To fit the margins each view must reduce in size by `(m * (n - 1)) / n`.
         *
         * For each view `i` the offet must be adjusted by `m * i/(n - 1)`.
         */
        layoutViews() {
            this._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
            this.updateSashEnablement();
            if (this.viewItems.length === 0) {
                return;
            }
            const visibleViewItems = this.viewItems.filter((i) => i.visible);
            const sashCount = Math.max(0, visibleViewItems.length - 1);
            const marginReducedSize = (this.margin * sashCount) / Math.max(1, visibleViewItems.length);
            let totalLeftOffset = 0;
            const viewLeftOffsets = [];
            const sashWidth = 4; // hardcoded in css
            const runningVisiblePanelCount = this.viewItems.reduce((arr, viewItem, i) => {
                const flag = viewItem.visible ? 1 : 0;
                if (i === 0) {
                    arr.push(flag);
                }
                else {
                    arr.push(arr[i - 1] + flag);
                }
                return arr;
            }, []);
            // calculate both view and cash positions
            this.viewItems.forEach((view, i) => {
                totalLeftOffset += this.viewItems[i].size;
                viewLeftOffsets.push(totalLeftOffset);
                const size = view.visible ? view.size - marginReducedSize : 0;
                const visiblePanelsBeforeThisView = Math.max(0, runningVisiblePanelCount[i] - 1);
                const offset = i === 0 || visiblePanelsBeforeThisView === 0
                    ? 0
                    : viewLeftOffsets[i - 1] +
                        (visiblePanelsBeforeThisView / sashCount) *
                            marginReducedSize;
                if (i < this.viewItems.length - 1) {
                    // calculate sash position
                    const newSize = view.visible
                        ? offset + size - sashWidth / 2 + this.margin / 2
                        : offset;
                    if (this._orientation === exports.Orientation.HORIZONTAL) {
                        this.sashes[i].container.style.left = `${newSize}px`;
                        this.sashes[i].container.style.top = `0px`;
                    }
                    if (this._orientation === exports.Orientation.VERTICAL) {
                        this.sashes[i].container.style.left = `0px`;
                        this.sashes[i].container.style.top = `${newSize}px`;
                    }
                }
                // calculate view position
                if (this._orientation === exports.Orientation.HORIZONTAL) {
                    view.container.style.width = `${size}px`;
                    view.container.style.left = `${offset}px`;
                    view.container.style.top = '';
                    view.container.style.height = '';
                }
                if (this._orientation === exports.Orientation.VERTICAL) {
                    view.container.style.height = `${size}px`;
                    view.container.style.top = `${offset}px`;
                    view.container.style.width = '';
                    view.container.style.left = '';
                }
                view.view.layout(view.size - marginReducedSize, this._orthogonalSize);
            });
        }
        findFirstSnapIndex(indexes) {
            // visible views first
            for (const index of indexes) {
                const viewItem = this.viewItems[index];
                if (!viewItem.visible) {
                    continue;
                }
                if (viewItem.snap) {
                    return index;
                }
            }
            // then, hidden views
            for (const index of indexes) {
                const viewItem = this.viewItems[index];
                if (viewItem.visible &&
                    viewItem.maximumSize - viewItem.minimumSize > 0) {
                    return undefined;
                }
                if (!viewItem.visible && viewItem.snap) {
                    return index;
                }
            }
            return undefined;
        }
        updateSashEnablement() {
            let previous = false;
            const collapsesDown = this.viewItems.map((i) => (previous = i.size - i.minimumSize > 0 || previous));
            previous = false;
            const expandsDown = this.viewItems.map((i) => (previous = i.maximumSize - i.size > 0 || previous));
            const reverseViews = [...this.viewItems].reverse();
            previous = false;
            const collapsesUp = reverseViews
                .map((i) => (previous = i.size - i.minimumSize > 0 || previous))
                .reverse();
            previous = false;
            const expandsUp = reverseViews
                .map((i) => (previous = i.maximumSize - i.size > 0 || previous))
                .reverse();
            let position = 0;
            for (let index = 0; index < this.sashes.length; index++) {
                const sash = this.sashes[index];
                const viewItem = this.viewItems[index];
                position += viewItem.size;
                const min = !(collapsesDown[index] && expandsUp[index + 1]);
                const max = !(expandsDown[index] && collapsesUp[index + 1]);
                if (min && max) {
                    const upIndexes = range(index, -1);
                    const downIndexes = range(index + 1, this.viewItems.length);
                    const snapBeforeIndex = this.findFirstSnapIndex(upIndexes);
                    const snapAfterIndex = this.findFirstSnapIndex(downIndexes);
                    const snappedBefore = typeof snapBeforeIndex === 'number' &&
                        !this.viewItems[snapBeforeIndex].visible;
                    const snappedAfter = typeof snapAfterIndex === 'number' &&
                        !this.viewItems[snapAfterIndex].visible;
                    if (snappedBefore &&
                        collapsesUp[index] &&
                        (position > 0 || this.startSnappingEnabled)) {
                        this.updateSash(sash, exports.SashState.MINIMUM);
                    }
                    else if (snappedAfter &&
                        collapsesDown[index] &&
                        (position < this._contentSize || this.endSnappingEnabled)) {
                        this.updateSash(sash, exports.SashState.MAXIMUM);
                    }
                    else {
                        this.updateSash(sash, exports.SashState.DISABLED);
                    }
                }
                else if (min && !max) {
                    this.updateSash(sash, exports.SashState.MINIMUM);
                }
                else if (!min && max) {
                    this.updateSash(sash, exports.SashState.MAXIMUM);
                }
                else {
                    this.updateSash(sash, exports.SashState.ENABLED);
                }
            }
        }
        updateSash(sash, state) {
            toggleClass(sash.container, 'dv-disabled', state === exports.SashState.DISABLED);
            toggleClass(sash.container, 'dv-enabled', state === exports.SashState.ENABLED);
            toggleClass(sash.container, 'dv-maximum', state === exports.SashState.MAXIMUM);
            toggleClass(sash.container, 'dv-minimum', state === exports.SashState.MINIMUM);
        }
        createViewContainer() {
            const element = document.createElement('div');
            element.className = 'dv-view-container';
            return element;
        }
        createSashContainer() {
            const element = document.createElement('div');
            element.className = 'dv-sash-container';
            return element;
        }
        createContainer() {
            const element = document.createElement('div');
            const orientationClassname = this._orientation === exports.Orientation.HORIZONTAL
                ? 'dv-horizontal'
                : 'dv-vertical';
            element.className = `dv-split-view-container ${orientationClassname}`;
            return element;
        }
        dispose() {
            this._onDidSashEnd.dispose();
            this._onDidAddView.dispose();
            this._onDidRemoveView.dispose();
            for (let i = 0; i < this.element.children.length; i++) {
                if (this.element.children.item(i) === this.element) {
                    this.element.removeChild(this.element);
                    break;
                }
            }
            for (const viewItem of this.viewItems) {
                viewItem.dispose();
            }
            this.element.remove();
        }
    }

    const PROPERTY_KEYS_SPLITVIEW = (() => {
        /**
         * by readong the keys from an empty value object TypeScript will error
         * when we add or remove new properties to `DockviewOptions`
         */
        const properties = {
            orientation: undefined,
            descriptor: undefined,
            proportionalLayout: undefined,
            styles: undefined,
            margin: undefined,
            disableAutoResizing: undefined,
            className: undefined,
        };
        return Object.keys(properties);
    })();

    class Paneview extends CompositeDisposable {
        get onDidAddView() {
            return this.splitview.onDidAddView;
        }
        get onDidRemoveView() {
            return this.splitview.onDidRemoveView;
        }
        get minimumSize() {
            return this.splitview.minimumSize;
        }
        get maximumSize() {
            return this.splitview.maximumSize;
        }
        get orientation() {
            return this.splitview.orientation;
        }
        get size() {
            return this.splitview.size;
        }
        get orthogonalSize() {
            return this.splitview.orthogonalSize;
        }
        constructor(container, options) {
            var _a;
            super();
            this.paneItems = [];
            this.skipAnimation = false;
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            this._orientation = (_a = options.orientation) !== null && _a !== void 0 ? _a : exports.Orientation.VERTICAL;
            this.element = document.createElement('div');
            this.element.className = 'dv-pane-container';
            container.appendChild(this.element);
            this.splitview = new Splitview(this.element, {
                orientation: this._orientation,
                proportionalLayout: false,
                descriptor: options.descriptor,
            });
            // if we've added views from the descriptor we need to
            // add the panes to our Pane array and setup animation
            this.getPanes().forEach((pane) => {
                const disposable = new CompositeDisposable(pane.onDidChangeExpansionState(() => {
                    this.setupAnimation();
                    this._onDidChange.fire(undefined);
                }));
                const paneItem = {
                    pane,
                    disposable: {
                        dispose: () => {
                            disposable.dispose();
                        },
                    },
                };
                this.paneItems.push(paneItem);
                pane.orthogonalSize = this.splitview.orthogonalSize;
            });
            this.addDisposables(this._onDidChange, this.splitview.onDidSashEnd(() => {
                this._onDidChange.fire(undefined);
            }), this.splitview.onDidAddView(() => {
                this._onDidChange.fire();
            }), this.splitview.onDidRemoveView(() => {
                this._onDidChange.fire();
            }));
        }
        setViewVisible(index, visible) {
            this.splitview.setViewVisible(index, visible);
        }
        addPane(pane, size, index = this.splitview.length, skipLayout = false) {
            const disposable = pane.onDidChangeExpansionState(() => {
                this.setupAnimation();
                this._onDidChange.fire(undefined);
            });
            const paneItem = {
                pane,
                disposable: {
                    dispose: () => {
                        disposable.dispose();
                    },
                },
            };
            this.paneItems.splice(index, 0, paneItem);
            pane.orthogonalSize = this.splitview.orthogonalSize;
            this.splitview.addView(pane, size, index, skipLayout);
        }
        getViewSize(index) {
            return this.splitview.getViewSize(index);
        }
        getPanes() {
            return this.splitview.getViews();
        }
        removePane(index, options = { skipDispose: false }) {
            const paneItem = this.paneItems.splice(index, 1)[0];
            this.splitview.removeView(index);
            if (!options.skipDispose) {
                paneItem.disposable.dispose();
                paneItem.pane.dispose();
            }
            return paneItem;
        }
        moveView(from, to) {
            if (from === to) {
                return;
            }
            const view = this.removePane(from, { skipDispose: true });
            this.skipAnimation = true;
            try {
                this.addPane(view.pane, view.pane.size, to, false);
            }
            finally {
                this.skipAnimation = false;
            }
        }
        layout(size, orthogonalSize) {
            this.splitview.layout(size, orthogonalSize);
        }
        setupAnimation() {
            if (this.skipAnimation) {
                return;
            }
            if (this.animationTimer) {
                clearTimeout(this.animationTimer);
                this.animationTimer = undefined;
            }
            addClasses(this.element, 'dv-animated');
            this.animationTimer = setTimeout(() => {
                this.animationTimer = undefined;
                removeClasses(this.element, 'dv-animated');
            }, 200);
        }
        dispose() {
            super.dispose();
            if (this.animationTimer) {
                clearTimeout(this.animationTimer);
                this.animationTimer = undefined;
            }
            this.paneItems.forEach((paneItem) => {
                paneItem.disposable.dispose();
                paneItem.pane.dispose();
            });
            this.paneItems = [];
            this.splitview.dispose();
            this.element.remove();
        }
    }

    /*---------------------------------------------------------------------------------------------
     * Accreditation: This file is largly based upon the MIT licenced VSCode sourcecode found at:
     * https://github.com/microsoft/vscode/tree/main/src/vs/base/browser/ui/grid
     *--------------------------------------------------------------------------------------------*/
    class LeafNode {
        get minimumWidth() {
            return this.view.minimumWidth;
        }
        get maximumWidth() {
            return this.view.maximumWidth;
        }
        get minimumHeight() {
            return this.view.minimumHeight;
        }
        get maximumHeight() {
            return this.view.maximumHeight;
        }
        get priority() {
            return this.view.priority;
        }
        get snap() {
            return this.view.snap;
        }
        get minimumSize() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.minimumHeight
                : this.minimumWidth;
        }
        get maximumSize() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.maximumHeight
                : this.maximumWidth;
        }
        get minimumOrthogonalSize() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.minimumWidth
                : this.minimumHeight;
        }
        get maximumOrthogonalSize() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.maximumWidth
                : this.maximumHeight;
        }
        get orthogonalSize() {
            return this._orthogonalSize;
        }
        get size() {
            return this._size;
        }
        get element() {
            return this.view.element;
        }
        get width() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.orthogonalSize
                : this.size;
        }
        get height() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.size
                : this.orthogonalSize;
        }
        constructor(view, orientation, orthogonalSize, size = 0) {
            this.view = view;
            this.orientation = orientation;
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            this._orthogonalSize = orthogonalSize;
            this._size = size;
            this._disposable = this.view.onDidChange((event) => {
                if (event) {
                    this._onDidChange.fire({
                        size: this.orientation === exports.Orientation.VERTICAL
                            ? event.width
                            : event.height,
                        orthogonalSize: this.orientation === exports.Orientation.VERTICAL
                            ? event.height
                            : event.width,
                    });
                }
                else {
                    this._onDidChange.fire({});
                }
            });
        }
        setVisible(visible) {
            if (this.view.setVisible) {
                this.view.setVisible(visible);
            }
        }
        layout(size, orthogonalSize) {
            this._size = size;
            this._orthogonalSize = orthogonalSize;
            this.view.layout(this.width, this.height);
        }
        dispose() {
            this._onDidChange.dispose();
            this._disposable.dispose();
        }
    }

    /*---------------------------------------------------------------------------------------------
     * Accreditation: This file is largly based upon the MIT licenced VSCode sourcecode found at:
     * https://github.com/microsoft/vscode/tree/main/src/vs/base/browser/ui/grid
     *--------------------------------------------------------------------------------------------*/
    class BranchNode extends CompositeDisposable {
        get width() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.size
                : this.orthogonalSize;
        }
        get height() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.orthogonalSize
                : this.size;
        }
        get minimumSize() {
            return this.children.length === 0
                ? 0
                : Math.max(...this.children.map((c, index) => this.splitview.isViewVisible(index)
                    ? c.minimumOrthogonalSize
                    : 0));
        }
        get maximumSize() {
            return Math.min(...this.children.map((c, index) => this.splitview.isViewVisible(index)
                ? c.maximumOrthogonalSize
                : Number.POSITIVE_INFINITY));
        }
        get minimumOrthogonalSize() {
            return this.splitview.minimumSize;
        }
        get maximumOrthogonalSize() {
            return this.splitview.maximumSize;
        }
        get orthogonalSize() {
            return this._orthogonalSize;
        }
        get size() {
            return this._size;
        }
        get minimumWidth() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.minimumOrthogonalSize
                : this.minimumSize;
        }
        get minimumHeight() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.minimumSize
                : this.minimumOrthogonalSize;
        }
        get maximumWidth() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.maximumOrthogonalSize
                : this.maximumSize;
        }
        get maximumHeight() {
            return this.orientation === exports.Orientation.HORIZONTAL
                ? this.maximumSize
                : this.maximumOrthogonalSize;
        }
        get priority() {
            if (this.children.length === 0) {
                return exports.LayoutPriority.Normal;
            }
            const priorities = this.children.map((c) => typeof c.priority === 'undefined'
                ? exports.LayoutPriority.Normal
                : c.priority);
            if (priorities.some((p) => p === exports.LayoutPriority.High)) {
                return exports.LayoutPriority.High;
            }
            else if (priorities.some((p) => p === exports.LayoutPriority.Low)) {
                return exports.LayoutPriority.Low;
            }
            return exports.LayoutPriority.Normal;
        }
        get disabled() {
            return this.splitview.disabled;
        }
        set disabled(value) {
            this.splitview.disabled = value;
        }
        get margin() {
            return this.splitview.margin;
        }
        set margin(value) {
            this.splitview.margin = value;
            this.children.forEach((child) => {
                if (child instanceof BranchNode) {
                    child.margin = value;
                }
            });
        }
        constructor(orientation, proportionalLayout, styles, size, orthogonalSize, disabled, margin, childDescriptors) {
            super();
            this.orientation = orientation;
            this.proportionalLayout = proportionalLayout;
            this.styles = styles;
            this._childrenDisposable = exports.DockviewDisposable.NONE;
            this.children = [];
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            this._onDidVisibilityChange = new Emitter();
            this.onDidVisibilityChange = this._onDidVisibilityChange.event;
            this._orthogonalSize = orthogonalSize;
            this._size = size;
            this.element = document.createElement('div');
            this.element.className = 'dv-branch-node';
            if (!childDescriptors) {
                this.splitview = new Splitview(this.element, {
                    orientation: this.orientation,
                    proportionalLayout,
                    styles,
                    margin,
                });
                this.splitview.layout(this.size, this.orthogonalSize);
            }
            else {
                const descriptor = {
                    views: childDescriptors.map((childDescriptor) => {
                        return {
                            view: childDescriptor.node,
                            size: childDescriptor.node.size,
                            visible: childDescriptor.node instanceof LeafNode &&
                                childDescriptor.visible !== undefined
                                ? childDescriptor.visible
                                : true,
                        };
                    }),
                    size: this.orthogonalSize,
                };
                this.children = childDescriptors.map((c) => c.node);
                this.splitview = new Splitview(this.element, {
                    orientation: this.orientation,
                    descriptor,
                    proportionalLayout,
                    styles,
                    margin,
                });
            }
            this.disabled = disabled;
            this.addDisposables(this._onDidChange, this._onDidVisibilityChange, this.splitview.onDidSashEnd(() => {
                this._onDidChange.fire({});
            }));
            this.setupChildrenEvents();
        }
        setVisible(_visible) {
            // noop
        }
        isChildVisible(index) {
            if (index < 0 || index >= this.children.length) {
                throw new Error('Invalid index');
            }
            return this.splitview.isViewVisible(index);
        }
        setChildVisible(index, visible) {
            if (index < 0 || index >= this.children.length) {
                throw new Error('Invalid index');
            }
            if (this.splitview.isViewVisible(index) === visible) {
                return;
            }
            const wereAllChildrenHidden = this.splitview.contentSize === 0;
            this.splitview.setViewVisible(index, visible);
            // }
            const areAllChildrenHidden = this.splitview.contentSize === 0;
            // If all children are hidden then the parent should hide the entire splitview
            // If the entire splitview is hidden then the parent should show the splitview when a child is shown
            if ((visible && wereAllChildrenHidden) ||
                (!visible && areAllChildrenHidden)) {
                this._onDidVisibilityChange.fire({ visible });
            }
        }
        moveChild(from, to) {
            if (from === to) {
                return;
            }
            if (from < 0 || from >= this.children.length) {
                throw new Error('Invalid from index');
            }
            if (from < to) {
                to--;
            }
            this.splitview.moveView(from, to);
            const child = this._removeChild(from);
            this._addChild(child, to);
        }
        getChildSize(index) {
            if (index < 0 || index >= this.children.length) {
                throw new Error('Invalid index');
            }
            return this.splitview.getViewSize(index);
        }
        resizeChild(index, size) {
            if (index < 0 || index >= this.children.length) {
                throw new Error('Invalid index');
            }
            this.splitview.resizeView(index, size);
        }
        layout(size, orthogonalSize) {
            this._size = orthogonalSize;
            this._orthogonalSize = size;
            this.splitview.layout(orthogonalSize, size);
        }
        addChild(node, size, index, skipLayout) {
            if (index < 0 || index > this.children.length) {
                throw new Error('Invalid index');
            }
            this.splitview.addView(node, size, index, skipLayout);
            this._addChild(node, index);
        }
        getChildCachedVisibleSize(index) {
            if (index < 0 || index >= this.children.length) {
                throw new Error('Invalid index');
            }
            return this.splitview.getViewCachedVisibleSize(index);
        }
        removeChild(index, sizing) {
            if (index < 0 || index >= this.children.length) {
                throw new Error('Invalid index');
            }
            this.splitview.removeView(index, sizing);
            return this._removeChild(index);
        }
        _addChild(node, index) {
            this.children.splice(index, 0, node);
            this.setupChildrenEvents();
        }
        _removeChild(index) {
            const [child] = this.children.splice(index, 1);
            this.setupChildrenEvents();
            return child;
        }
        setupChildrenEvents() {
            this._childrenDisposable.dispose();
            this._childrenDisposable = new CompositeDisposable(exports.DockviewEvent.any(...this.children.map((c) => c.onDidChange))((e) => {
                /**
                 * indicate a change has occured to allows any re-rendering but don't bubble
                 * event because that was specific to this branch
                 */
                this._onDidChange.fire({ size: e.orthogonalSize });
            }), ...this.children.map((c, i) => {
                if (c instanceof BranchNode) {
                    return c.onDidVisibilityChange(({ visible }) => {
                        this.setChildVisible(i, visible);
                    });
                }
                return exports.DockviewDisposable.NONE;
            }));
        }
        dispose() {
            this._childrenDisposable.dispose();
            this.splitview.dispose();
            this.children.forEach((child) => child.dispose());
            super.dispose();
        }
    }

    /*---------------------------------------------------------------------------------------------
     * Accreditation: This file is largly based upon the MIT licenced VSCode sourcecode found at:
     * https://github.com/microsoft/vscode/tree/main/src/vs/base/browser/ui/grid
     *--------------------------------------------------------------------------------------------*/
    function findLeaf(candiateNode, last) {
        if (candiateNode instanceof LeafNode) {
            return candiateNode;
        }
        if (candiateNode instanceof BranchNode) {
            return findLeaf(candiateNode.children[last ? candiateNode.children.length - 1 : 0], last);
        }
        throw new Error('invalid node');
    }
    function flipNode(node, size, orthogonalSize) {
        if (node instanceof BranchNode) {
            const result = new BranchNode(orthogonal(node.orientation), node.proportionalLayout, node.styles, size, orthogonalSize, node.disabled, node.margin);
            let totalSize = 0;
            for (let i = node.children.length - 1; i >= 0; i--) {
                const child = node.children[i];
                const childSize = child instanceof BranchNode ? child.orthogonalSize : child.size;
                let newSize = node.size === 0
                    ? 0
                    : Math.round((size * childSize) / node.size);
                totalSize += newSize;
                // The last view to add should adjust to rounding errors
                if (i === 0) {
                    newSize += size - totalSize;
                }
                result.addChild(flipNode(child, orthogonalSize, newSize), newSize, 0, true);
            }
            return result;
        }
        else {
            return new LeafNode(node.view, orthogonal(node.orientation), orthogonalSize);
        }
    }
    function indexInParent(element) {
        const parentElement = element.parentElement;
        if (!parentElement) {
            throw new Error('Invalid grid element');
        }
        let el = parentElement.firstElementChild;
        let index = 0;
        while (el !== element && el !== parentElement.lastElementChild && el) {
            el = el.nextElementSibling;
            index++;
        }
        return index;
    }
    /**
     * Find the grid location of a specific DOM element by traversing the parent
     * chain and finding each child index on the way.
     *
     * This will break as soon as DOM structures of the Splitview or Gridview change.
     */
    function getGridLocation(element) {
        const parentElement = element.parentElement;
        if (!parentElement) {
            throw new Error('Invalid grid element');
        }
        if (/\bdv-grid-view\b/.test(parentElement.className)) {
            return [];
        }
        const index = indexInParent(parentElement);
        const ancestor = parentElement.parentElement.parentElement.parentElement;
        return [...getGridLocation(ancestor), index];
    }
    function getRelativeLocation(rootOrientation, location, direction) {
        const orientation = getLocationOrientation(rootOrientation, location);
        const directionOrientation = getDirectionOrientation(direction);
        if (orientation === directionOrientation) {
            const [rest, _index] = tail(location);
            let index = _index;
            if (direction === 'right' || direction === 'bottom') {
                index += 1;
            }
            return [...rest, index];
        }
        else {
            const index = direction === 'right' || direction === 'bottom' ? 1 : 0;
            return [...location, index];
        }
    }
    function getDirectionOrientation(direction) {
        return direction === 'top' || direction === 'bottom'
            ? exports.Orientation.VERTICAL
            : exports.Orientation.HORIZONTAL;
    }
    function getLocationOrientation(rootOrientation, location) {
        return location.length % 2 === 0
            ? orthogonal(rootOrientation)
            : rootOrientation;
    }
    const orthogonal = (orientation) => orientation === exports.Orientation.HORIZONTAL
        ? exports.Orientation.VERTICAL
        : exports.Orientation.HORIZONTAL;
    function isGridBranchNode(node) {
        return !!node.children;
    }
    const serializeBranchNode = (node, orientation) => {
        const size = orientation === exports.Orientation.VERTICAL ? node.box.width : node.box.height;
        if (!isGridBranchNode(node)) {
            if (typeof node.cachedVisibleSize === 'number') {
                return {
                    type: 'leaf',
                    data: node.view.toJSON(),
                    size: node.cachedVisibleSize,
                    visible: false,
                };
            }
            return { type: 'leaf', data: node.view.toJSON(), size };
        }
        return {
            type: 'branch',
            data: node.children.map((c) => serializeBranchNode(c, orthogonal(orientation))),
            size,
        };
    };
    class Gridview {
        get length() {
            return this._root ? this._root.children.length : 0;
        }
        get orientation() {
            return this.root.orientation;
        }
        set orientation(orientation) {
            if (this.root.orientation === orientation) {
                return;
            }
            const { size, orthogonalSize } = this.root;
            this.root = flipNode(this.root, orthogonalSize, size);
            this.root.layout(size, orthogonalSize);
        }
        get width() {
            return this.root.width;
        }
        get height() {
            return this.root.height;
        }
        get minimumWidth() {
            return this.root.minimumWidth;
        }
        get minimumHeight() {
            return this.root.minimumHeight;
        }
        get maximumWidth() {
            return this.root.maximumHeight;
        }
        get maximumHeight() {
            return this.root.maximumHeight;
        }
        get locked() {
            return this._locked;
        }
        set locked(value) {
            this._locked = value;
            const branch = [this.root];
            /**
             * simple depth-first-search to cover all nodes
             *
             * @see https://en.wikipedia.org/wiki/Depth-first_search
             */
            while (branch.length > 0) {
                const node = branch.pop();
                if (node instanceof BranchNode) {
                    node.disabled = value;
                    branch.push(...node.children);
                }
            }
        }
        get margin() {
            return this._margin;
        }
        set margin(value) {
            this._margin = value;
            this.root.margin = value;
        }
        maximizedView() {
            var _a;
            return (_a = this._maximizedNode) === null || _a === void 0 ? void 0 : _a.leaf.view;
        }
        hasMaximizedView() {
            return this._maximizedNode !== undefined;
        }
        maximizeView(view) {
            var _a;
            const location = getGridLocation(view.element);
            const [_, node] = this.getNode(location);
            if (!(node instanceof LeafNode)) {
                return;
            }
            if (((_a = this._maximizedNode) === null || _a === void 0 ? void 0 : _a.leaf) === node) {
                return;
            }
            if (this.hasMaximizedView()) {
                this.exitMaximizedView();
            }
            serializeBranchNode(this.getView(), this.orientation);
            const hiddenOnMaximize = [];
            function hideAllViewsBut(parent, exclude) {
                for (let i = 0; i < parent.children.length; i++) {
                    const child = parent.children[i];
                    if (child instanceof LeafNode) {
                        if (child !== exclude) {
                            if (parent.isChildVisible(i)) {
                                parent.setChildVisible(i, false);
                            }
                            else {
                                hiddenOnMaximize.push(child);
                            }
                        }
                    }
                    else {
                        hideAllViewsBut(child, exclude);
                    }
                }
            }
            hideAllViewsBut(this.root, node);
            this._maximizedNode = { leaf: node, hiddenOnMaximize };
            this._onDidMaximizedNodeChange.fire({
                view: node.view,
                isMaximized: true,
            });
        }
        exitMaximizedView() {
            if (!this._maximizedNode) {
                return;
            }
            const hiddenOnMaximize = this._maximizedNode.hiddenOnMaximize;
            function showViewsInReverseOrder(parent) {
                for (let index = parent.children.length - 1; index >= 0; index--) {
                    const child = parent.children[index];
                    if (child instanceof LeafNode) {
                        if (!hiddenOnMaximize.includes(child)) {
                            parent.setChildVisible(index, true);
                        }
                    }
                    else {
                        showViewsInReverseOrder(child);
                    }
                }
            }
            showViewsInReverseOrder(this.root);
            const tmp = this._maximizedNode.leaf;
            this._maximizedNode = undefined;
            this._onDidMaximizedNodeChange.fire({
                view: tmp.view,
                isMaximized: false,
            });
        }
        serialize() {
            const maximizedView = this.maximizedView();
            let maxmizedViewLocation;
            if (maximizedView) {
                /**
                 * The minimum information we can get away with in order to serialize a maxmized view is it's location within the grid
                 * which is represented as a branch of indices
                 */
                maxmizedViewLocation = getGridLocation(maximizedView.element);
            }
            if (this.hasMaximizedView()) {
                /**
                 * the saved layout cannot be in its maxmized state otherwise all of the underlying
                 * view dimensions will be wrong
                 *
                 * To counteract this we temporaily remove the maximized view to compute the serialized output
                 * of the grid before adding back the maxmized view as to not alter the layout from the users
                 * perspective when `.toJSON()` is called
                 */
                this.exitMaximizedView();
            }
            const root = serializeBranchNode(this.getView(), this.orientation);
            const resullt = {
                root,
                width: this.width,
                height: this.height,
                orientation: this.orientation,
            };
            if (maxmizedViewLocation) {
                resullt.maximizedNode = {
                    location: maxmizedViewLocation,
                };
            }
            if (maximizedView) {
                // replace any maximzied view that was removed for serialization purposes
                this.maximizeView(maximizedView);
            }
            return resullt;
        }
        dispose() {
            this.disposable.dispose();
            this._onDidChange.dispose();
            this._onDidMaximizedNodeChange.dispose();
            this._onDidViewVisibilityChange.dispose();
            this.root.dispose();
            this._maximizedNode = undefined;
            this.element.remove();
        }
        clear() {
            const orientation = this.root.orientation;
            this.root = new BranchNode(orientation, this.proportionalLayout, this.styles, this.root.size, this.root.orthogonalSize, this.locked, this.margin);
        }
        deserialize(json, deserializer) {
            const orientation = json.orientation;
            const height = orientation === exports.Orientation.VERTICAL ? json.height : json.width;
            this._deserialize(json.root, orientation, deserializer, height);
            /**
             * The deserialied layout must be positioned through this.layout(...)
             * before any maximizedNode can be positioned
             */
            this.layout(json.width, json.height);
            if (json.maximizedNode) {
                const location = json.maximizedNode.location;
                const [_, node] = this.getNode(location);
                if (!(node instanceof LeafNode)) {
                    return;
                }
                this.maximizeView(node.view);
            }
        }
        _deserialize(root, orientation, deserializer, orthogonalSize) {
            this.root = this._deserializeNode(root, orientation, deserializer, orthogonalSize);
        }
        _deserializeNode(node, orientation, deserializer, orthogonalSize) {
            var _a;
            let result;
            if (node.type === 'branch') {
                const serializedChildren = node.data;
                const children = serializedChildren.map((serializedChild) => {
                    return {
                        node: this._deserializeNode(serializedChild, orthogonal(orientation), deserializer, node.size),
                        visible: serializedChild.visible,
                    };
                });
                result = new BranchNode(orientation, this.proportionalLayout, this.styles, node.size, // <- orthogonal size - flips at each depth
                orthogonalSize, // <- size - flips at each depth,
                this.locked, this.margin, children);
            }
            else {
                const view = deserializer.fromJSON(node);
                if (typeof node.visible === 'boolean') {
                    (_a = view.setVisible) === null || _a === void 0 ? void 0 : _a.call(view, node.visible);
                }
                result = new LeafNode(view, orientation, orthogonalSize, node.size);
            }
            return result;
        }
        get root() {
            return this._root;
        }
        set root(root) {
            const oldRoot = this._root;
            if (oldRoot) {
                oldRoot.dispose();
                this._maximizedNode = undefined;
                this.element.removeChild(oldRoot.element);
            }
            this._root = root;
            this.element.appendChild(this._root.element);
            this.disposable.value = this._root.onDidChange((e) => {
                this._onDidChange.fire(e);
            });
        }
        /**
         * If the root is orientated as a VERTICAL node then nest the existing root within a new HORIZIONTAL root node
         * If the root is orientated as a HORIZONTAL node then nest the existing root within a new VERITCAL root node
         */
        insertOrthogonalSplitviewAtRoot() {
            if (!this._root) {
                return;
            }
            const oldRoot = this.root;
            oldRoot.element.remove();
            this._root = new BranchNode(orthogonal(oldRoot.orientation), this.proportionalLayout, this.styles, this.root.orthogonalSize, this.root.size, this.locked, this.margin);
            if (oldRoot.children.length === 0) ;
            else if (oldRoot.children.length === 1) {
                // can remove one level of redundant branching if there is only a single child
                const childReference = oldRoot.children[0];
                const child = oldRoot.removeChild(0); // remove to prevent disposal when disposing of unwanted root
                child.dispose();
                oldRoot.dispose();
                this._root.addChild(
                /**
                 * the child node will have the same orientation as the new root since
                 * we are removing the inbetween node.
                 * the entire 'tree' must be flipped recursively to ensure that the orientation
                 * flips at each level
                 */
                flipNode(childReference, childReference.orthogonalSize, childReference.size), exports.Sizing.Distribute, 0);
            }
            else {
                this._root.addChild(oldRoot, exports.Sizing.Distribute, 0);
            }
            this.element.appendChild(this._root.element);
            this.disposable.value = this._root.onDidChange((e) => {
                this._onDidChange.fire(e);
            });
        }
        next(location) {
            return this.progmaticSelect(location);
        }
        previous(location) {
            return this.progmaticSelect(location, true);
        }
        getView(location) {
            const node = location ? this.getNode(location)[1] : this.root;
            return this._getViews(node, this.orientation);
        }
        _getViews(node, orientation, cachedVisibleSize) {
            const box = { height: node.height, width: node.width };
            if (node instanceof LeafNode) {
                return { box, view: node.view, cachedVisibleSize };
            }
            const children = [];
            for (let i = 0; i < node.children.length; i++) {
                const child = node.children[i];
                const nodeCachedVisibleSize = node.getChildCachedVisibleSize(i);
                children.push(this._getViews(child, orthogonal(orientation), nodeCachedVisibleSize));
            }
            return { box, children };
        }
        progmaticSelect(location, reverse = false) {
            const [path, node] = this.getNode(location);
            if (!(node instanceof LeafNode)) {
                throw new Error('invalid location');
            }
            for (let i = path.length - 1; i > -1; i--) {
                const n = path[i];
                const l = location[i] || 0;
                const canProgressInCurrentLevel = reverse
                    ? l - 1 > -1
                    : l + 1 < n.children.length;
                if (canProgressInCurrentLevel) {
                    return findLeaf(n.children[reverse ? l - 1 : l + 1], reverse);
                }
            }
            return findLeaf(this.root, reverse);
        }
        constructor(proportionalLayout, styles, orientation, locked, margin) {
            this.proportionalLayout = proportionalLayout;
            this.styles = styles;
            this._locked = false;
            this._margin = 0;
            this._maximizedNode = undefined;
            this.disposable = new MutableDisposable();
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            this._onDidViewVisibilityChange = new Emitter();
            this.onDidViewVisibilityChange = this._onDidViewVisibilityChange.event;
            this._onDidMaximizedNodeChange = new Emitter();
            this.onDidMaximizedNodeChange = this._onDidMaximizedNodeChange.event;
            this.element = document.createElement('div');
            this.element.className = 'dv-grid-view';
            this._locked = locked !== null && locked !== void 0 ? locked : false;
            this._margin = margin !== null && margin !== void 0 ? margin : 0;
            this.root = new BranchNode(orientation, proportionalLayout, styles, 0, 0, this.locked, this.margin);
        }
        isViewVisible(location) {
            const [rest, index] = tail(location);
            const [, parent] = this.getNode(rest);
            if (!(parent instanceof BranchNode)) {
                throw new Error('Invalid from location');
            }
            return parent.isChildVisible(index);
        }
        setViewVisible(location, visible) {
            if (this.hasMaximizedView()) {
                this.exitMaximizedView();
            }
            const [rest, index] = tail(location);
            const [, parent] = this.getNode(rest);
            if (!(parent instanceof BranchNode)) {
                throw new Error('Invalid from location');
            }
            this._onDidViewVisibilityChange.fire();
            parent.setChildVisible(index, visible);
        }
        moveView(parentLocation, from, to) {
            if (this.hasMaximizedView()) {
                this.exitMaximizedView();
            }
            const [, parent] = this.getNode(parentLocation);
            if (!(parent instanceof BranchNode)) {
                throw new Error('Invalid location');
            }
            parent.moveChild(from, to);
        }
        addView(view, size, location) {
            if (this.hasMaximizedView()) {
                this.exitMaximizedView();
            }
            const [rest, index] = tail(location);
            const [pathToParent, parent] = this.getNode(rest);
            if (parent instanceof BranchNode) {
                const node = new LeafNode(view, orthogonal(parent.orientation), parent.orthogonalSize);
                parent.addChild(node, size, index);
            }
            else {
                const [grandParent, ..._] = [...pathToParent].reverse();
                const [parentIndex, ...__] = [...rest].reverse();
                let newSiblingSize = 0;
                const newSiblingCachedVisibleSize = grandParent.getChildCachedVisibleSize(parentIndex);
                if (typeof newSiblingCachedVisibleSize === 'number') {
                    newSiblingSize = exports.Sizing.Invisible(newSiblingCachedVisibleSize);
                }
                const child = grandParent.removeChild(parentIndex);
                child.dispose();
                const newParent = new BranchNode(parent.orientation, this.proportionalLayout, this.styles, parent.size, parent.orthogonalSize, this.locked, this.margin);
                grandParent.addChild(newParent, parent.size, parentIndex);
                const newSibling = new LeafNode(parent.view, grandParent.orientation, parent.size);
                newParent.addChild(newSibling, newSiblingSize, 0);
                if (typeof size !== 'number' && size.type === 'split') {
                    size = { type: 'split', index: 0 };
                }
                const node = new LeafNode(view, grandParent.orientation, parent.size);
                newParent.addChild(node, size, index);
            }
        }
        remove(view, sizing) {
            const location = getGridLocation(view.element);
            return this.removeView(location, sizing);
        }
        removeView(location, sizing) {
            if (this.hasMaximizedView()) {
                this.exitMaximizedView();
            }
            const [rest, index] = tail(location);
            const [pathToParent, parent] = this.getNode(rest);
            if (!(parent instanceof BranchNode)) {
                throw new Error('Invalid location');
            }
            const nodeToRemove = parent.children[index];
            if (!(nodeToRemove instanceof LeafNode)) {
                throw new Error('Invalid location');
            }
            parent.removeChild(index, sizing);
            nodeToRemove.dispose();
            if (parent.children.length !== 1) {
                return nodeToRemove.view;
            }
            // if the parent has only one child and we know the parent is a BranchNode we can make the tree
            // more efficiently spaced by replacing the parent BranchNode with the child.
            // if that child is a LeafNode then we simply replace the BranchNode with the child otherwise if the child
            // is a BranchNode too we should spread it's children into the grandparent.
            // refer to the remaining child as the sibling
            const sibling = parent.children[0];
            if (pathToParent.length === 0) {
                // if the parent is root
                if (sibling instanceof LeafNode) {
                    // if the sibling is a leaf node no action is required
                    return nodeToRemove.view;
                }
                // otherwise the sibling is a branch node. since the parent is the root and the root has only one child
                // which is a branch node we can just set this branch node to be the new root node
                // for good housekeeping we'll removing the sibling from it's existing tree
                parent.removeChild(0, sizing);
                // and set that sibling node to be root
                this.root = sibling;
                return nodeToRemove.view;
            }
            // otherwise the parent is apart of a large sub-tree
            const [grandParent, ..._] = [...pathToParent].reverse();
            const [parentIndex, ...__] = [...rest].reverse();
            const isSiblingVisible = parent.isChildVisible(0);
            // either way we need to remove the sibling from it's existing tree
            parent.removeChild(0, sizing);
            // note the sizes of all of the grandparents children
            const sizes = grandParent.children.map((_size, i) => grandParent.getChildSize(i));
            // remove the parent from the grandparent since we are moving the sibling to take the parents place
            // this parent is no longer used and can be disposed of
            grandParent.removeChild(parentIndex, sizing).dispose();
            if (sibling instanceof BranchNode) {
                // replace the parent with the siblings children
                sizes.splice(parentIndex, 1, ...sibling.children.map((c) => c.size));
                // and add those siblings to the grandparent
                for (let i = 0; i < sibling.children.length; i++) {
                    const child = sibling.children[i];
                    grandParent.addChild(child, child.size, parentIndex + i);
                }
                /**
                 * clean down the branch node since we need to dipose of it and
                 * when .dispose() it called on a branch it will dispose of any
                 * views it is holding onto.
                 */
                while (sibling.children.length > 0) {
                    sibling.removeChild(0);
                }
            }
            else {
                // otherwise create a new leaf node and add that to the grandparent
                const newSibling = new LeafNode(sibling.view, orthogonal(sibling.orientation), sibling.size);
                const siblingSizing = isSiblingVisible
                    ? sibling.orthogonalSize
                    : exports.Sizing.Invisible(sibling.orthogonalSize);
                grandParent.addChild(newSibling, siblingSizing, parentIndex);
            }
            // the containing node of the sibling is no longer required and can be disposed of
            sibling.dispose();
            // resize everything
            for (let i = 0; i < sizes.length; i++) {
                grandParent.resizeChild(i, sizes[i]);
            }
            return nodeToRemove.view;
        }
        layout(width, height) {
            const [size, orthogonalSize] = this.root.orientation === exports.Orientation.HORIZONTAL
                ? [height, width]
                : [width, height];
            this.root.layout(size, orthogonalSize);
        }
        getNode(location, node = this.root, path = []) {
            if (location.length === 0) {
                return [path, node];
            }
            if (!(node instanceof BranchNode)) {
                throw new Error('Invalid location');
            }
            const [index, ...rest] = location;
            if (index < 0 || index >= node.children.length) {
                throw new Error('Invalid location');
            }
            const child = node.children[index];
            path.push(node);
            return this.getNode(rest, child, path);
        }
    }

    const PROPERTY_KEYS_GRIDVIEW = (() => {
        /**
         * by readong the keys from an empty value object TypeScript will error
         * when we add or remove new properties to `DockviewOptions`
         */
        const properties = {
            disableAutoResizing: undefined,
            proportionalLayout: undefined,
            orientation: undefined,
            hideBorders: undefined,
            className: undefined,
        };
        return Object.keys(properties);
    })();

    class Resizable extends CompositeDisposable {
        get element() {
            return this._element;
        }
        get disableResizing() {
            return this._disableResizing;
        }
        set disableResizing(value) {
            this._disableResizing = value;
        }
        constructor(parentElement, disableResizing = false) {
            super();
            this._disableResizing = disableResizing;
            this._element = parentElement;
            this.addDisposables(watchElementResize(this._element, (entry) => {
                if (this.isDisposed) {
                    /**
                     * resize is delayed through requestAnimationFrame so there is a small chance
                     * the component has already been disposed of
                     */
                    return;
                }
                if (this.disableResizing) {
                    return;
                }
                if (!this._element.offsetParent) {
                    /**
                     * offsetParent === null is equivalent to display: none being set on the element or one
                     * of it's parents. In the display: none case the size will become (0, 0) which we do
                     * not want to propagate.
                     *
                     * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent
                     *
                     * You could use checkVisibility() but at the time of writing it's not supported across
                     * all Browsers
                     *
                     * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/checkVisibility
                     */
                    return;
                }
                if (!isInDocument(this._element)) {
                    /**
                     * since the event is dispatched through requestAnimationFrame there is a small chance
                     * the component is no longer attached to the DOM, if that is the case the dimensions
                     * are mostly likely all zero and meaningless. we should skip this case.
                     */
                    return;
                }
                const { width, height } = entry.contentRect;
                this.layout(width, height);
            }));
        }
    }

    const nextLayoutId$1 = sequentialNumberGenerator();
    function toTarget(direction) {
        switch (direction) {
            case 'left':
                return 'left';
            case 'right':
                return 'right';
            case 'above':
                return 'top';
            case 'below':
                return 'bottom';
            case 'within':
            default:
                return 'center';
        }
    }
    class BaseGrid extends Resizable {
        get id() {
            return this._id;
        }
        get size() {
            return this._groups.size;
        }
        get groups() {
            return Array.from(this._groups.values()).map((_) => _.value);
        }
        get width() {
            return this.gridview.width;
        }
        get height() {
            return this.gridview.height;
        }
        get minimumHeight() {
            return this.gridview.minimumHeight;
        }
        get maximumHeight() {
            return this.gridview.maximumHeight;
        }
        get minimumWidth() {
            return this.gridview.minimumWidth;
        }
        get maximumWidth() {
            return this.gridview.maximumWidth;
        }
        get activeGroup() {
            return this._activeGroup;
        }
        get locked() {
            return this.gridview.locked;
        }
        set locked(value) {
            this.gridview.locked = value;
        }
        constructor(container, options) {
            var _a;
            super(document.createElement('div'), options.disableAutoResizing);
            this._id = nextLayoutId$1.next();
            this._groups = new Map();
            this._onDidRemove = new Emitter();
            this.onDidRemove = this._onDidRemove.event;
            this._onDidAdd = new Emitter();
            this.onDidAdd = this._onDidAdd.event;
            this._onDidMaximizedChange = new Emitter();
            this.onDidMaximizedChange = this._onDidMaximizedChange.event;
            this._onDidActiveChange = new Emitter();
            this.onDidActiveChange = this._onDidActiveChange.event;
            this._bufferOnDidLayoutChange = new AsapEvent();
            this.onDidLayoutChange = this._bufferOnDidLayoutChange.onEvent;
            this._onDidViewVisibilityChangeMicroTaskQueue = new AsapEvent();
            this.onDidViewVisibilityChangeMicroTaskQueue = this._onDidViewVisibilityChangeMicroTaskQueue.onEvent;
            this.element.style.height = '100%';
            this.element.style.width = '100%';
            this._classNames = new Classnames(this.element);
            this._classNames.setClassNames((_a = options.className) !== null && _a !== void 0 ? _a : '');
            // the container is owned by the third-party, do not modify/delete it
            container.appendChild(this.element);
            this.gridview = new Gridview(!!options.proportionalLayout, options.styles, options.orientation, options.locked, options.margin);
            this.gridview.locked = !!options.locked;
            this.element.appendChild(this.gridview.element);
            this.layout(0, 0, true); // set some elements height/widths
            this.addDisposables(this.gridview.onDidMaximizedNodeChange((event) => {
                this._onDidMaximizedChange.fire({
                    panel: event.view,
                    isMaximized: event.isMaximized,
                });
            }), this.gridview.onDidViewVisibilityChange(() => this._onDidViewVisibilityChangeMicroTaskQueue.fire()), this.onDidViewVisibilityChangeMicroTaskQueue(() => {
                this.layout(this.width, this.height, true);
            }), exports.DockviewDisposable.from(() => {
                var _a;
                (_a = this.element.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(this.element);
            }), this.gridview.onDidChange(() => {
                this._bufferOnDidLayoutChange.fire();
            }), exports.DockviewEvent.any(this.onDidAdd, this.onDidRemove, this.onDidActiveChange)(() => {
                this._bufferOnDidLayoutChange.fire();
            }), this._onDidMaximizedChange, this._onDidViewVisibilityChangeMicroTaskQueue, this._bufferOnDidLayoutChange);
        }
        setVisible(panel, visible) {
            this.gridview.setViewVisible(getGridLocation(panel.element), visible);
            this._bufferOnDidLayoutChange.fire();
        }
        isVisible(panel) {
            return this.gridview.isViewVisible(getGridLocation(panel.element));
        }
        updateOptions(options) {
            var _a, _b, _c, _d;
            if (typeof options.proportionalLayout === 'boolean') ;
            if (options.orientation) {
                this.gridview.orientation = options.orientation;
            }
            if ('disableResizing' in options) {
                this.disableResizing = (_a = options.disableAutoResizing) !== null && _a !== void 0 ? _a : false;
            }
            if ('locked' in options) {
                this.locked = (_b = options.locked) !== null && _b !== void 0 ? _b : false;
            }
            if ('margin' in options) {
                this.gridview.margin = (_c = options.margin) !== null && _c !== void 0 ? _c : 0;
            }
            if ('className' in options) {
                this._classNames.setClassNames((_d = options.className) !== null && _d !== void 0 ? _d : '');
            }
        }
        maximizeGroup(panel) {
            this.gridview.maximizeView(panel);
            this.doSetGroupActive(panel);
        }
        isMaximizedGroup(panel) {
            return this.gridview.maximizedView() === panel;
        }
        exitMaximizedGroup() {
            this.gridview.exitMaximizedView();
        }
        hasMaximizedGroup() {
            return this.gridview.hasMaximizedView();
        }
        doAddGroup(group, location = [0], size) {
            this.gridview.addView(group, size !== null && size !== void 0 ? size : exports.Sizing.Distribute, location);
            this._onDidAdd.fire(group);
        }
        doRemoveGroup(group, options) {
            if (!this._groups.has(group.id)) {
                throw new Error('invalid operation');
            }
            const item = this._groups.get(group.id);
            const view = this.gridview.remove(group, exports.Sizing.Distribute);
            if (item && !(options === null || options === void 0 ? void 0 : options.skipDispose)) {
                item.disposable.dispose();
                item.value.dispose();
                this._groups.delete(group.id);
                this._onDidRemove.fire(group);
            }
            if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
                const groups = Array.from(this._groups.values());
                this.doSetGroupActive(groups.length > 0 ? groups[0].value : undefined);
            }
            return view;
        }
        getPanel(id) {
            var _a;
            return (_a = this._groups.get(id)) === null || _a === void 0 ? void 0 : _a.value;
        }
        doSetGroupActive(group) {
            if (this._activeGroup === group) {
                return;
            }
            if (this._activeGroup) {
                this._activeGroup.setActive(false);
            }
            if (group) {
                group.setActive(true);
            }
            this._activeGroup = group;
            this._onDidActiveChange.fire(group);
        }
        removeGroup(group) {
            this.doRemoveGroup(group);
        }
        moveToNext(options) {
            var _a;
            if (!options) {
                options = {};
            }
            if (!options.group) {
                if (!this.activeGroup) {
                    return;
                }
                options.group = this.activeGroup;
            }
            const location = getGridLocation(options.group.element);
            const next = (_a = this.gridview.next(location)) === null || _a === void 0 ? void 0 : _a.view;
            this.doSetGroupActive(next);
        }
        moveToPrevious(options) {
            var _a;
            if (!options) {
                options = {};
            }
            if (!options.group) {
                if (!this.activeGroup) {
                    return;
                }
                options.group = this.activeGroup;
            }
            const location = getGridLocation(options.group.element);
            const next = (_a = this.gridview.previous(location)) === null || _a === void 0 ? void 0 : _a.view;
            this.doSetGroupActive(next);
        }
        layout(width, height, forceResize) {
            const different = forceResize || width !== this.width || height !== this.height;
            if (!different) {
                return;
            }
            this.gridview.element.style.height = `${height}px`;
            this.gridview.element.style.width = `${width}px`;
            this.gridview.layout(width, height);
        }
        dispose() {
            this._onDidActiveChange.dispose();
            this._onDidAdd.dispose();
            this._onDidRemove.dispose();
            for (const group of this.groups) {
                group.dispose();
            }
            this.gridview.dispose();
            super.dispose();
        }
    }

    class SplitviewApi {
        /**
         * The minimum size  the component can reach where size is measured in the direction of orientation provided.
         */
        get minimumSize() {
            return this.component.minimumSize;
        }
        /**
         * The maximum size the component can reach where size is measured in the direction of orientation provided.
         */
        get maximumSize() {
            return this.component.maximumSize;
        }
        /**
         * Width of the component.
         */
        get width() {
            return this.component.width;
        }
        /**
         * Height of the component.
         */
        get height() {
            return this.component.height;
        }
        /**
         * The current number of panels.
         */
        get length() {
            return this.component.length;
        }
        /**
         * The current orientation of the component.
         */
        get orientation() {
            return this.component.orientation;
        }
        /**
         * The list of current panels.
         */
        get panels() {
            return this.component.panels;
        }
        /**
         * Invoked after a layout is loaded through the `fromJSON` method.
         */
        get onDidLayoutFromJSON() {
            return this.component.onDidLayoutFromJSON;
        }
        /**
         * Invoked whenever any aspect of the layout changes.
         * If listening to this event it may be worth debouncing ouputs.
         */
        get onDidLayoutChange() {
            return this.component.onDidLayoutChange;
        }
        /**
         * Invoked when a view is added.
         */
        get onDidAddView() {
            return this.component.onDidAddView;
        }
        /**
         * Invoked when a view is removed.
         */
        get onDidRemoveView() {
            return this.component.onDidRemoveView;
        }
        constructor(component) {
            this.component = component;
        }
        /**
         * Removes an existing panel and optionally provide a `Sizing` method
         * for the subsequent resize.
         */
        removePanel(panel, sizing) {
            this.component.removePanel(panel, sizing);
        }
        /**
         * Focus the component.
         */
        focus() {
            this.component.focus();
        }
        /**
         * Get the reference to a panel given it's `string` id.
         */
        getPanel(id) {
            return this.component.getPanel(id);
        }
        /**
         * Layout the panel with a width and height.
         */
        layout(width, height) {
            return this.component.layout(width, height);
        }
        /**
         * Add a new panel and return the created instance.
         */
        addPanel(options) {
            return this.component.addPanel(options);
        }
        /**
         * Move a panel given it's current and desired index.
         */
        movePanel(from, to) {
            this.component.movePanel(from, to);
        }
        /**
         * Deserialize a layout to built a splitivew.
         */
        fromJSON(data) {
            this.component.fromJSON(data);
        }
        /** Serialize a layout */
        toJSON() {
            return this.component.toJSON();
        }
        /**
         * Remove all panels and clear the component.
         */
        clear() {
            this.component.clear();
        }
        /**
         * Update configuratable options.
         */
        updateOptions(options) {
            this.component.updateOptions(options);
        }
        /**
         * Release resources and teardown component. Do not call when using framework versions of dockview.
         */
        dispose() {
            this.component.dispose();
        }
    }
    class PaneviewApi {
        /**
         * The minimum size  the component can reach where size is measured in the direction of orientation provided.
         */
        get minimumSize() {
            return this.component.minimumSize;
        }
        /**
         * The maximum size the component can reach where size is measured in the direction of orientation provided.
         */
        get maximumSize() {
            return this.component.maximumSize;
        }
        /**
         * Width of the component.
         */
        get width() {
            return this.component.width;
        }
        /**
         * Height of the component.
         */
        get height() {
            return this.component.height;
        }
        /**
         * All panel objects.
         */
        get panels() {
            return this.component.panels;
        }
        /**
         * Invoked when any layout change occures, an aggregation of many events.
         */
        get onDidLayoutChange() {
            return this.component.onDidLayoutChange;
        }
        /**
         * Invoked after a layout is deserialzied using the `fromJSON` method.
         */
        get onDidLayoutFromJSON() {
            return this.component.onDidLayoutFromJSON;
        }
        /**
         * Invoked when a panel is added. May be called multiple times when moving panels.
         */
        get onDidAddView() {
            return this.component.onDidAddView;
        }
        /**
         * Invoked when a panel is removed. May be called multiple times when moving panels.
         */
        get onDidRemoveView() {
            return this.component.onDidRemoveView;
        }
        /**
         * Invoked when a Drag'n'Drop event occurs that the component was unable to handle. Exposed for custom Drag'n'Drop functionality.
         */
        get onDidDrop() {
            return this.component.onDidDrop;
        }
        get onUnhandledDragOverEvent() {
            return this.component.onUnhandledDragOverEvent;
        }
        constructor(component) {
            this.component = component;
        }
        /**
         * Remove a panel given the panel object.
         */
        removePanel(panel) {
            this.component.removePanel(panel);
        }
        /**
         * Get a panel object given a `string` id. May return `undefined`.
         */
        getPanel(id) {
            return this.component.getPanel(id);
        }
        /**
         * Move a panel given it's current and desired index.
         */
        movePanel(from, to) {
            this.component.movePanel(from, to);
        }
        /**
         *  Focus the component. Will try to focus an active panel if one exists.
         */
        focus() {
            this.component.focus();
        }
        /**
         * Force resize the component to an exact width and height. Read about auto-resizing before using.
         */
        layout(width, height) {
            this.component.layout(width, height);
        }
        /**
         * Add a panel and return the created object.
         */
        addPanel(options) {
            return this.component.addPanel(options);
        }
        /**
         * Create a component from a serialized object.
         */
        fromJSON(data) {
            this.component.fromJSON(data);
        }
        /**
         * Create a serialized object of the current component.
         */
        toJSON() {
            return this.component.toJSON();
        }
        /**
         * Reset the component back to an empty and default state.
         */
        clear() {
            this.component.clear();
        }
        /**
         * Update configuratable options.
         */
        updateOptions(options) {
            this.component.updateOptions(options);
        }
        /**
         * Release resources and teardown component. Do not call when using framework versions of dockview.
         */
        dispose() {
            this.component.dispose();
        }
    }
    class GridviewApi {
        /**
         * Width of the component.
         */
        get width() {
            return this.component.width;
        }
        /**
         * Height of the component.
         */
        get height() {
            return this.component.height;
        }
        /**
         * Minimum height of the component.
         */
        get minimumHeight() {
            return this.component.minimumHeight;
        }
        /**
         * Maximum height of the component.
         */
        get maximumHeight() {
            return this.component.maximumHeight;
        }
        /**
         * Minimum width of the component.
         */
        get minimumWidth() {
            return this.component.minimumWidth;
        }
        /**
         * Maximum width of the component.
         */
        get maximumWidth() {
            return this.component.maximumWidth;
        }
        /**
         * Invoked when any layout change occures, an aggregation of many events.
         */
        get onDidLayoutChange() {
            return this.component.onDidLayoutChange;
        }
        /**
         * Invoked when a panel is added. May be called multiple times when moving panels.
         */
        get onDidAddPanel() {
            return this.component.onDidAddGroup;
        }
        /**
         * Invoked when a panel is removed. May be called multiple times when moving panels.
         */
        get onDidRemovePanel() {
            return this.component.onDidRemoveGroup;
        }
        /**
         * Invoked when the active panel changes. May be undefined if no panel is active.
         */
        get onDidActivePanelChange() {
            return this.component.onDidActiveGroupChange;
        }
        /**
         * Invoked after a layout is deserialzied using the `fromJSON` method.
         */
        get onDidLayoutFromJSON() {
            return this.component.onDidLayoutFromJSON;
        }
        /**
         * All panel objects.
         */
        get panels() {
            return this.component.groups;
        }
        /**
         * Current orientation. Can be changed after initialization.
         */
        get orientation() {
            return this.component.orientation;
        }
        set orientation(value) {
            this.component.updateOptions({ orientation: value });
        }
        constructor(component) {
            this.component = component;
        }
        /**
         *  Focus the component. Will try to focus an active panel if one exists.
         */
        focus() {
            this.component.focus();
        }
        /**
         * Force resize the component to an exact width and height. Read about auto-resizing before using.
         */
        layout(width, height, force = false) {
            this.component.layout(width, height, force);
        }
        /**
         * Add a panel and return the created object.
         */
        addPanel(options) {
            return this.component.addPanel(options);
        }
        /**
         * Remove a panel given the panel object.
         */
        removePanel(panel, sizing) {
            this.component.removePanel(panel, sizing);
        }
        /**
         * Move a panel in a particular direction relative to another panel.
         */
        movePanel(panel, options) {
            this.component.movePanel(panel, options);
        }
        /**
         * Get a panel object given a `string` id. May return `undefined`.
         */
        getPanel(id) {
            return this.component.getPanel(id);
        }
        /**
         * Create a component from a serialized object.
         */
        fromJSON(data) {
            return this.component.fromJSON(data);
        }
        /**
         * Create a serialized object of the current component.
         */
        toJSON() {
            return this.component.toJSON();
        }
        /**
         * Reset the component back to an empty and default state.
         */
        clear() {
            this.component.clear();
        }
        updateOptions(options) {
            this.component.updateOptions(options);
        }
        /**
         * Release resources and teardown component. Do not call when using framework versions of dockview.
         */
        dispose() {
            this.component.dispose();
        }
    }
    class DockviewApi {
        /**
         * The unique identifier for this instance. Used to manage scope of Drag'n'Drop events.
         */
        get id() {
            return this.component.id;
        }
        /**
         * Width of the component.
         */
        get width() {
            return this.component.width;
        }
        /**
         * Height of the component.
         */
        get height() {
            return this.component.height;
        }
        /**
         * Minimum height of the component.
         */
        get minimumHeight() {
            return this.component.minimumHeight;
        }
        /**
         * Maximum height of the component.
         */
        get maximumHeight() {
            return this.component.maximumHeight;
        }
        /**
         * Minimum width of the component.
         */
        get minimumWidth() {
            return this.component.minimumWidth;
        }
        /**
         * Maximum width of the component.
         */
        get maximumWidth() {
            return this.component.maximumWidth;
        }
        /**
         * Total number of groups.
         */
        get size() {
            return this.component.size;
        }
        /**
         * Total number of panels.
         */
        get totalPanels() {
            return this.component.totalPanels;
        }
        /**
         * Invoked when the active group changes. May be undefined if no group is active.
         */
        get onDidActiveGroupChange() {
            return this.component.onDidActiveGroupChange;
        }
        /**
         * Invoked when a group is added. May be called multiple times when moving groups.
         */
        get onDidAddGroup() {
            return this.component.onDidAddGroup;
        }
        /**
         * Invoked when a group is removed. May be called multiple times when moving groups.
         */
        get onDidRemoveGroup() {
            return this.component.onDidRemoveGroup;
        }
        /**
         * Invoked when the active panel changes. May be undefined if no panel is active.
         */
        get onDidActivePanelChange() {
            return this.component.onDidActivePanelChange;
        }
        /**
         * Invoked when a panel is added. May be called multiple times when moving panels.
         */
        get onDidAddPanel() {
            return this.component.onDidAddPanel;
        }
        /**
         * Invoked when a panel is removed. May be called multiple times when moving panels.
         */
        get onDidRemovePanel() {
            return this.component.onDidRemovePanel;
        }
        get onDidMovePanel() {
            return this.component.onDidMovePanel;
        }
        /**
         * Invoked after a layout is deserialzied using the `fromJSON` method.
         */
        get onDidLayoutFromJSON() {
            return this.component.onDidLayoutFromJSON;
        }
        /**
         * Invoked when any layout change occures, an aggregation of many events.
         */
        get onDidLayoutChange() {
            return this.component.onDidLayoutChange;
        }
        /**
         * Invoked when a Drag'n'Drop event occurs that the component was unable to handle. Exposed for custom Drag'n'Drop functionality.
         */
        get onDidDrop() {
            return this.component.onDidDrop;
        }
        /**
         * Invoked when a Drag'n'Drop event occurs but before dockview handles it giving the user an opportunity to intecept and
         * prevent the event from occuring using the standard `preventDefault()` syntax.
         *
         * Preventing certain events may causes unexpected behaviours, use carefully.
         */
        get onWillDrop() {
            return this.component.onWillDrop;
        }
        /**
         * Invoked before an overlay is shown indicating a drop target.
         *
         * Calling `event.preventDefault()` will prevent the overlay being shown and prevent
         * the any subsequent drop event.
         */
        get onWillShowOverlay() {
            return this.component.onWillShowOverlay;
        }
        /**
         * Invoked before a group is dragged.
         *
         * Calling `event.nativeEvent.preventDefault()` will prevent the group drag starting.
         *
         */
        get onWillDragGroup() {
            return this.component.onWillDragGroup;
        }
        /**
         * Invoked before a panel is dragged.
         *
         * Calling `event.nativeEvent.preventDefault()` will prevent the panel drag starting.
         */
        get onWillDragPanel() {
            return this.component.onWillDragPanel;
        }
        get onUnhandledDragOverEvent() {
            return this.component.onUnhandledDragOverEvent;
        }
        get onDidPopoutGroupSizeChange() {
            return this.component.onDidPopoutGroupSizeChange;
        }
        get onDidPopoutGroupPositionChange() {
            return this.component.onDidPopoutGroupPositionChange;
        }
        /**
         * All panel objects.
         */
        get panels() {
            return this.component.panels;
        }
        /**
         * All group objects.
         */
        get groups() {
            return this.component.groups;
        }
        /**
         *  Active panel object.
         */
        get activePanel() {
            return this.component.activePanel;
        }
        /**
         * Active group object.
         */
        get activeGroup() {
            return this.component.activeGroup;
        }
        constructor(component) {
            this.component = component;
        }
        /**
         *  Focus the component. Will try to focus an active panel if one exists.
         */
        focus() {
            this.component.focus();
        }
        /**
         * Get a panel object given a `string` id. May return `undefined`.
         */
        getPanel(id) {
            return this.component.getGroupPanel(id);
        }
        /**
         * Force resize the component to an exact width and height. Read about auto-resizing before using.
         */
        layout(width, height, force = false) {
            this.component.layout(width, height, force);
        }
        /**
         * Add a panel and return the created object.
         */
        addPanel(options) {
            return this.component.addPanel(options);
        }
        /**
         * Remove a panel given the panel object.
         */
        removePanel(panel) {
            this.component.removePanel(panel);
        }
        /**
         * Add a group and return the created object.
         */
        addGroup(options) {
            return this.component.addGroup(options);
        }
        /**
         * Close all groups and panels.
         */
        closeAllGroups() {
            return this.component.closeAllGroups();
        }
        /**
         * Remove a group and any panels within the group.
         */
        removeGroup(group) {
            this.component.removeGroup(group);
        }
        /**
         * Get a group object given a `string` id. May return undefined.
         */
        getGroup(id) {
            return this.component.getPanel(id);
        }
        /**
         * Add a floating group
         */
        addFloatingGroup(item, options) {
            return this.component.addFloatingGroup(item, options);
        }
        /**
         * Create a component from a serialized object.
         */
        fromJSON(data) {
            this.component.fromJSON(data);
        }
        /**
         * Create a serialized object of the current component.
         */
        toJSON() {
            return this.component.toJSON();
        }
        /**
         * Reset the component back to an empty and default state.
         */
        clear() {
            this.component.clear();
        }
        /**
         * Move the focus progmatically to the next panel or group.
         */
        moveToNext(options) {
            this.component.moveToNext(options);
        }
        /**
         * Move the focus progmatically to the previous panel or group.
         */
        moveToPrevious(options) {
            this.component.moveToPrevious(options);
        }
        maximizeGroup(panel) {
            this.component.maximizeGroup(panel.group);
        }
        hasMaximizedGroup() {
            return this.component.hasMaximizedGroup();
        }
        exitMaximizedGroup() {
            this.component.exitMaximizedGroup();
        }
        get onDidMaximizedGroupChange() {
            return this.component.onDidMaximizedGroupChange;
        }
        /**
         * Add a popout group in a new Window
         */
        addPopoutGroup(item, options) {
            return this.component.addPopoutGroup(item, options);
        }
        updateOptions(options) {
            this.component.updateOptions(options);
        }
        /**
         * Release resources and teardown component. Do not call when using framework versions of dockview.
         */
        dispose() {
            this.component.dispose();
        }
    }

    class DragHandler extends CompositeDisposable {
        constructor(el) {
            super();
            this.el = el;
            this.dataDisposable = new MutableDisposable();
            this.pointerEventsDisposable = new MutableDisposable();
            this._onDragStart = new Emitter();
            this.onDragStart = this._onDragStart.event;
            this.addDisposables(this._onDragStart, this.dataDisposable, this.pointerEventsDisposable);
            this.configure();
        }
        isCancelled(_event) {
            return false;
        }
        configure() {
            this.addDisposables(this._onDragStart, addDisposableListener(this.el, 'dragstart', (event) => {
                if (event.defaultPrevented || this.isCancelled(event)) {
                    event.preventDefault();
                    return;
                }
                const iframes = disableIframePointEvents();
                this.pointerEventsDisposable.value = {
                    dispose: () => {
                        iframes.release();
                    },
                };
                this.el.classList.add('dv-dragged');
                setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
                this.dataDisposable.value = this.getData(event);
                this._onDragStart.fire(event);
                if (event.dataTransfer) {
                    event.dataTransfer.effectAllowed = 'move';
                    const hasData = event.dataTransfer.items.length > 0;
                    if (!hasData) {
                        /**
                         * Although this is not used by dockview many third party dnd libraries will check
                         * dataTransfer.types to determine valid drag events.
                         *
                         * For example: in react-dnd if dataTransfer.types is not set then the dragStart event will be cancelled
                         * through .preventDefault(). Since this is applied globally to all drag events this would break dockviews
                         * dnd logic. You can see the code at
                     P    * https://github.com/react-dnd/react-dnd/blob/main/packages/backend-html5/src/HTML5BackendImpl.ts#L542
                         */
                        event.dataTransfer.setData('text/plain', '');
                    }
                }
            }), addDisposableListener(this.el, 'dragend', () => {
                this.pointerEventsDisposable.dispose();
                setTimeout(() => {
                    this.dataDisposable.dispose(); // allow the data to be read by other handlers before disposing
                }, 0);
            }));
        }
    }

    class DragAndDropObserver extends CompositeDisposable {
        constructor(element, callbacks) {
            super();
            this.element = element;
            this.callbacks = callbacks;
            this.target = null;
            this.registerListeners();
        }
        onDragEnter(e) {
            this.target = e.target;
            this.callbacks.onDragEnter(e);
        }
        onDragOver(e) {
            e.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)
            if (this.callbacks.onDragOver) {
                this.callbacks.onDragOver(e);
            }
        }
        onDragLeave(e) {
            if (this.target === e.target) {
                this.target = null;
                this.callbacks.onDragLeave(e);
            }
        }
        onDragEnd(e) {
            this.target = null;
            this.callbacks.onDragEnd(e);
        }
        onDrop(e) {
            this.callbacks.onDrop(e);
        }
        registerListeners() {
            this.addDisposables(addDisposableListener(this.element, 'dragenter', (e) => {
                this.onDragEnter(e);
            }, true));
            this.addDisposables(addDisposableListener(this.element, 'dragover', (e) => {
                this.onDragOver(e);
            }, true));
            this.addDisposables(addDisposableListener(this.element, 'dragleave', (e) => {
                this.onDragLeave(e);
            }));
            this.addDisposables(addDisposableListener(this.element, 'dragend', (e) => {
                this.onDragEnd(e);
            }));
            this.addDisposables(addDisposableListener(this.element, 'drop', (e) => {
                this.onDrop(e);
            }));
        }
    }

    class WillShowOverlayEvent extends DockviewEvent {
        get nativeEvent() {
            return this.options.nativeEvent;
        }
        get position() {
            return this.options.position;
        }
        constructor(options) {
            super();
            this.options = options;
        }
    }
    function directionToPosition(direction) {
        switch (direction) {
            case 'above':
                return 'top';
            case 'below':
                return 'bottom';
            case 'left':
                return 'left';
            case 'right':
                return 'right';
            case 'within':
                return 'center';
            default:
                throw new Error(`invalid direction '${direction}'`);
        }
    }
    function positionToDirection(position) {
        switch (position) {
            case 'top':
                return 'above';
            case 'bottom':
                return 'below';
            case 'left':
                return 'left';
            case 'right':
                return 'right';
            case 'center':
                return 'within';
            default:
                throw new Error(`invalid position '${position}'`);
        }
    }
    const DEFAULT_ACTIVATION_SIZE = {
        value: 20,
        type: 'percentage',
    };
    const DEFAULT_SIZE = {
        value: 50,
        type: 'percentage',
    };
    const SMALL_WIDTH_BOUNDARY = 100;
    const SMALL_HEIGHT_BOUNDARY = 100;
    class Droptarget extends CompositeDisposable {
        get disabled() {
            return this._disabled;
        }
        set disabled(value) {
            this._disabled = value;
        }
        get state() {
            return this._state;
        }
        constructor(element, options) {
            super();
            this.element = element;
            this.options = options;
            this._onDrop = new Emitter();
            this.onDrop = this._onDrop.event;
            this._onWillShowOverlay = new Emitter();
            this.onWillShowOverlay = this._onWillShowOverlay.event;
            this._disabled = false;
            // use a set to take advantage of #<set>.has
            this._acceptedTargetZonesSet = new Set(this.options.acceptedTargetZones);
            this.dnd = new DragAndDropObserver(this.element, {
                onDragEnter: () => {
                    var _a, _b, _c;
                    (_c = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a)) === null || _c === void 0 ? void 0 : _c.getElements();
                },
                onDragOver: (e) => {
                    var _a, _b, _c, _d, _e, _f, _g;
                    Droptarget.ACTUAL_TARGET = this;
                    const overrideTraget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
                    if (this._acceptedTargetZonesSet.size === 0) {
                        if (overrideTraget) {
                            return;
                        }
                        this.removeDropTarget();
                        return;
                    }
                    const target = (_e = (_d = (_c = this.options).getOverlayOutline) === null || _d === void 0 ? void 0 : _d.call(_c)) !== null && _e !== void 0 ? _e : this.element;
                    const width = target.offsetWidth;
                    const height = target.offsetHeight;
                    if (width === 0 || height === 0) {
                        return; // avoid div!0
                    }
                    const rect = e.currentTarget.getBoundingClientRect();
                    const x = ((_f = e.clientX) !== null && _f !== void 0 ? _f : 0) - rect.left;
                    const y = ((_g = e.clientY) !== null && _g !== void 0 ? _g : 0) - rect.top;
                    const quadrant = this.calculateQuadrant(this._acceptedTargetZonesSet, x, y, width, height);
                    /**
                     * If the event has already been used by another DropTarget instance
                     * then don't show a second drop target, only one target should be
                     * active at any one time
                     */
                    if (this.isAlreadyUsed(e) || quadrant === null) {
                        // no drop target should be displayed
                        this.removeDropTarget();
                        return;
                    }
                    if (!this.options.canDisplayOverlay(e, quadrant)) {
                        if (overrideTraget) {
                            return;
                        }
                        this.removeDropTarget();
                        return;
                    }
                    const willShowOverlayEvent = new WillShowOverlayEvent({
                        nativeEvent: e,
                        position: quadrant,
                    });
                    /**
                     * Provide an opportunity to prevent the overlay appearing and in turn
                     * any dnd behaviours
                     */
                    this._onWillShowOverlay.fire(willShowOverlayEvent);
                    if (willShowOverlayEvent.defaultPrevented) {
                        this.removeDropTarget();
                        return;
                    }
                    this.markAsUsed(e);
                    if (overrideTraget) ;
                    else if (!this.targetElement) {
                        this.targetElement = document.createElement('div');
                        this.targetElement.className = 'dv-drop-target-dropzone';
                        this.overlayElement = document.createElement('div');
                        this.overlayElement.className = 'dv-drop-target-selection';
                        this._state = 'center';
                        this.targetElement.appendChild(this.overlayElement);
                        target.classList.add('dv-drop-target');
                        target.append(this.targetElement);
                        // this.overlayElement.style.opacity = '0';
                        // requestAnimationFrame(() => {
                        //     if (this.overlayElement) {
                        //         this.overlayElement.style.opacity = '';
                        //     }
                        // });
                    }
                    this.toggleClasses(quadrant, width, height);
                    this._state = quadrant;
                },
                onDragLeave: () => {
                    var _a, _b;
                    const target = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
                    if (target) {
                        return;
                    }
                    this.removeDropTarget();
                },
                onDragEnd: (e) => {
                    var _a, _b;
                    const target = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
                    if (target && Droptarget.ACTUAL_TARGET === this) {
                        if (this._state) {
                            // only stop the propagation of the event if we are dealing with it
                            // which is only when the target has state
                            e.stopPropagation();
                            this._onDrop.fire({
                                position: this._state,
                                nativeEvent: e,
                            });
                        }
                    }
                    this.removeDropTarget();
                    target === null || target === void 0 ? void 0 : target.clear();
                },
                onDrop: (e) => {
                    var _a, _b, _c;
                    e.preventDefault();
                    const state = this._state;
                    this.removeDropTarget();
                    (_c = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a)) === null || _c === void 0 ? void 0 : _c.clear();
                    if (state) {
                        // only stop the propagation of the event if we are dealing with it
                        // which is only when the target has state
                        e.stopPropagation();
                        this._onDrop.fire({ position: state, nativeEvent: e });
                    }
                },
            });
            this.addDisposables(this._onDrop, this._onWillShowOverlay, this.dnd);
        }
        setTargetZones(acceptedTargetZones) {
            this._acceptedTargetZonesSet = new Set(acceptedTargetZones);
        }
        setOverlayModel(model) {
            this.options.overlayModel = model;
        }
        dispose() {
            this.removeDropTarget();
            super.dispose();
        }
        /**
         * Add a property to the event object for other potential listeners to check
         */
        markAsUsed(event) {
            event[Droptarget.USED_EVENT_ID] = true;
        }
        /**
         * Check is the event has already been used by another instance of DropTarget
         */
        isAlreadyUsed(event) {
            const value = event[Droptarget.USED_EVENT_ID];
            return typeof value === 'boolean' && value;
        }
        toggleClasses(quadrant, width, height) {
            var _a, _b, _c, _d, _e, _f, _g;
            const target = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
            if (!target && !this.overlayElement) {
                return;
            }
            const isSmallX = width < SMALL_WIDTH_BOUNDARY;
            const isSmallY = height < SMALL_HEIGHT_BOUNDARY;
            const isLeft = quadrant === 'left';
            const isRight = quadrant === 'right';
            const isTop = quadrant === 'top';
            const isBottom = quadrant === 'bottom';
            const rightClass = !isSmallX && isRight;
            const leftClass = !isSmallX && isLeft;
            const topClass = !isSmallY && isTop;
            const bottomClass = !isSmallY && isBottom;
            let size = 1;
            const sizeOptions = (_d = (_c = this.options.overlayModel) === null || _c === void 0 ? void 0 : _c.size) !== null && _d !== void 0 ? _d : DEFAULT_SIZE;
            if (sizeOptions.type === 'percentage') {
                size = clamp(sizeOptions.value, 0, 100) / 100;
            }
            else {
                if (rightClass || leftClass) {
                    size = clamp(0, sizeOptions.value, width) / width;
                }
                if (topClass || bottomClass) {
                    size = clamp(0, sizeOptions.value, height) / height;
                }
            }
            if (target) {
                const outlineEl = (_g = (_f = (_e = this.options).getOverlayOutline) === null || _f === void 0 ? void 0 : _f.call(_e)) !== null && _g !== void 0 ? _g : this.element;
                const elBox = outlineEl.getBoundingClientRect();
                const ta = target.getElements(undefined, outlineEl);
                const el = ta.root;
                const overlay = ta.overlay;
                const bigbox = el.getBoundingClientRect();
                const rootTop = elBox.top - bigbox.top;
                const rootLeft = elBox.left - bigbox.left;
                const box = {
                    top: rootTop,
                    left: rootLeft,
                    width: width,
                    height: height,
                };
                if (rightClass) {
                    box.left = rootLeft + width * (1 - size);
                    box.width = width * size;
                }
                else if (leftClass) {
                    box.width = width * size;
                }
                else if (topClass) {
                    box.height = height * size;
                }
                else if (bottomClass) {
                    box.top = rootTop + height * (1 - size);
                    box.height = height * size;
                }
                if (isSmallX && isLeft) {
                    box.width = 4;
                }
                if (isSmallX && isRight) {
                    box.left = rootLeft + width - 4;
                    box.width = 4;
                }
                const topPx = `${Math.round(box.top)}px`;
                const leftPx = `${Math.round(box.left)}px`;
                const widthPx = `${Math.round(box.width)}px`;
                const heightPx = `${Math.round(box.height)}px`;
                if (overlay.style.top === topPx &&
                    overlay.style.left === leftPx &&
                    overlay.style.width === widthPx &&
                    overlay.style.height === heightPx) {
                    return;
                }
                overlay.style.top = topPx;
                overlay.style.left = leftPx;
                overlay.style.width = widthPx;
                overlay.style.height = heightPx;
                overlay.style.visibility = 'visible';
                overlay.className = `dv-drop-target-anchor${this.options.className ? ` ${this.options.className}` : ''}`;
                toggleClass(overlay, 'dv-drop-target-left', isLeft);
                toggleClass(overlay, 'dv-drop-target-right', isRight);
                toggleClass(overlay, 'dv-drop-target-top', isTop);
                toggleClass(overlay, 'dv-drop-target-bottom', isBottom);
                toggleClass(overlay, 'dv-drop-target-center', quadrant === 'center');
                if (ta.changed) {
                    toggleClass(overlay, 'dv-drop-target-anchor-container-changed', true);
                    setTimeout(() => {
                        toggleClass(overlay, 'dv-drop-target-anchor-container-changed', false);
                    }, 10);
                }
                return;
            }
            if (!this.overlayElement) {
                return;
            }
            const box = { top: '0px', left: '0px', width: '100%', height: '100%' };
            /**
             * You can also achieve the overlay placement using the transform CSS property
             * to translate and scale the element however this has the undesired effect of
             * 'skewing' the element. Comment left here for anybody that ever revisits this.
             *
             * @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform
             *
             * right
             * translateX(${100 * (1 - size) / 2}%) scaleX(${scale})
             *
             * left
             * translateX(-${100 * (1 - size) / 2}%) scaleX(${scale})
             *
             * top
             * translateY(-${100 * (1 - size) / 2}%) scaleY(${scale})
             *
             * bottom
             * translateY(${100 * (1 - size) / 2}%) scaleY(${scale})
             */
            if (rightClass) {
                box.left = `${100 * (1 - size)}%`;
                box.width = `${100 * size}%`;
            }
            else if (leftClass) {
                box.width = `${100 * size}%`;
            }
            else if (topClass) {
                box.height = `${100 * size}%`;
            }
            else if (bottomClass) {
                box.top = `${100 * (1 - size)}%`;
                box.height = `${100 * size}%`;
            }
            this.overlayElement.style.top = box.top;
            this.overlayElement.style.left = box.left;
            this.overlayElement.style.width = box.width;
            this.overlayElement.style.height = box.height;
            toggleClass(this.overlayElement, 'dv-drop-target-small-vertical', isSmallY);
            toggleClass(this.overlayElement, 'dv-drop-target-small-horizontal', isSmallX);
            toggleClass(this.overlayElement, 'dv-drop-target-left', isLeft);
            toggleClass(this.overlayElement, 'dv-drop-target-right', isRight);
            toggleClass(this.overlayElement, 'dv-drop-target-top', isTop);
            toggleClass(this.overlayElement, 'dv-drop-target-bottom', isBottom);
            toggleClass(this.overlayElement, 'dv-drop-target-center', quadrant === 'center');
        }
        calculateQuadrant(overlayType, x, y, width, height) {
            var _a, _b;
            const activationSizeOptions = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) !== null && _b !== void 0 ? _b : DEFAULT_ACTIVATION_SIZE;
            const isPercentage = activationSizeOptions.type === 'percentage';
            if (isPercentage) {
                return calculateQuadrantAsPercentage(overlayType, x, y, width, height, activationSizeOptions.value);
            }
            return calculateQuadrantAsPixels(overlayType, x, y, width, height, activationSizeOptions.value);
        }
        removeDropTarget() {
            var _a;
            if (this.targetElement) {
                this._state = undefined;
                (_a = this.targetElement.parentElement) === null || _a === void 0 ? void 0 : _a.classList.remove('dv-drop-target');
                this.targetElement.remove();
                this.targetElement = undefined;
                this.overlayElement = undefined;
            }
        }
    }
    Droptarget.USED_EVENT_ID = '__dockview_droptarget_event_is_used__';
    function calculateQuadrantAsPercentage(overlayType, x, y, width, height, threshold) {
        const xp = (100 * x) / width;
        const yp = (100 * y) / height;
        if (overlayType.has('left') && xp < threshold) {
            return 'left';
        }
        if (overlayType.has('right') && xp > 100 - threshold) {
            return 'right';
        }
        if (overlayType.has('top') && yp < threshold) {
            return 'top';
        }
        if (overlayType.has('bottom') && yp > 100 - threshold) {
            return 'bottom';
        }
        if (!overlayType.has('center')) {
            return null;
        }
        return 'center';
    }
    function calculateQuadrantAsPixels(overlayType, x, y, width, height, threshold) {
        if (overlayType.has('left') && x < threshold) {
            return 'left';
        }
        if (overlayType.has('right') && x > width - threshold) {
            return 'right';
        }
        if (overlayType.has('top') && y < threshold) {
            return 'top';
        }
        if (overlayType.has('bottom') && y > height - threshold) {
            return 'bottom';
        }
        if (!overlayType.has('center')) {
            return null;
        }
        return 'center';
    }

    const PROPERTY_KEYS_PANEVIEW = (() => {
        /**
         * by readong the keys from an empty value object TypeScript will error
         * when we add or remove new properties to `DockviewOptions`
         */
        const properties = {
            disableAutoResizing: undefined,
            disableDnd: undefined,
            className: undefined,
        };
        return Object.keys(properties);
    })();
    class PaneviewUnhandledDragOverEvent extends AcceptableEvent {
        constructor(nativeEvent, position, getData, panel) {
            super();
            this.nativeEvent = nativeEvent;
            this.position = position;
            this.getData = getData;
            this.panel = panel;
        }
    }

    class WillFocusEvent extends DockviewEvent {
        constructor() {
            super();
        }
    }
    /**
     * A core api implementation that should be used across all panel-like objects
     */
    class PanelApiImpl extends CompositeDisposable {
        get isFocused() {
            return this._isFocused;
        }
        get isActive() {
            return this._isActive;
        }
        get isVisible() {
            return this._isVisible;
        }
        get width() {
            return this._width;
        }
        get height() {
            return this._height;
        }
        constructor(id, component) {
            super();
            this.id = id;
            this.component = component;
            this._isFocused = false;
            this._isActive = false;
            this._isVisible = true;
            this._width = 0;
            this._height = 0;
            this._parameters = {};
            this.panelUpdatesDisposable = new MutableDisposable();
            this._onDidDimensionChange = new Emitter();
            this.onDidDimensionsChange = this._onDidDimensionChange.event;
            this._onDidChangeFocus = new Emitter();
            this.onDidFocusChange = this._onDidChangeFocus.event;
            //
            this._onWillFocus = new Emitter();
            this.onWillFocus = this._onWillFocus.event;
            //
            this._onDidVisibilityChange = new Emitter();
            this.onDidVisibilityChange = this._onDidVisibilityChange.event;
            this._onWillVisibilityChange = new Emitter();
            this.onWillVisibilityChange = this._onWillVisibilityChange.event;
            this._onDidActiveChange = new Emitter();
            this.onDidActiveChange = this._onDidActiveChange.event;
            this._onActiveChange = new Emitter();
            this.onActiveChange = this._onActiveChange.event;
            this._onDidParametersChange = new Emitter();
            this.onDidParametersChange = this._onDidParametersChange.event;
            this.addDisposables(this.onDidFocusChange((event) => {
                this._isFocused = event.isFocused;
            }), this.onDidActiveChange((event) => {
                this._isActive = event.isActive;
            }), this.onDidVisibilityChange((event) => {
                this._isVisible = event.isVisible;
            }), this.onDidDimensionsChange((event) => {
                this._width = event.width;
                this._height = event.height;
            }), this.panelUpdatesDisposable, this._onDidDimensionChange, this._onDidChangeFocus, this._onDidVisibilityChange, this._onDidActiveChange, this._onWillFocus, this._onActiveChange, this._onWillFocus, this._onWillVisibilityChange, this._onDidParametersChange);
        }
        getParameters() {
            return this._parameters;
        }
        initialize(panel) {
            this.panelUpdatesDisposable.value = this._onDidParametersChange.event((parameters) => {
                this._parameters = parameters;
                panel.update({
                    params: parameters,
                });
            });
        }
        setVisible(isVisible) {
            this._onWillVisibilityChange.fire({ isVisible });
        }
        setActive() {
            this._onActiveChange.fire();
        }
        updateParameters(parameters) {
            this._onDidParametersChange.fire(parameters);
        }
    }

    class SplitviewPanelApiImpl extends PanelApiImpl {
        //
        constructor(id, component) {
            super(id, component);
            this._onDidConstraintsChangeInternal = new Emitter();
            this.onDidConstraintsChangeInternal = this._onDidConstraintsChangeInternal.event;
            //
            this._onDidConstraintsChange = new Emitter({
                replay: true,
            });
            this.onDidConstraintsChange = this._onDidConstraintsChange.event;
            //
            this._onDidSizeChange = new Emitter();
            this.onDidSizeChange = this._onDidSizeChange.event;
            this.addDisposables(this._onDidConstraintsChangeInternal, this._onDidConstraintsChange, this._onDidSizeChange);
        }
        setConstraints(value) {
            this._onDidConstraintsChangeInternal.fire(value);
        }
        setSize(event) {
            this._onDidSizeChange.fire(event);
        }
    }

    class PaneviewPanelApiImpl extends SplitviewPanelApiImpl {
        set pane(pane) {
            this._pane = pane;
        }
        constructor(id, component) {
            super(id, component);
            this._onDidExpansionChange = new Emitter({
                replay: true,
            });
            this.onDidExpansionChange = this._onDidExpansionChange.event;
            this._onMouseEnter = new Emitter({});
            this.onMouseEnter = this._onMouseEnter.event;
            this._onMouseLeave = new Emitter({});
            this.onMouseLeave = this._onMouseLeave.event;
            this.addDisposables(this._onDidExpansionChange, this._onMouseEnter, this._onMouseLeave);
        }
        setExpanded(isExpanded) {
            var _a;
            (_a = this._pane) === null || _a === void 0 ? void 0 : _a.setExpanded(isExpanded);
        }
        get isExpanded() {
            var _a;
            return !!((_a = this._pane) === null || _a === void 0 ? void 0 : _a.isExpanded());
        }
    }

    class BasePanelView extends CompositeDisposable {
        get element() {
            return this._element;
        }
        get width() {
            return this._width;
        }
        get height() {
            return this._height;
        }
        get params() {
            var _a;
            return (_a = this._params) === null || _a === void 0 ? void 0 : _a.params;
        }
        constructor(id, component, api) {
            super();
            this.id = id;
            this.component = component;
            this.api = api;
            this._height = 0;
            this._width = 0;
            this._element = document.createElement('div');
            this._element.tabIndex = -1;
            this._element.style.outline = 'none';
            this._element.style.height = '100%';
            this._element.style.width = '100%';
            this._element.style.overflow = 'hidden';
            const focusTracker = trackFocus(this._element);
            this.addDisposables(this.api, focusTracker.onDidFocus(() => {
                this.api._onDidChangeFocus.fire({ isFocused: true });
            }), focusTracker.onDidBlur(() => {
                this.api._onDidChangeFocus.fire({ isFocused: false });
            }), focusTracker);
        }
        focus() {
            const event = new WillFocusEvent();
            this.api._onWillFocus.fire(event);
            if (event.defaultPrevented) {
                return;
            }
            this._element.focus();
        }
        layout(width, height) {
            this._width = width;
            this._height = height;
            this.api._onDidDimensionChange.fire({ width, height });
            if (this.part) {
                if (this._params) {
                    this.part.update(this._params.params);
                }
            }
        }
        init(parameters) {
            this._params = parameters;
            this.part = this.getComponent();
        }
        update(event) {
            var _a, _b;
            // merge the new parameters with the existing parameters
            this._params = Object.assign(Object.assign({}, this._params), { params: Object.assign(Object.assign({}, (_a = this._params) === null || _a === void 0 ? void 0 : _a.params), event.params) });
            /**
             * delete new keys that have a value of undefined,
             * allow values of null
             */
            for (const key of Object.keys(event.params)) {
                if (event.params[key] === undefined) {
                    delete this._params.params[key];
                }
            }
            // update the view with the updated props
            (_b = this.part) === null || _b === void 0 ? void 0 : _b.update({ params: this._params.params });
        }
        toJSON() {
            var _a, _b;
            const params = (_b = (_a = this._params) === null || _a === void 0 ? void 0 : _a.params) !== null && _b !== void 0 ? _b : {};
            return {
                id: this.id,
                component: this.component,
                params: Object.keys(params).length > 0 ? params : undefined,
            };
        }
        dispose() {
            var _a;
            this.api.dispose();
            (_a = this.part) === null || _a === void 0 ? void 0 : _a.dispose();
            super.dispose();
        }
    }

    class PaneviewPanel extends BasePanelView {
        set orientation(value) {
            this._orientation = value;
        }
        get orientation() {
            return this._orientation;
        }
        get minimumSize() {
            const headerSize = this.headerSize;
            const expanded = this.isExpanded();
            const minimumBodySize = expanded ? this._minimumBodySize : 0;
            return headerSize + minimumBodySize;
        }
        get maximumSize() {
            const headerSize = this.headerSize;
            const expanded = this.isExpanded();
            const maximumBodySize = expanded ? this._maximumBodySize : 0;
            return headerSize + maximumBodySize;
        }
        get size() {
            return this._size;
        }
        get orthogonalSize() {
            return this._orthogonalSize;
        }
        set orthogonalSize(size) {
            this._orthogonalSize = size;
        }
        get minimumBodySize() {
            return this._minimumBodySize;
        }
        set minimumBodySize(value) {
            this._minimumBodySize = typeof value === 'number' ? value : 0;
        }
        get maximumBodySize() {
            return this._maximumBodySize;
        }
        set maximumBodySize(value) {
            this._maximumBodySize =
                typeof value === 'number' ? value : Number.POSITIVE_INFINITY;
        }
        get headerVisible() {
            return this._headerVisible;
        }
        set headerVisible(value) {
            this._headerVisible = value;
            this.header.style.display = value ? '' : 'none';
        }
        constructor(options) {
            super(options.id, options.component, new PaneviewPanelApiImpl(options.id, options.component));
            this._onDidChangeExpansionState = new Emitter({ replay: true });
            this.onDidChangeExpansionState = this._onDidChangeExpansionState.event;
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            this._orthogonalSize = 0;
            this._size = 0;
            this._isExpanded = false;
            this.api.pane = this; // TODO cannot use 'this' before 'super'
            this.api.initialize(this);
            this.headerSize = options.headerSize;
            this.headerComponent = options.headerComponent;
            this._minimumBodySize = options.minimumBodySize;
            this._maximumBodySize = options.maximumBodySize;
            this._isExpanded = options.isExpanded;
            this._headerVisible = options.isHeaderVisible;
            this._onDidChangeExpansionState.fire(this.isExpanded()); // initialize value
            this._orientation = options.orientation;
            this.element.classList.add('dv-pane');
            this.addDisposables(this.api.onWillVisibilityChange((event) => {
                const { isVisible } = event;
                const { accessor } = this._params;
                accessor.setVisible(this, isVisible);
            }), this.api.onDidSizeChange((event) => {
                this._onDidChange.fire({ size: event.size });
            }), addDisposableListener(this.element, 'mouseenter', (ev) => {
                this.api._onMouseEnter.fire(ev);
            }), addDisposableListener(this.element, 'mouseleave', (ev) => {
                this.api._onMouseLeave.fire(ev);
            }));
            this.addDisposables(this._onDidChangeExpansionState, this.onDidChangeExpansionState((isPanelExpanded) => {
                this.api._onDidExpansionChange.fire({
                    isExpanded: isPanelExpanded,
                });
            }), this.api.onDidFocusChange((e) => {
                if (!this.header) {
                    return;
                }
                if (e.isFocused) {
                    addClasses(this.header, 'focused');
                }
                else {
                    removeClasses(this.header, 'focused');
                }
            }));
            this.renderOnce();
        }
        setVisible(isVisible) {
            this.api._onDidVisibilityChange.fire({ isVisible });
        }
        setActive(isActive) {
            this.api._onDidActiveChange.fire({ isActive });
        }
        isExpanded() {
            return this._isExpanded;
        }
        setExpanded(expanded) {
            if (this._isExpanded === expanded) {
                return;
            }
            this._isExpanded = expanded;
            if (expanded) {
                if (this.animationTimer) {
                    clearTimeout(this.animationTimer);
                }
                if (this.body) {
                    this.element.appendChild(this.body);
                }
            }
            else {
                this.animationTimer = setTimeout(() => {
                    var _a;
                    (_a = this.body) === null || _a === void 0 ? void 0 : _a.remove();
                }, 200);
            }
            this._onDidChange.fire(expanded ? { size: this.width } : {});
            this._onDidChangeExpansionState.fire(expanded);
        }
        layout(size, orthogonalSize) {
            this._size = size;
            this._orthogonalSize = orthogonalSize;
            const [width, height] = this.orientation === exports.Orientation.HORIZONTAL
                ? [size, orthogonalSize]
                : [orthogonalSize, size];
            super.layout(width, height);
        }
        init(parameters) {
            var _a, _b;
            super.init(parameters);
            if (typeof parameters.minimumBodySize === 'number') {
                this.minimumBodySize = parameters.minimumBodySize;
            }
            if (typeof parameters.maximumBodySize === 'number') {
                this.maximumBodySize = parameters.maximumBodySize;
            }
            this.bodyPart = this.getBodyComponent();
            this.headerPart = this.getHeaderComponent();
            this.bodyPart.init(Object.assign(Object.assign({}, parameters), { api: this.api }));
            this.headerPart.init(Object.assign(Object.assign({}, parameters), { api: this.api }));
            (_a = this.body) === null || _a === void 0 ? void 0 : _a.append(this.bodyPart.element);
            (_b = this.header) === null || _b === void 0 ? void 0 : _b.append(this.headerPart.element);
            if (typeof parameters.isExpanded === 'boolean') {
                this.setExpanded(parameters.isExpanded);
            }
        }
        toJSON() {
            const params = this._params;
            return Object.assign(Object.assign({}, super.toJSON()), { headerComponent: this.headerComponent, title: params.title });
        }
        renderOnce() {
            this.header = document.createElement('div');
            this.header.tabIndex = 0;
            this.header.className = 'dv-pane-header';
            this.header.style.height = `${this.headerSize}px`;
            this.header.style.lineHeight = `${this.headerSize}px`;
            this.header.style.minHeight = `${this.headerSize}px`;
            this.header.style.maxHeight = `${this.headerSize}px`;
            this.element.appendChild(this.header);
            this.body = document.createElement('div');
            this.body.className = 'dv-pane-body';
            this.element.appendChild(this.body);
        }
        // TODO slightly hacky by-pass of the component to create a body and header component
        getComponent() {
            return {
                update: (params) => {
                    var _a, _b;
                    (_a = this.bodyPart) === null || _a === void 0 ? void 0 : _a.update({ params });
                    (_b = this.headerPart) === null || _b === void 0 ? void 0 : _b.update({ params });
                },
                dispose: () => {
                    var _a, _b;
                    (_a = this.bodyPart) === null || _a === void 0 ? void 0 : _a.dispose();
                    (_b = this.headerPart) === null || _b === void 0 ? void 0 : _b.dispose();
                },
            };
        }
    }

    class DraggablePaneviewPanel extends PaneviewPanel {
        constructor(options) {
            super({
                id: options.id,
                component: options.component,
                headerComponent: options.headerComponent,
                orientation: options.orientation,
                isExpanded: options.isExpanded,
                isHeaderVisible: true,
                headerSize: options.headerSize,
                minimumBodySize: options.minimumBodySize,
                maximumBodySize: options.maximumBodySize,
            });
            this._onDidDrop = new Emitter();
            this.onDidDrop = this._onDidDrop.event;
            this._onUnhandledDragOverEvent = new Emitter();
            this.onUnhandledDragOverEvent = this._onUnhandledDragOverEvent.event;
            this.accessor = options.accessor;
            this.addDisposables(this._onDidDrop, this._onUnhandledDragOverEvent);
            if (!options.disableDnd) {
                this.initDragFeatures();
            }
        }
        initDragFeatures() {
            if (!this.header) {
                return;
            }
            const id = this.id;
            const accessorId = this.accessor.id;
            this.header.draggable = true;
            this.handler = new (class PaneDragHandler extends DragHandler {
                getData() {
                    LocalSelectionTransfer.getInstance().setData([new PaneTransfer(accessorId, id)], PaneTransfer.prototype);
                    return {
                        dispose: () => {
                            LocalSelectionTransfer.getInstance().clearData(PaneTransfer.prototype);
                        },
                    };
                }
            })(this.header);
            this.target = new Droptarget(this.element, {
                acceptedTargetZones: ['top', 'bottom'],
                overlayModel: {
                    activationSize: { type: 'percentage', value: 50 },
                },
                canDisplayOverlay: (event, position) => {
                    const data = getPaneData();
                    if (data) {
                        if (data.paneId !== this.id &&
                            data.viewId === this.accessor.id) {
                            return true;
                        }
                    }
                    const firedEvent = new PaneviewUnhandledDragOverEvent(event, position, getPaneData, this);
                    this._onUnhandledDragOverEvent.fire(firedEvent);
                    return firedEvent.isAccepted;
                },
            });
            this.addDisposables(this._onDidDrop, this.handler, this.target, this.target.onDrop((event) => {
                this.onDrop(event);
            }));
        }
        onDrop(event) {
            const data = getPaneData();
            if (!data || data.viewId !== this.accessor.id) {
                // if there is no local drag event for this panel
                // or if the drag event was creating by another Paneview instance
                this._onDidDrop.fire(Object.assign(Object.assign({}, event), { panel: this, api: new PaneviewApi(this.accessor), getData: getPaneData }));
                return;
            }
            const containerApi = this._params
                .containerApi;
            const panelId = data.paneId;
            const existingPanel = containerApi.getPanel(panelId);
            if (!existingPanel) {
                // if the panel doesn't exist
                this._onDidDrop.fire(Object.assign(Object.assign({}, event), { panel: this, getData: getPaneData, api: new PaneviewApi(this.accessor) }));
                return;
            }
            const allPanels = containerApi.panels;
            const fromIndex = allPanels.indexOf(existingPanel);
            let toIndex = containerApi.panels.indexOf(this);
            if (event.position === 'left' || event.position === 'top') {
                toIndex = Math.max(0, toIndex - 1);
            }
            if (event.position === 'right' || event.position === 'bottom') {
                if (fromIndex > toIndex) {
                    toIndex++;
                }
                toIndex = Math.min(allPanels.length - 1, toIndex);
            }
            containerApi.movePanel(fromIndex, toIndex);
        }
    }

    class ContentContainer extends CompositeDisposable {
        get element() {
            return this._element;
        }
        constructor(accessor, group) {
            super();
            this.accessor = accessor;
            this.group = group;
            this.disposable = new MutableDisposable();
            this._onDidFocus = new Emitter();
            this.onDidFocus = this._onDidFocus.event;
            this._onDidBlur = new Emitter();
            this.onDidBlur = this._onDidBlur.event;
            this._element = document.createElement('div');
            this._element.className = 'dv-content-container';
            this._element.tabIndex = -1;
            this.addDisposables(this._onDidFocus, this._onDidBlur);
            const target = group.dropTargetContainer;
            this.dropTarget = new Droptarget(this.element, {
                getOverlayOutline: () => {
                    var _a;
                    return ((_a = accessor.options.theme) === null || _a === void 0 ? void 0 : _a.dndPanelOverlay) === 'group'
                        ? this.element.parentElement
                        : null;
                },
                className: 'dv-drop-target-content',
                acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
                canDisplayOverlay: (event, position) => {
                    if (this.group.locked === 'no-drop-target' ||
                        (this.group.locked && position === 'center')) {
                        return false;
                    }
                    const data = getPanelData();
                    if (!data &&
                        event.shiftKey &&
                        this.group.location.type !== 'floating') {
                        return false;
                    }
                    if (data && data.viewId === this.accessor.id) {
                        return true;
                    }
                    return this.group.canDisplayOverlay(event, position, 'content');
                },
                getOverrideTarget: target ? () => target.model : undefined,
            });
            this.addDisposables(this.dropTarget);
        }
        show() {
            this.element.style.display = '';
        }
        hide() {
            this.element.style.display = 'none';
        }
        renderPanel(panel, options = { asActive: true }) {
            const doRender = options.asActive ||
                (this.panel && this.group.isPanelActive(this.panel));
            if (this.panel &&
                this.panel.view.content.element.parentElement === this._element) {
                /**
                 * If the currently attached panel is mounted directly to the content then remove it
                 */
                this._element.removeChild(this.panel.view.content.element);
            }
            this.panel = panel;
            let container;
            switch (panel.api.renderer) {
                case 'onlyWhenVisible':
                    this.group.renderContainer.detatch(panel);
                    if (this.panel) {
                        if (doRender) {
                            this._element.appendChild(this.panel.view.content.element);
                        }
                    }
                    container = this._element;
                    break;
                case 'always':
                    if (panel.view.content.element.parentElement === this._element) {
                        this._element.removeChild(panel.view.content.element);
                    }
                    container = this.group.renderContainer.attach({
                        panel,
                        referenceContainer: this,
                    });
                    break;
                default:
                    throw new Error(`dockview: invalid renderer type '${panel.api.renderer}'`);
            }
            if (doRender) {
                const focusTracker = trackFocus(container);
                const disposable = new CompositeDisposable();
                disposable.addDisposables(focusTracker, focusTracker.onDidFocus(() => this._onDidFocus.fire()), focusTracker.onDidBlur(() => this._onDidBlur.fire()));
                this.disposable.value = disposable;
            }
        }
        openPanel(panel) {
            if (this.panel === panel) {
                return;
            }
            this.renderPanel(panel);
        }
        layout(_width, _height) {
            // noop
        }
        closePanel() {
            var _a;
            if (this.panel) {
                if (this.panel.api.renderer === 'onlyWhenVisible') {
                    (_a = this.panel.view.content.element.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(this.panel.view.content.element);
                }
            }
            this.panel = undefined;
        }
        dispose() {
            this.disposable.dispose();
            super.dispose();
        }
    }

    function addGhostImage(dataTransfer, ghostElement, options) {
        var _a, _b;
        // class dockview provides to force ghost image to be drawn on a different layer and prevent weird rendering issues
        addClasses(ghostElement, 'dv-dragged');
        document.body.appendChild(ghostElement);
        dataTransfer.setDragImage(ghostElement, (_a = options === null || options === void 0 ? void 0 : options.x) !== null && _a !== void 0 ? _a : 0, (_b = options === null || options === void 0 ? void 0 : options.y) !== null && _b !== void 0 ? _b : 0);
        setTimeout(() => {
            removeClasses(ghostElement, 'dv-dragged');
            ghostElement.remove();
        }, 0);
    }

    class TabDragHandler extends DragHandler {
        constructor(element, accessor, group, panel) {
            super(element);
            this.accessor = accessor;
            this.group = group;
            this.panel = panel;
            this.panelTransfer = LocalSelectionTransfer.getInstance();
        }
        getData(event) {
            this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, this.panel.id)], PanelTransfer.prototype);
            return {
                dispose: () => {
                    this.panelTransfer.clearData(PanelTransfer.prototype);
                },
            };
        }
    }
    class Tab extends CompositeDisposable {
        get element() {
            return this._element;
        }
        constructor(panel, accessor, group) {
            super();
            this.panel = panel;
            this.accessor = accessor;
            this.group = group;
            this.content = undefined;
            this._onPointDown = new Emitter();
            this.onPointerDown = this._onPointDown.event;
            this._onDropped = new Emitter();
            this.onDrop = this._onDropped.event;
            this._onDragStart = new Emitter();
            this.onDragStart = this._onDragStart.event;
            this._element = document.createElement('div');
            this._element.className = 'dv-tab';
            this._element.tabIndex = 0;
            this._element.draggable = true;
            toggleClass(this.element, 'dv-inactive-tab', true);
            const dragHandler = new TabDragHandler(this._element, this.accessor, this.group, this.panel);
            this.dropTarget = new Droptarget(this._element, {
                acceptedTargetZones: ['left', 'right'],
                overlayModel: { activationSize: { value: 50, type: 'percentage' } },
                canDisplayOverlay: (event, position) => {
                    if (this.group.locked) {
                        return false;
                    }
                    const data = getPanelData();
                    if (data && this.accessor.id === data.viewId) {
                        return true;
                    }
                    return this.group.model.canDisplayOverlay(event, position, 'tab');
                },
                getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
            });
            this.onWillShowOverlay = this.dropTarget.onWillShowOverlay;
            this.addDisposables(this._onPointDown, this._onDropped, this._onDragStart, dragHandler.onDragStart((event) => {
                if (event.dataTransfer) {
                    const style = getComputedStyle(this.element);
                    const newNode = this.element.cloneNode(true);
                    Array.from(style).forEach((key) => newNode.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key)));
                    newNode.style.position = 'absolute';
                    addGhostImage(event.dataTransfer, newNode, {
                        y: -10,
                        x: 30,
                    });
                }
                this._onDragStart.fire(event);
            }), dragHandler, addDisposableListener(this._element, 'pointerdown', (event) => {
                this._onPointDown.fire(event);
            }), this.dropTarget.onDrop((event) => {
                this._onDropped.fire(event);
            }), this.dropTarget);
        }
        setActive(isActive) {
            toggleClass(this.element, 'dv-active-tab', isActive);
            toggleClass(this.element, 'dv-inactive-tab', !isActive);
        }
        setContent(part) {
            if (this.content) {
                this._element.removeChild(this.content.element);
            }
            this.content = part;
            this._element.appendChild(this.content.element);
        }
        dispose() {
            super.dispose();
        }
    }

    class GroupDragHandler extends DragHandler {
        constructor(element, accessor, group) {
            super(element);
            this.accessor = accessor;
            this.group = group;
            this.panelTransfer = LocalSelectionTransfer.getInstance();
            this.addDisposables(addDisposableListener(element, 'pointerdown', (e) => {
                if (e.shiftKey) {
                    /**
                     * You cannot call e.preventDefault() because that will prevent drag events from firing
                     * but we also need to stop any group overlay drag events from occuring
                     * Use a custom event marker that can be checked by the overlay drag events
                     */
                    quasiPreventDefault(e);
                }
            }, true));
        }
        isCancelled(_event) {
            if (this.group.api.location.type === 'floating' && !_event.shiftKey) {
                return true;
            }
            return false;
        }
        getData(dragEvent) {
            const dataTransfer = dragEvent.dataTransfer;
            this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, null)], PanelTransfer.prototype);
            const style = window.getComputedStyle(this.el);
            const bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color');
            const color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color');
            if (dataTransfer) {
                const ghostElement = document.createElement('div');
                ghostElement.style.backgroundColor = bgColor;
                ghostElement.style.color = color;
                ghostElement.style.padding = '2px 8px';
                ghostElement.style.height = '24px';
                ghostElement.style.fontSize = '11px';
                ghostElement.style.lineHeight = '20px';
                ghostElement.style.borderRadius = '12px';
                ghostElement.style.position = 'absolute';
                ghostElement.style.pointerEvents = 'none';
                ghostElement.style.top = '-9999px';
                ghostElement.textContent = `Multiple Panels (${this.group.size})`;
                addGhostImage(dataTransfer, ghostElement, { y: -10, x: 30 });
            }
            return {
                dispose: () => {
                    this.panelTransfer.clearData(PanelTransfer.prototype);
                },
            };
        }
    }

    class VoidContainer extends CompositeDisposable {
        get element() {
            return this._element;
        }
        constructor(accessor, group) {
            super();
            this.accessor = accessor;
            this.group = group;
            this._onDrop = new Emitter();
            this.onDrop = this._onDrop.event;
            this._onDragStart = new Emitter();
            this.onDragStart = this._onDragStart.event;
            this._element = document.createElement('div');
            this._element.className = 'dv-void-container';
            this._element.draggable = true;
            this.addDisposables(this._onDrop, this._onDragStart, addDisposableListener(this._element, 'pointerdown', () => {
                this.accessor.doSetGroupActive(this.group);
            }));
            const handler = new GroupDragHandler(this._element, accessor, group);
            this.dropTraget = new Droptarget(this._element, {
                acceptedTargetZones: ['center'],
                canDisplayOverlay: (event, position) => {
                    const data = getPanelData();
                    if (data && this.accessor.id === data.viewId) {
                        return true;
                    }
                    return group.model.canDisplayOverlay(event, position, 'header_space');
                },
                getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
            });
            this.onWillShowOverlay = this.dropTraget.onWillShowOverlay;
            this.addDisposables(handler, handler.onDragStart((event) => {
                this._onDragStart.fire(event);
            }), this.dropTraget.onDrop((event) => {
                this._onDrop.fire(event);
            }), this.dropTraget);
        }
    }

    class Scrollbar extends CompositeDisposable {
        get element() {
            return this._element;
        }
        constructor(scrollableElement) {
            super();
            this.scrollableElement = scrollableElement;
            this._scrollLeft = 0;
            this._element = document.createElement('div');
            this._element.className = 'dv-scrollable';
            this._horizontalScrollbar = document.createElement('div');
            this._horizontalScrollbar.className = 'dv-scrollbar-horizontal';
            this.element.appendChild(scrollableElement);
            this.element.appendChild(this._horizontalScrollbar);
            this.addDisposables(addDisposableListener(this.element, 'wheel', (event) => {
                this._scrollLeft += event.deltaY * Scrollbar.MouseWheelSpeed;
                this.calculateScrollbarStyles();
            }), addDisposableListener(this._horizontalScrollbar, 'pointerdown', (event) => {
                event.preventDefault();
                toggleClass(this.element, 'dv-scrollable-scrolling', true);
                const originalClientX = event.clientX;
                const originalScrollLeft = this._scrollLeft;
                const onPointerMove = (event) => {
                    const deltaX = event.clientX - originalClientX;
                    const { clientWidth } = this.element;
                    const { scrollWidth } = this.scrollableElement;
                    const p = clientWidth / scrollWidth;
                    this._scrollLeft = originalScrollLeft + deltaX / p;
                    this.calculateScrollbarStyles();
                };
                const onEnd = () => {
                    toggleClass(this.element, 'dv-scrollable-scrolling', false);
                    document.removeEventListener('pointermove', onPointerMove);
                    document.removeEventListener('pointerup', onEnd);
                    document.removeEventListener('pointercancel', onEnd);
                };
                document.addEventListener('pointermove', onPointerMove);
                document.addEventListener('pointerup', onEnd);
                document.addEventListener('pointercancel', onEnd);
            }), addDisposableListener(this.element, 'scroll', () => {
                this.calculateScrollbarStyles();
            }), addDisposableListener(this.scrollableElement, 'scroll', () => {
                this._scrollLeft = this.scrollableElement.scrollLeft;
                this.calculateScrollbarStyles();
            }), watchElementResize(this.element, () => {
                toggleClass(this.element, 'dv-scrollable-resizing', true);
                if (this._animationTimer) {
                    clearTimeout(this._animationTimer);
                }
                this._animationTimer = setTimeout(() => {
                    clearTimeout(this._animationTimer);
                    toggleClass(this.element, 'dv-scrollable-resizing', false);
                }, 500);
                this.calculateScrollbarStyles();
            }));
        }
        calculateScrollbarStyles() {
            const { clientWidth } = this.element;
            const { scrollWidth } = this.scrollableElement;
            const hasScrollbar = scrollWidth > clientWidth;
            if (hasScrollbar) {
                const px = clientWidth * (clientWidth / scrollWidth);
                this._horizontalScrollbar.style.width = `${px}px`;
                this._scrollLeft = clamp(this._scrollLeft, 0, this.scrollableElement.scrollWidth - clientWidth);
                this.scrollableElement.scrollLeft = this._scrollLeft;
                const percentageComplete = this._scrollLeft / (scrollWidth - clientWidth);
                this._horizontalScrollbar.style.left = `${(clientWidth - px) * percentageComplete}px`;
            }
            else {
                this._horizontalScrollbar.style.width = `0px`;
                this._horizontalScrollbar.style.left = `0px`;
                this._scrollLeft = 0;
            }
        }
    }
    Scrollbar.MouseWheelSpeed = 1;

    class Tabs extends CompositeDisposable {
        get showTabsOverflowControl() {
            return this._showTabsOverflowControl;
        }
        set showTabsOverflowControl(value) {
            if (this._showTabsOverflowControl == value) {
                return;
            }
            this._showTabsOverflowControl = value;
            if (value) {
                const observer = new OverflowObserver(this._tabsList);
                this._observerDisposable.value = new CompositeDisposable(observer, observer.onDidChange((event) => {
                    const hasOverflow = event.hasScrollX || event.hasScrollY;
                    this.toggleDropdown({ reset: !hasOverflow });
                }), addDisposableListener(this._tabsList, 'scroll', () => {
                    this.toggleDropdown({ reset: false });
                }));
            }
        }
        get element() {
            return this._element;
        }
        get panels() {
            return this._tabs.map((_) => _.value.panel.id);
        }
        get size() {
            return this._tabs.length;
        }
        get tabs() {
            return this._tabs.map((_) => _.value);
        }
        constructor(group, accessor, options) {
            super();
            this.group = group;
            this.accessor = accessor;
            this._observerDisposable = new MutableDisposable();
            this._tabs = [];
            this.selectedIndex = -1;
            this._showTabsOverflowControl = false;
            this._onTabDragStart = new Emitter();
            this.onTabDragStart = this._onTabDragStart.event;
            this._onDrop = new Emitter();
            this.onDrop = this._onDrop.event;
            this._onWillShowOverlay = new Emitter();
            this.onWillShowOverlay = this._onWillShowOverlay.event;
            this._onOverflowTabsChange = new Emitter();
            this.onOverflowTabsChange = this._onOverflowTabsChange.event;
            this._tabsList = document.createElement('div');
            this._tabsList.className = 'dv-tabs-container dv-horizontal';
            this.showTabsOverflowControl = options.showTabsOverflowControl;
            if (accessor.options.scrollbars === 'native') {
                this._element = this._tabsList;
            }
            else {
                const scrollbar = new Scrollbar(this._tabsList);
                this._element = scrollbar.element;
                this.addDisposables(scrollbar);
            }
            this.addDisposables(this._onOverflowTabsChange, this._observerDisposable, this._onWillShowOverlay, this._onDrop, this._onTabDragStart, addDisposableListener(this.element, 'pointerdown', (event) => {
                if (event.defaultPrevented) {
                    return;
                }
                const isLeftClick = event.button === 0;
                if (isLeftClick) {
                    this.accessor.doSetGroupActive(this.group);
                }
            }), exports.DockviewDisposable.from(() => {
                for (const { value, disposable } of this._tabs) {
                    disposable.dispose();
                    value.dispose();
                }
                this._tabs = [];
            }));
        }
        indexOf(id) {
            return this._tabs.findIndex((tab) => tab.value.panel.id === id);
        }
        isActive(tab) {
            return (this.selectedIndex > -1 &&
                this._tabs[this.selectedIndex].value === tab);
        }
        setActivePanel(panel) {
            let runningWidth = 0;
            for (const tab of this._tabs) {
                const isActivePanel = panel.id === tab.value.panel.id;
                tab.value.setActive(isActivePanel);
                if (isActivePanel) {
                    const element = tab.value.element;
                    const parentElement = element.parentElement;
                    if (runningWidth < parentElement.scrollLeft ||
                        runningWidth + element.clientWidth >
                            parentElement.scrollLeft + parentElement.clientWidth) {
                        parentElement.scrollLeft = runningWidth;
                    }
                }
                runningWidth += tab.value.element.clientWidth;
            }
        }
        openPanel(panel, index = this._tabs.length) {
            if (this._tabs.find((tab) => tab.value.panel.id === panel.id)) {
                return;
            }
            const tab = new Tab(panel, this.accessor, this.group);
            tab.setContent(panel.view.tab);
            const disposable = new CompositeDisposable(tab.onDragStart((event) => {
                this._onTabDragStart.fire({ nativeEvent: event, panel });
            }), tab.onPointerDown((event) => {
                if (event.defaultPrevented) {
                    return;
                }
                const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
                const isFloatingWithOnePanel = this.group.api.location.type === 'floating' &&
                    this.size === 1;
                if (isFloatingGroupsEnabled &&
                    !isFloatingWithOnePanel &&
                    event.shiftKey) {
                    event.preventDefault();
                    const panel = this.accessor.getGroupPanel(tab.panel.id);
                    const { top, left } = tab.element.getBoundingClientRect();
                    const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect();
                    this.accessor.addFloatingGroup(panel, {
                        x: left - rootLeft,
                        y: top - rootTop,
                        inDragMode: true,
                    });
                    return;
                }
                switch (event.button) {
                    case 0: // left click or touch
                        if (this.group.activePanel !== panel) {
                            this.group.model.openPanel(panel);
                        }
                        break;
                }
            }), tab.onDrop((event) => {
                this._onDrop.fire({
                    event: event.nativeEvent,
                    index: this._tabs.findIndex((x) => x.value === tab),
                });
            }), tab.onWillShowOverlay((event) => {
                this._onWillShowOverlay.fire(new WillShowOverlayLocationEvent(event, {
                    kind: 'tab',
                    panel: this.group.activePanel,
                    api: this.accessor.api,
                    group: this.group,
                    getData: getPanelData,
                }));
            }));
            const value = { value: tab, disposable };
            this.addTab(value, index);
        }
        delete(id) {
            const index = this.indexOf(id);
            const tabToRemove = this._tabs.splice(index, 1)[0];
            const { value, disposable } = tabToRemove;
            disposable.dispose();
            value.dispose();
            value.element.remove();
        }
        addTab(tab, index = this._tabs.length) {
            if (index < 0 || index > this._tabs.length) {
                throw new Error('invalid location');
            }
            this._tabsList.insertBefore(tab.value.element, this._tabsList.children[index]);
            this._tabs = [
                ...this._tabs.slice(0, index),
                tab,
                ...this._tabs.slice(index),
            ];
            if (this.selectedIndex < 0) {
                this.selectedIndex = index;
            }
        }
        toggleDropdown(options) {
            const tabs = options.reset
                ? []
                : this._tabs
                    .filter((tab) => !isChildEntirelyVisibleWithinParent(tab.value.element, this._tabsList))
                    .map((x) => x.value.panel.id);
            this._onOverflowTabsChange.fire({ tabs, reset: options.reset });
        }
    }

    const createSvgElementFromPath = (params) => {
        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttributeNS(null, 'height', params.height);
        svg.setAttributeNS(null, 'width', params.width);
        svg.setAttributeNS(null, 'viewBox', params.viewbox);
        svg.setAttributeNS(null, 'aria-hidden', 'false');
        svg.setAttributeNS(null, 'focusable', 'false');
        svg.classList.add('dv-svg');
        const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
        path.setAttributeNS(null, 'd', params.path);
        svg.appendChild(path);
        return svg;
    };
    const createCloseButton = () => createSvgElementFromPath({
        width: '11',
        height: '11',
        viewbox: '0 0 28 28',
        path: 'M2.1 27.3L0 25.2L11.55 13.65L0 2.1L2.1 0L13.65 11.55L25.2 0L27.3 2.1L15.75 13.65L27.3 25.2L25.2 27.3L13.65 15.75L2.1 27.3Z',
    });
    const createExpandMoreButton = () => createSvgElementFromPath({
        width: '11',
        height: '11',
        viewbox: '0 0 24 15',
        path: 'M12 14.15L0 2.15L2.15 0L12 9.9L21.85 0.0499992L24 2.2L12 14.15Z',
    });
    const createChevronRightButton = () => createSvgElementFromPath({
        width: '11',
        height: '11',
        viewbox: '0 0 15 25',
        path: 'M2.15 24.1L0 21.95L9.9 12.05L0 2.15L2.15 0L14.2 12.05L2.15 24.1Z',
    });

    function createDropdownElementHandle() {
        const el = document.createElement('div');
        el.className = 'dv-tabs-overflow-dropdown-default';
        const text = document.createElement('span');
        text.textContent = ``;
        const icon = createChevronRightButton();
        el.appendChild(icon);
        el.appendChild(text);
        return {
            element: el,
            update: (params) => {
                text.textContent = `${params.tabs}`;
            },
        };
    }

    class TabsContainer extends CompositeDisposable {
        get onTabDragStart() {
            return this.tabs.onTabDragStart;
        }
        get panels() {
            return this.tabs.panels;
        }
        get size() {
            return this.tabs.size;
        }
        get hidden() {
            return this._hidden;
        }
        set hidden(value) {
            this._hidden = value;
            this.element.style.display = value ? 'none' : '';
        }
        get element() {
            return this._element;
        }
        constructor(accessor, group) {
            super();
            this.accessor = accessor;
            this.group = group;
            this._hidden = false;
            this.dropdownPart = null;
            this._overflowTabs = [];
            this._dropdownDisposable = new MutableDisposable();
            this._onDrop = new Emitter();
            this.onDrop = this._onDrop.event;
            this._onGroupDragStart = new Emitter();
            this.onGroupDragStart = this._onGroupDragStart.event;
            this._onWillShowOverlay = new Emitter();
            this.onWillShowOverlay = this._onWillShowOverlay.event;
            this._element = document.createElement('div');
            this._element.className = 'dv-tabs-and-actions-container';
            toggleClass(this._element, 'dv-full-width-single-tab', this.accessor.options.singleTabMode === 'fullwidth');
            this.rightActionsContainer = document.createElement('div');
            this.rightActionsContainer.className = 'dv-right-actions-container';
            this.leftActionsContainer = document.createElement('div');
            this.leftActionsContainer.className = 'dv-left-actions-container';
            this.preActionsContainer = document.createElement('div');
            this.preActionsContainer.className = 'dv-pre-actions-container';
            this.tabs = new Tabs(group, accessor, {
                showTabsOverflowControl: !accessor.options.disableTabsOverflowList,
            });
            this.voidContainer = new VoidContainer(this.accessor, this.group);
            this._element.appendChild(this.preActionsContainer);
            this._element.appendChild(this.tabs.element);
            this._element.appendChild(this.leftActionsContainer);
            this._element.appendChild(this.voidContainer.element);
            this._element.appendChild(this.rightActionsContainer);
            this.addDisposables(this.tabs.onDrop((e) => this._onDrop.fire(e)), this.tabs.onWillShowOverlay((e) => this._onWillShowOverlay.fire(e)), accessor.onDidOptionsChange(() => {
                this.tabs.showTabsOverflowControl =
                    !accessor.options.disableTabsOverflowList;
            }), this.tabs.onOverflowTabsChange((event) => {
                this.toggleDropdown(event);
            }), this.tabs, this._onWillShowOverlay, this._onDrop, this._onGroupDragStart, this.voidContainer, this.voidContainer.onDragStart((event) => {
                this._onGroupDragStart.fire({
                    nativeEvent: event,
                    group: this.group,
                });
            }), this.voidContainer.onDrop((event) => {
                this._onDrop.fire({
                    event: event.nativeEvent,
                    index: this.tabs.size,
                });
            }), this.voidContainer.onWillShowOverlay((event) => {
                this._onWillShowOverlay.fire(new WillShowOverlayLocationEvent(event, {
                    kind: 'header_space',
                    panel: this.group.activePanel,
                    api: this.accessor.api,
                    group: this.group,
                    getData: getPanelData,
                }));
            }), addDisposableListener(this.voidContainer.element, 'pointerdown', (event) => {
                if (event.defaultPrevented) {
                    return;
                }
                const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
                if (isFloatingGroupsEnabled &&
                    event.shiftKey &&
                    this.group.api.location.type !== 'floating') {
                    event.preventDefault();
                    const { top, left } = this.element.getBoundingClientRect();
                    const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect();
                    this.accessor.addFloatingGroup(this.group, {
                        x: left - rootLeft + 20,
                        y: top - rootTop + 20,
                        inDragMode: true,
                    });
                }
            }));
        }
        show() {
            if (!this.hidden) {
                this.element.style.display = '';
            }
        }
        hide() {
            this._element.style.display = 'none';
        }
        setRightActionsElement(element) {
            if (this.rightActions === element) {
                return;
            }
            if (this.rightActions) {
                this.rightActions.remove();
                this.rightActions = undefined;
            }
            if (element) {
                this.rightActionsContainer.appendChild(element);
                this.rightActions = element;
            }
        }
        setLeftActionsElement(element) {
            if (this.leftActions === element) {
                return;
            }
            if (this.leftActions) {
                this.leftActions.remove();
                this.leftActions = undefined;
            }
            if (element) {
                this.leftActionsContainer.appendChild(element);
                this.leftActions = element;
            }
        }
        setPrefixActionsElement(element) {
            if (this.preActions === element) {
                return;
            }
            if (this.preActions) {
                this.preActions.remove();
                this.preActions = undefined;
            }
            if (element) {
                this.preActionsContainer.appendChild(element);
                this.preActions = element;
            }
        }
        isActive(tab) {
            return this.tabs.isActive(tab);
        }
        indexOf(id) {
            return this.tabs.indexOf(id);
        }
        setActive(_isGroupActive) {
            // noop
        }
        delete(id) {
            this.tabs.delete(id);
            this.updateClassnames();
        }
        setActivePanel(panel) {
            this.tabs.setActivePanel(panel);
        }
        openPanel(panel, index = this.tabs.size) {
            this.tabs.openPanel(panel, index);
            this.updateClassnames();
        }
        closePanel(panel) {
            this.delete(panel.id);
        }
        updateClassnames() {
            toggleClass(this._element, 'dv-single-tab', this.size === 1);
        }
        toggleDropdown(options) {
            const tabs = options.reset ? [] : options.tabs;
            this._overflowTabs = tabs;
            if (this._overflowTabs.length > 0 && this.dropdownPart) {
                this.dropdownPart.update({ tabs: tabs.length });
                return;
            }
            if (this._overflowTabs.length === 0) {
                this._dropdownDisposable.dispose();
                return;
            }
            const root = document.createElement('div');
            root.className = 'dv-tabs-overflow-dropdown-root';
            const part = createDropdownElementHandle();
            part.update({ tabs: tabs.length });
            this.dropdownPart = part;
            root.appendChild(part.element);
            this.rightActionsContainer.prepend(root);
            this._dropdownDisposable.value = new CompositeDisposable(exports.DockviewDisposable.from(() => {
                var _a, _b;
                root.remove();
                (_b = (_a = this.dropdownPart) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
                this.dropdownPart = null;
            }), addDisposableListener(root, 'pointerdown', (event) => {
                event.preventDefault();
            }, { capture: true }), addDisposableListener(root, 'click', (event) => {
                const el = document.createElement('div');
                el.style.overflow = 'auto';
                el.className = 'dv-tabs-overflow-container';
                for (const tab of this.tabs.tabs.filter((tab) => this._overflowTabs.includes(tab.panel.id))) {
                    const panelObject = this.group.panels.find((panel) => panel === tab.panel);
                    const tabComponent = panelObject.view.createTabRenderer('headerOverflow');
                    const child = tabComponent.element;
                    const wrapper = document.createElement('div');
                    toggleClass(wrapper, 'dv-tab', true);
                    toggleClass(wrapper, 'dv-active-tab', panelObject.api.isActive);
                    toggleClass(wrapper, 'dv-inactive-tab', !panelObject.api.isActive);
                    wrapper.addEventListener('mousedown', () => {
                        this.accessor.popupService.close();
                        tab.element.scrollIntoView();
                        tab.panel.api.setActive();
                    });
                    wrapper.appendChild(child);
                    el.appendChild(wrapper);
                }
                this.accessor.popupService.openPopover(el, {
                    x: event.clientX,
                    y: event.clientY,
                });
            }));
        }
    }

    class DockviewUnhandledDragOverEvent extends AcceptableEvent {
        constructor(nativeEvent, target, position, getData, group) {
            super();
            this.nativeEvent = nativeEvent;
            this.target = target;
            this.position = position;
            this.getData = getData;
            this.group = group;
        }
    }
    const PROPERTY_KEYS_DOCKVIEW = (() => {
        /**
         * by readong the keys from an empty value object TypeScript will error
         * when we add or remove new properties to `DockviewOptions`
         */
        const properties = {
            disableAutoResizing: undefined,
            hideBorders: undefined,
            singleTabMode: undefined,
            disableFloatingGroups: undefined,
            floatingGroupBounds: undefined,
            popoutUrl: undefined,
            defaultRenderer: undefined,
            debug: undefined,
            rootOverlayModel: undefined,
            locked: undefined,
            disableDnd: undefined,
            className: undefined,
            noPanelsOverlay: undefined,
            dndEdges: undefined,
            theme: undefined,
            disableTabsOverflowList: undefined,
            scrollbars: undefined,
        };
        return Object.keys(properties);
    })();
    function isPanelOptionsWithPanel(data) {
        if (data.referencePanel) {
            return true;
        }
        return false;
    }
    function isPanelOptionsWithGroup(data) {
        if (data.referenceGroup) {
            return true;
        }
        return false;
    }
    function isGroupOptionsWithPanel(data) {
        if (data.referencePanel) {
            return true;
        }
        return false;
    }
    function isGroupOptionsWithGroup(data) {
        if (data.referenceGroup) {
            return true;
        }
        return false;
    }

    class DockviewDidDropEvent extends DockviewEvent {
        get nativeEvent() {
            return this.options.nativeEvent;
        }
        get position() {
            return this.options.position;
        }
        get panel() {
            return this.options.panel;
        }
        get group() {
            return this.options.group;
        }
        get api() {
            return this.options.api;
        }
        constructor(options) {
            super();
            this.options = options;
        }
        getData() {
            return this.options.getData();
        }
    }
    class DockviewWillDropEvent extends DockviewDidDropEvent {
        get kind() {
            return this._kind;
        }
        constructor(options) {
            super(options);
            this._kind = options.kind;
        }
    }
    class WillShowOverlayLocationEvent {
        get kind() {
            return this.options.kind;
        }
        get nativeEvent() {
            return this.event.nativeEvent;
        }
        get position() {
            return this.event.position;
        }
        get defaultPrevented() {
            return this.event.defaultPrevented;
        }
        get panel() {
            return this.options.panel;
        }
        get api() {
            return this.options.api;
        }
        get group() {
            return this.options.group;
        }
        preventDefault() {
            this.event.preventDefault();
        }
        getData() {
            return this.options.getData();
        }
        constructor(event, options) {
            this.event = event;
            this.options = options;
        }
    }
    class DockviewGroupPanelModel extends CompositeDisposable {
        get element() {
            throw new Error('dockview: not supported');
        }
        get activePanel() {
            return this._activePanel;
        }
        get locked() {
            return this._locked;
        }
        set locked(value) {
            this._locked = value;
            toggleClass(this.container, 'dv-locked-groupview', value === 'no-drop-target' || value);
        }
        get isActive() {
            return this._isGroupActive;
        }
        get panels() {
            return this._panels;
        }
        get size() {
            return this._panels.length;
        }
        get isEmpty() {
            return this._panels.length === 0;
        }
        get hasWatermark() {
            return !!(this.watermark && this.container.contains(this.watermark.element));
        }
        get header() {
            return this.tabsContainer;
        }
        get isContentFocused() {
            if (!document.activeElement) {
                return false;
            }
            return isAncestor(document.activeElement, this.contentContainer.element);
        }
        get location() {
            return this._location;
        }
        set location(value) {
            this._location = value;
            toggleClass(this.container, 'dv-groupview-floating', false);
            toggleClass(this.container, 'dv-groupview-popout', false);
            switch (value.type) {
                case 'grid':
                    this.contentContainer.dropTarget.setTargetZones([
                        'top',
                        'bottom',
                        'left',
                        'right',
                        'center',
                    ]);
                    break;
                case 'floating':
                    this.contentContainer.dropTarget.setTargetZones(['center']);
                    this.contentContainer.dropTarget.setTargetZones(value
                        ? ['center']
                        : ['top', 'bottom', 'left', 'right', 'center']);
                    toggleClass(this.container, 'dv-groupview-floating', true);
                    break;
                case 'popout':
                    this.contentContainer.dropTarget.setTargetZones(['center']);
                    toggleClass(this.container, 'dv-groupview-popout', true);
                    break;
            }
            this.groupPanel.api._onDidLocationChange.fire({
                location: this.location,
            });
        }
        constructor(container, accessor, id, options, groupPanel) {
            var _a;
            super();
            this.container = container;
            this.accessor = accessor;
            this.id = id;
            this.options = options;
            this.groupPanel = groupPanel;
            this._isGroupActive = false;
            this._locked = false;
            this._location = { type: 'grid' };
            this.mostRecentlyUsed = [];
            this._overwriteRenderContainer = null;
            this._overwriteDropTargetContainer = null;
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            this._width = 0;
            this._height = 0;
            this._panels = [];
            this._panelDisposables = new Map();
            this._onMove = new Emitter();
            this.onMove = this._onMove.event;
            this._onDidDrop = new Emitter();
            this.onDidDrop = this._onDidDrop.event;
            this._onWillDrop = new Emitter();
            this.onWillDrop = this._onWillDrop.event;
            this._onWillShowOverlay = new Emitter();
            this.onWillShowOverlay = this._onWillShowOverlay.event;
            this._onTabDragStart = new Emitter();
            this.onTabDragStart = this._onTabDragStart.event;
            this._onGroupDragStart = new Emitter();
            this.onGroupDragStart = this._onGroupDragStart.event;
            this._onDidAddPanel = new Emitter();
            this.onDidAddPanel = this._onDidAddPanel.event;
            this._onDidPanelTitleChange = new Emitter();
            this.onDidPanelTitleChange = this._onDidPanelTitleChange.event;
            this._onDidPanelParametersChange = new Emitter();
            this.onDidPanelParametersChange = this._onDidPanelParametersChange.event;
            this._onDidRemovePanel = new Emitter();
            this.onDidRemovePanel = this._onDidRemovePanel.event;
            this._onDidActivePanelChange = new Emitter();
            this.onDidActivePanelChange = this._onDidActivePanelChange.event;
            this._onUnhandledDragOverEvent = new Emitter();
            this.onUnhandledDragOverEvent = this._onUnhandledDragOverEvent.event;
            toggleClass(this.container, 'dv-groupview', true);
            this._api = new DockviewApi(this.accessor);
            this.tabsContainer = new TabsContainer(this.accessor, this.groupPanel);
            this.contentContainer = new ContentContainer(this.accessor, this);
            container.append(this.tabsContainer.element, this.contentContainer.element);
            this.header.hidden = !!options.hideHeader;
            this.locked = (_a = options.locked) !== null && _a !== void 0 ? _a : false;
            this.addDisposables(this._onTabDragStart, this._onGroupDragStart, this._onWillShowOverlay, this.tabsContainer.onTabDragStart((event) => {
                this._onTabDragStart.fire(event);
            }), this.tabsContainer.onGroupDragStart((event) => {
                this._onGroupDragStart.fire(event);
            }), this.tabsContainer.onDrop((event) => {
                this.handleDropEvent('header', event.event, 'center', event.index);
            }), this.contentContainer.onDidFocus(() => {
                this.accessor.doSetGroupActive(this.groupPanel);
            }), this.contentContainer.onDidBlur(() => {
                // noop
            }), this.contentContainer.dropTarget.onDrop((event) => {
                this.handleDropEvent('content', event.nativeEvent, event.position);
            }), this.tabsContainer.onWillShowOverlay((event) => {
                this._onWillShowOverlay.fire(event);
            }), this.contentContainer.dropTarget.onWillShowOverlay((event) => {
                this._onWillShowOverlay.fire(new WillShowOverlayLocationEvent(event, {
                    kind: 'content',
                    panel: this.activePanel,
                    api: this._api,
                    group: this.groupPanel,
                    getData: getPanelData,
                }));
            }), this._onMove, this._onDidChange, this._onDidDrop, this._onWillDrop, this._onDidAddPanel, this._onDidRemovePanel, this._onDidActivePanelChange, this._onUnhandledDragOverEvent, this._onDidPanelTitleChange, this._onDidPanelParametersChange);
        }
        focusContent() {
            this.contentContainer.element.focus();
        }
        set renderContainer(value) {
            this.panels.forEach((panel) => {
                this.renderContainer.detatch(panel);
            });
            this._overwriteRenderContainer = value;
            this.panels.forEach((panel) => {
                this.rerender(panel);
            });
        }
        get renderContainer() {
            var _a;
            return ((_a = this._overwriteRenderContainer) !== null && _a !== void 0 ? _a : this.accessor.overlayRenderContainer);
        }
        set dropTargetContainer(value) {
            this._overwriteDropTargetContainer = value;
        }
        get dropTargetContainer() {
            var _a;
            return ((_a = this._overwriteDropTargetContainer) !== null && _a !== void 0 ? _a : this.accessor.rootDropTargetContainer);
        }
        initialize() {
            if (this.options.panels) {
                this.options.panels.forEach((panel) => {
                    this.doAddPanel(panel);
                });
            }
            if (this.options.activePanel) {
                this.openPanel(this.options.activePanel);
            }
            // must be run after the constructor otherwise this.parent may not be
            // correctly initialized
            this.setActive(this.isActive, true);
            this.updateContainer();
            if (this.accessor.options.createRightHeaderActionComponent) {
                this._rightHeaderActions =
                    this.accessor.options.createRightHeaderActionComponent(this.groupPanel);
                this.addDisposables(this._rightHeaderActions);
                this._rightHeaderActions.init({
                    containerApi: this._api,
                    api: this.groupPanel.api,
                    group: this.groupPanel,
                });
                this.tabsContainer.setRightActionsElement(this._rightHeaderActions.element);
            }
            if (this.accessor.options.createLeftHeaderActionComponent) {
                this._leftHeaderActions =
                    this.accessor.options.createLeftHeaderActionComponent(this.groupPanel);
                this.addDisposables(this._leftHeaderActions);
                this._leftHeaderActions.init({
                    containerApi: this._api,
                    api: this.groupPanel.api,
                    group: this.groupPanel,
                });
                this.tabsContainer.setLeftActionsElement(this._leftHeaderActions.element);
            }
            if (this.accessor.options.createPrefixHeaderActionComponent) {
                this._prefixHeaderActions =
                    this.accessor.options.createPrefixHeaderActionComponent(this.groupPanel);
                this.addDisposables(this._prefixHeaderActions);
                this._prefixHeaderActions.init({
                    containerApi: this._api,
                    api: this.groupPanel.api,
                    group: this.groupPanel,
                });
                this.tabsContainer.setPrefixActionsElement(this._prefixHeaderActions.element);
            }
        }
        rerender(panel) {
            this.contentContainer.renderPanel(panel, { asActive: false });
        }
        indexOf(panel) {
            return this.tabsContainer.indexOf(panel.id);
        }
        toJSON() {
            var _a;
            const result = {
                views: this.tabsContainer.panels,
                activeView: (_a = this._activePanel) === null || _a === void 0 ? void 0 : _a.id,
                id: this.id,
            };
            if (this.locked !== false) {
                result.locked = this.locked;
            }
            if (this.header.hidden) {
                result.hideHeader = true;
            }
            return result;
        }
        moveToNext(options) {
            if (!options) {
                options = {};
            }
            if (!options.panel) {
                options.panel = this.activePanel;
            }
            const index = options.panel ? this.panels.indexOf(options.panel) : -1;
            let normalizedIndex;
            if (index < this.panels.length - 1) {
                normalizedIndex = index + 1;
            }
            else if (!options.suppressRoll) {
                normalizedIndex = 0;
            }
            else {
                return;
            }
            this.openPanel(this.panels[normalizedIndex]);
        }
        moveToPrevious(options) {
            if (!options) {
                options = {};
            }
            if (!options.panel) {
                options.panel = this.activePanel;
            }
            if (!options.panel) {
                return;
            }
            const index = this.panels.indexOf(options.panel);
            let normalizedIndex;
            if (index > 0) {
                normalizedIndex = index - 1;
            }
            else if (!options.suppressRoll) {
                normalizedIndex = this.panels.length - 1;
            }
            else {
                return;
            }
            this.openPanel(this.panels[normalizedIndex]);
        }
        containsPanel(panel) {
            return this.panels.includes(panel);
        }
        init(_params) {
            //noop
        }
        update(_params) {
            //noop
        }
        focus() {
            var _a;
            (_a = this._activePanel) === null || _a === void 0 ? void 0 : _a.focus();
        }
        openPanel(panel, options = {}) {
            /**
             * set the panel group
             * add the panel
             * check if group active
             * check if panel active
             */
            if (typeof options.index !== 'number' ||
                options.index > this.panels.length) {
                options.index = this.panels.length;
            }
            const skipSetActive = !!options.skipSetActive;
            // ensure the group is updated before we fire any events
            panel.updateParentGroup(this.groupPanel, {
                skipSetActive: options.skipSetActive,
            });
            this.doAddPanel(panel, options.index, {
                skipSetActive: skipSetActive,
            });
            if (this._activePanel === panel) {
                this.contentContainer.renderPanel(panel, { asActive: true });
                return;
            }
            if (!skipSetActive) {
                this.doSetActivePanel(panel);
            }
            if (!options.skipSetGroupActive) {
                this.accessor.doSetGroupActive(this.groupPanel);
            }
            if (!options.skipSetActive) {
                this.updateContainer();
            }
        }
        removePanel(groupItemOrId, options = {
            skipSetActive: false,
        }) {
            const id = typeof groupItemOrId === 'string'
                ? groupItemOrId
                : groupItemOrId.id;
            const panelToRemove = this._panels.find((panel) => panel.id === id);
            if (!panelToRemove) {
                throw new Error('invalid operation');
            }
            return this._removePanel(panelToRemove, options);
        }
        closeAllPanels() {
            if (this.panels.length > 0) {
                // take a copy since we will be edting the array as we iterate through
                const arrPanelCpy = [...this.panels];
                for (const panel of arrPanelCpy) {
                    this.doClose(panel);
                }
            }
            else {
                this.accessor.removeGroup(this.groupPanel);
            }
        }
        closePanel(panel) {
            this.doClose(panel);
        }
        doClose(panel) {
            const isLast = this.panels.length === 1 && this.accessor.groups.length === 1;
            this.accessor.removePanel(panel, isLast && this.accessor.options.noPanelsOverlay === 'emptyGroup'
                ? { removeEmptyGroup: false }
                : undefined);
        }
        isPanelActive(panel) {
            return this._activePanel === panel;
        }
        updateActions(element) {
            this.tabsContainer.setRightActionsElement(element);
        }
        setActive(isGroupActive, force = false) {
            if (!force && this.isActive === isGroupActive) {
                return;
            }
            this._isGroupActive = isGroupActive;
            toggleClass(this.container, 'dv-active-group', isGroupActive);
            toggleClass(this.container, 'dv-inactive-group', !isGroupActive);
            this.tabsContainer.setActive(this.isActive);
            if (!this._activePanel && this.panels.length > 0) {
                this.doSetActivePanel(this.panels[0]);
            }
            this.updateContainer();
        }
        layout(width, height) {
            var _a;
            this._width = width;
            this._height = height;
            this.contentContainer.layout(this._width, this._height);
            if ((_a = this._activePanel) === null || _a === void 0 ? void 0 : _a.layout) {
                this._activePanel.layout(this._width, this._height);
            }
        }
        _removePanel(panel, options) {
            const isActivePanel = this._activePanel === panel;
            this.doRemovePanel(panel);
            if (isActivePanel && this.panels.length > 0) {
                const nextPanel = this.mostRecentlyUsed[0];
                this.openPanel(nextPanel, {
                    skipSetActive: options.skipSetActive,
                    skipSetGroupActive: options.skipSetActiveGroup,
                });
            }
            if (this._activePanel && this.panels.length === 0) {
                this.doSetActivePanel(undefined);
            }
            if (!options.skipSetActive) {
                this.updateContainer();
            }
            return panel;
        }
        doRemovePanel(panel) {
            const index = this.panels.indexOf(panel);
            if (this._activePanel === panel) {
                this.contentContainer.closePanel();
            }
            this.tabsContainer.delete(panel.id);
            this._panels.splice(index, 1);
            if (this.mostRecentlyUsed.includes(panel)) {
                const index = this.mostRecentlyUsed.indexOf(panel);
                this.mostRecentlyUsed.splice(index, 1);
            }
            const disposable = this._panelDisposables.get(panel.id);
            if (disposable) {
                disposable.dispose();
                this._panelDisposables.delete(panel.id);
            }
            this._onDidRemovePanel.fire({ panel });
        }
        doAddPanel(panel, index = this.panels.length, options = { skipSetActive: false }) {
            const existingPanel = this._panels.indexOf(panel);
            const hasExistingPanel = existingPanel > -1;
            this.tabsContainer.show();
            this.contentContainer.show();
            this.tabsContainer.openPanel(panel, index);
            if (!options.skipSetActive) {
                this.contentContainer.openPanel(panel);
            }
            if (hasExistingPanel) {
                // TODO - need to ensure ordering hasn't changed and if it has need to re-order this.panels
                return;
            }
            this.updateMru(panel);
            this.panels.splice(index, 0, panel);
            this._panelDisposables.set(panel.id, new CompositeDisposable(panel.api.onDidTitleChange((event) => this._onDidPanelTitleChange.fire(event)), panel.api.onDidParametersChange((event) => this._onDidPanelParametersChange.fire(event))));
            this._onDidAddPanel.fire({ panel });
        }
        doSetActivePanel(panel) {
            if (this._activePanel === panel) {
                return;
            }
            this._activePanel = panel;
            if (panel) {
                this.tabsContainer.setActivePanel(panel);
                panel.layout(this._width, this._height);
                this.updateMru(panel);
                this._onDidActivePanelChange.fire({
                    panel,
                });
            }
        }
        updateMru(panel) {
            if (this.mostRecentlyUsed.includes(panel)) {
                this.mostRecentlyUsed.splice(this.mostRecentlyUsed.indexOf(panel), 1);
            }
            this.mostRecentlyUsed = [panel, ...this.mostRecentlyUsed];
        }
        updateContainer() {
            var _a, _b;
            this.panels.forEach((panel) => panel.runEvents());
            if (this.isEmpty && !this.watermark) {
                const watermark = this.accessor.createWatermarkComponent();
                watermark.init({
                    containerApi: this._api,
                    group: this.groupPanel,
                });
                this.watermark = watermark;
                addDisposableListener(this.watermark.element, 'pointerdown', () => {
                    if (!this.isActive) {
                        this.accessor.doSetGroupActive(this.groupPanel);
                    }
                });
                this.contentContainer.element.appendChild(this.watermark.element);
            }
            if (!this.isEmpty && this.watermark) {
                this.watermark.element.remove();
                (_b = (_a = this.watermark).dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
                this.watermark = undefined;
            }
        }
        canDisplayOverlay(event, position, target) {
            const firedEvent = new DockviewUnhandledDragOverEvent(event, target, position, getPanelData, this.accessor.getPanel(this.id));
            this._onUnhandledDragOverEvent.fire(firedEvent);
            return firedEvent.isAccepted;
        }
        handleDropEvent(type, event, position, index) {
            if (this.locked === 'no-drop-target') {
                return;
            }
            function getKind() {
                switch (type) {
                    case 'header':
                        return typeof index === 'number' ? 'tab' : 'header_space';
                    case 'content':
                        return 'content';
                }
            }
            const panel = typeof index === 'number' ? this.panels[index] : undefined;
            const willDropEvent = new DockviewWillDropEvent({
                nativeEvent: event,
                position,
                panel,
                getData: () => getPanelData(),
                kind: getKind(),
                group: this.groupPanel,
                api: this._api,
            });
            this._onWillDrop.fire(willDropEvent);
            if (willDropEvent.defaultPrevented) {
                return;
            }
            const data = getPanelData();
            if (data && data.viewId === this.accessor.id) {
                if (type === 'content') {
                    if (data.groupId === this.id) {
                        // don't allow to drop on self for center position
                        if (position === 'center') {
                            return;
                        }
                        if (data.panelId === null) {
                            // don't allow group move to drop anywhere on self
                            return;
                        }
                    }
                }
                if (type === 'header') {
                    if (data.groupId === this.id) {
                        if (data.panelId === null) {
                            return;
                        }
                    }
                }
                if (data.panelId === null) {
                    // this is a group move dnd event
                    const { groupId } = data;
                    this._onMove.fire({
                        target: position,
                        groupId: groupId,
                        index,
                    });
                    return;
                }
                const fromSameGroup = this.tabsContainer.indexOf(data.panelId) !== -1;
                if (fromSameGroup && this.tabsContainer.size === 1) {
                    return;
                }
                const { groupId, panelId } = data;
                const isSameGroup = this.id === groupId;
                if (isSameGroup && !position) {
                    const oldIndex = this.tabsContainer.indexOf(panelId);
                    if (oldIndex === index) {
                        return;
                    }
                }
                this._onMove.fire({
                    target: position,
                    groupId: data.groupId,
                    itemId: data.panelId,
                    index,
                });
            }
            else {
                this._onDidDrop.fire(new DockviewDidDropEvent({
                    nativeEvent: event,
                    position,
                    panel,
                    getData: () => getPanelData(),
                    group: this.groupPanel,
                    api: this._api,
                }));
            }
        }
        dispose() {
            var _a, _b, _c;
            super.dispose();
            (_a = this.watermark) === null || _a === void 0 ? void 0 : _a.element.remove();
            (_c = (_b = this.watermark) === null || _b === void 0 ? void 0 : _b.dispose) === null || _c === void 0 ? void 0 : _c.call(_b);
            this.watermark = undefined;
            for (const panel of this.panels) {
                panel.dispose();
            }
            this.tabsContainer.dispose();
            this.contentContainer.dispose();
        }
    }

    class GridviewPanelApiImpl extends PanelApiImpl {
        constructor(id, component, panel) {
            super(id, component);
            this._onDidConstraintsChangeInternal = new Emitter();
            this.onDidConstraintsChangeInternal = this._onDidConstraintsChangeInternal.event;
            this._onDidConstraintsChange = new Emitter();
            this.onDidConstraintsChange = this._onDidConstraintsChange.event;
            this._onDidSizeChange = new Emitter();
            this.onDidSizeChange = this._onDidSizeChange.event;
            this.addDisposables(this._onDidConstraintsChangeInternal, this._onDidConstraintsChange, this._onDidSizeChange);
            if (panel) {
                this.initialize(panel);
            }
        }
        setConstraints(value) {
            this._onDidConstraintsChangeInternal.fire(value);
        }
        setSize(event) {
            this._onDidSizeChange.fire(event);
        }
    }

    class GridviewPanel extends BasePanelView {
        get priority() {
            return this._priority;
        }
        get snap() {
            return this._snap;
        }
        get minimumWidth() {
            /**
             * defer to protected function to allow subclasses to override easily.
             * see https://github.com/microsoft/TypeScript/issues/338
             */
            return this.__minimumWidth();
        }
        get minimumHeight() {
            /**
             * defer to protected function to allow subclasses to override easily.
             * see https://github.com/microsoft/TypeScript/issues/338
             */
            return this.__minimumHeight();
        }
        get maximumHeight() {
            /**
             * defer to protected function to allow subclasses to override easily.
             * see https://github.com/microsoft/TypeScript/issues/338
             */
            return this.__maximumHeight();
        }
        get maximumWidth() {
            /**
             * defer to protected function to allow subclasses to override easily.
             * see https://github.com/microsoft/TypeScript/issues/338
             */
            return this.__maximumWidth();
        }
        __minimumWidth() {
            const width = typeof this._minimumWidth === 'function'
                ? this._minimumWidth()
                : this._minimumWidth;
            if (width !== this._evaluatedMinimumWidth) {
                this._evaluatedMinimumWidth = width;
                this.updateConstraints();
            }
            return width;
        }
        __maximumWidth() {
            const width = typeof this._maximumWidth === 'function'
                ? this._maximumWidth()
                : this._maximumWidth;
            if (width !== this._evaluatedMaximumWidth) {
                this._evaluatedMaximumWidth = width;
                this.updateConstraints();
            }
            return width;
        }
        __minimumHeight() {
            const height = typeof this._minimumHeight === 'function'
                ? this._minimumHeight()
                : this._minimumHeight;
            if (height !== this._evaluatedMinimumHeight) {
                this._evaluatedMinimumHeight = height;
                this.updateConstraints();
            }
            return height;
        }
        __maximumHeight() {
            const height = typeof this._maximumHeight === 'function'
                ? this._maximumHeight()
                : this._maximumHeight;
            if (height !== this._evaluatedMaximumHeight) {
                this._evaluatedMaximumHeight = height;
                this.updateConstraints();
            }
            return height;
        }
        get isActive() {
            return this.api.isActive;
        }
        get isVisible() {
            return this.api.isVisible;
        }
        constructor(id, component, options, api) {
            super(id, component, api !== null && api !== void 0 ? api : new GridviewPanelApiImpl(id, component));
            this._evaluatedMinimumWidth = 0;
            this._evaluatedMaximumWidth = Number.MAX_SAFE_INTEGER;
            this._evaluatedMinimumHeight = 0;
            this._evaluatedMaximumHeight = Number.MAX_SAFE_INTEGER;
            this._minimumWidth = 0;
            this._minimumHeight = 0;
            this._maximumWidth = Number.MAX_SAFE_INTEGER;
            this._maximumHeight = Number.MAX_SAFE_INTEGER;
            this._snap = false;
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            if (typeof (options === null || options === void 0 ? void 0 : options.minimumWidth) === 'number') {
                this._minimumWidth = options.minimumWidth;
            }
            if (typeof (options === null || options === void 0 ? void 0 : options.maximumWidth) === 'number') {
                this._maximumWidth = options.maximumWidth;
            }
            if (typeof (options === null || options === void 0 ? void 0 : options.minimumHeight) === 'number') {
                this._minimumHeight = options.minimumHeight;
            }
            if (typeof (options === null || options === void 0 ? void 0 : options.maximumHeight) === 'number') {
                this._maximumHeight = options.maximumHeight;
            }
            this.api.initialize(this); // TODO: required to by-pass 'super before this' requirement
            this.addDisposables(this.api.onWillVisibilityChange((event) => {
                const { isVisible } = event;
                const { accessor } = this._params;
                accessor.setVisible(this, isVisible);
            }), this.api.onActiveChange(() => {
                const { accessor } = this._params;
                accessor.doSetGroupActive(this);
            }), this.api.onDidConstraintsChangeInternal((event) => {
                if (typeof event.minimumWidth === 'number' ||
                    typeof event.minimumWidth === 'function') {
                    this._minimumWidth = event.minimumWidth;
                }
                if (typeof event.minimumHeight === 'number' ||
                    typeof event.minimumHeight === 'function') {
                    this._minimumHeight = event.minimumHeight;
                }
                if (typeof event.maximumWidth === 'number' ||
                    typeof event.maximumWidth === 'function') {
                    this._maximumWidth = event.maximumWidth;
                }
                if (typeof event.maximumHeight === 'number' ||
                    typeof event.maximumHeight === 'function') {
                    this._maximumHeight = event.maximumHeight;
                }
            }), this.api.onDidSizeChange((event) => {
                this._onDidChange.fire({
                    height: event.height,
                    width: event.width,
                });
            }), this._onDidChange);
        }
        setVisible(isVisible) {
            this.api._onDidVisibilityChange.fire({ isVisible });
        }
        setActive(isActive) {
            this.api._onDidActiveChange.fire({ isActive });
        }
        init(parameters) {
            if (parameters.maximumHeight) {
                this._maximumHeight = parameters.maximumHeight;
            }
            if (parameters.minimumHeight) {
                this._minimumHeight = parameters.minimumHeight;
            }
            if (parameters.maximumWidth) {
                this._maximumWidth = parameters.maximumWidth;
            }
            if (parameters.minimumWidth) {
                this._minimumWidth = parameters.minimumWidth;
            }
            this._priority = parameters.priority;
            this._snap = !!parameters.snap;
            super.init(parameters);
            if (typeof parameters.isVisible === 'boolean') {
                this.setVisible(parameters.isVisible);
            }
        }
        updateConstraints() {
            this.api._onDidConstraintsChange.fire({
                minimumWidth: this._evaluatedMinimumWidth,
                maximumWidth: this._evaluatedMaximumWidth,
                minimumHeight: this._evaluatedMinimumHeight,
                maximumHeight: this._evaluatedMaximumHeight,
            });
        }
        toJSON() {
            const state = super.toJSON();
            const maximum = (value) => value === Number.MAX_SAFE_INTEGER ? undefined : value;
            const minimum = (value) => (value <= 0 ? undefined : value);
            return Object.assign(Object.assign({}, state), { minimumHeight: minimum(this.minimumHeight), maximumHeight: maximum(this.maximumHeight), minimumWidth: minimum(this.minimumWidth), maximumWidth: maximum(this.maximumWidth), snap: this.snap, priority: this.priority });
        }
    }

    const NOT_INITIALIZED_MESSAGE = 'dockview: DockviewGroupPanelApiImpl not initialized';
    class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
        get location() {
            if (!this._group) {
                throw new Error(NOT_INITIALIZED_MESSAGE);
            }
            return this._group.model.location;
        }
        constructor(id, accessor) {
            super(id, '__dockviewgroup__');
            this.accessor = accessor;
            this._onDidLocationChange = new Emitter();
            this.onDidLocationChange = this._onDidLocationChange.event;
            this._onDidActivePanelChange = new Emitter();
            this.onDidActivePanelChange = this._onDidActivePanelChange.event;
            this.addDisposables(this._onDidLocationChange, this._onDidActivePanelChange);
        }
        close() {
            if (!this._group) {
                return;
            }
            return this.accessor.removeGroup(this._group);
        }
        getWindow() {
            return this.location.type === 'popout'
                ? this.location.getWindow()
                : window;
        }
        moveTo(options) {
            var _a, _b, _c;
            if (!this._group) {
                throw new Error(NOT_INITIALIZED_MESSAGE);
            }
            const group = (_a = options.group) !== null && _a !== void 0 ? _a : this.accessor.addGroup({
                direction: positionToDirection((_b = options.position) !== null && _b !== void 0 ? _b : 'right'),
                skipSetActive: true,
            });
            this.accessor.moveGroupOrPanel({
                from: { groupId: this._group.id },
                to: {
                    group,
                    position: options.group
                        ? (_c = options.position) !== null && _c !== void 0 ? _c : 'center'
                        : 'center',
                    index: options.index,
                },
            });
        }
        maximize() {
            if (!this._group) {
                throw new Error(NOT_INITIALIZED_MESSAGE);
            }
            if (this.location.type !== 'grid') {
                // only grid groups can be maximized
                return;
            }
            this.accessor.maximizeGroup(this._group);
        }
        isMaximized() {
            if (!this._group) {
                throw new Error(NOT_INITIALIZED_MESSAGE);
            }
            return this.accessor.isMaximizedGroup(this._group);
        }
        exitMaximized() {
            if (!this._group) {
                throw new Error(NOT_INITIALIZED_MESSAGE);
            }
            if (this.isMaximized()) {
                this.accessor.exitMaximizedGroup();
            }
        }
        initialize(group) {
            this._group = group;
        }
    }

    const MINIMUM_DOCKVIEW_GROUP_PANEL_WIDTH = 100;
    const MINIMUM_DOCKVIEW_GROUP_PANEL_HEIGHT = 100;
    class DockviewGroupPanel extends GridviewPanel {
        get minimumWidth() {
            var _a;
            const activePanelMinimumWidth = (_a = this.activePanel) === null || _a === void 0 ? void 0 : _a.minimumWidth;
            if (typeof activePanelMinimumWidth === 'number') {
                return activePanelMinimumWidth;
            }
            return super.__minimumWidth();
        }
        get minimumHeight() {
            var _a;
            const activePanelMinimumHeight = (_a = this.activePanel) === null || _a === void 0 ? void 0 : _a.minimumHeight;
            if (typeof activePanelMinimumHeight === 'number') {
                return activePanelMinimumHeight;
            }
            return super.__minimumHeight();
        }
        get maximumWidth() {
            var _a;
            const activePanelMaximumWidth = (_a = this.activePanel) === null || _a === void 0 ? void 0 : _a.maximumWidth;
            if (typeof activePanelMaximumWidth === 'number') {
                return activePanelMaximumWidth;
            }
            return super.__maximumWidth();
        }
        get maximumHeight() {
            var _a;
            const activePanelMaximumHeight = (_a = this.activePanel) === null || _a === void 0 ? void 0 : _a.maximumHeight;
            if (typeof activePanelMaximumHeight === 'number') {
                return activePanelMaximumHeight;
            }
            return super.__maximumHeight();
        }
        get panels() {
            return this._model.panels;
        }
        get activePanel() {
            return this._model.activePanel;
        }
        get size() {
            return this._model.size;
        }
        get model() {
            return this._model;
        }
        get locked() {
            return this._model.locked;
        }
        set locked(value) {
            this._model.locked = value;
        }
        get header() {
            return this._model.header;
        }
        constructor(accessor, id, options) {
            var _a, _b, _c, _d, _e, _f;
            super(id, 'groupview_default', {
                minimumHeight: (_b = (_a = options.constraints) === null || _a === void 0 ? void 0 : _a.minimumHeight) !== null && _b !== void 0 ? _b : MINIMUM_DOCKVIEW_GROUP_PANEL_HEIGHT,
                minimumWidth: (_d = (_c = options.constraints) === null || _c === void 0 ? void 0 : _c.maximumHeight) !== null && _d !== void 0 ? _d : MINIMUM_DOCKVIEW_GROUP_PANEL_WIDTH,
                maximumHeight: (_e = options.constraints) === null || _e === void 0 ? void 0 : _e.maximumHeight,
                maximumWidth: (_f = options.constraints) === null || _f === void 0 ? void 0 : _f.maximumWidth,
            }, new DockviewGroupPanelApiImpl(id, accessor));
            this.api.initialize(this); // cannot use 'this' after after 'super' call
            this._model = new DockviewGroupPanelModel(this.element, accessor, id, options, this);
            this.addDisposables(this.model.onDidActivePanelChange((event) => {
                this.api._onDidActivePanelChange.fire(event);
            }));
        }
        focus() {
            if (!this.api.isActive) {
                this.api.setActive();
            }
            super.focus();
        }
        initialize() {
            this._model.initialize();
        }
        setActive(isActive) {
            super.setActive(isActive);
            this.model.setActive(isActive);
        }
        layout(width, height) {
            super.layout(width, height);
            this.model.layout(width, height);
        }
        getComponent() {
            return this._model;
        }
        toJSON() {
            return this.model.toJSON();
        }
    }

    const themeDark = {
        name: 'dark',
        className: 'dockview-theme-dark',
    };
    const themeLight = {
        name: 'light',
        className: 'dockview-theme-light',
    };
    const themeVisualStudio = {
        name: 'visualStudio',
        className: 'dockview-theme-vs',
    };
    const themeAbyss = {
        name: 'abyss',
        className: 'dockview-theme-abyss',
    };
    const themeDracula = {
        name: 'dracula',
        className: 'dockview-theme-dracula',
    };
    const themeReplit = {
        name: 'replit',
        className: 'dockview-theme-replit',
        gap: 10,
    };
    const themeAbyssSpaced = {
        name: 'abyssSpaced',
        className: 'dockview-theme-abyss-spaced',
        gap: 10,
        dndOverlayMounting: 'absolute',
        dndPanelOverlay: 'group',
    };
    const themeLightSpaced = {
        name: 'lightSpaced',
        className: 'dockview-theme-light-spaced',
        gap: 10,
        dndOverlayMounting: 'absolute',
        dndPanelOverlay: 'group',
    };

    class DockviewPanelApiImpl extends GridviewPanelApiImpl {
        get location() {
            return this.group.api.location;
        }
        get title() {
            return this.panel.title;
        }
        get isGroupActive() {
            return this.group.isActive;
        }
        get renderer() {
            return this.panel.renderer;
        }
        set group(value) {
            const oldGroup = this._group;
            if (this._group !== value) {
                this._group = value;
                this._onDidGroupChange.fire({});
                this.setupGroupEventListeners(oldGroup);
                this._onDidLocationChange.fire({
                    location: this.group.api.location,
                });
            }
        }
        get group() {
            return this._group;
        }
        get tabComponent() {
            return this._tabComponent;
        }
        constructor(panel, group, accessor, component, tabComponent) {
            super(panel.id, component);
            this.panel = panel;
            this.accessor = accessor;
            this._onDidTitleChange = new Emitter();
            this.onDidTitleChange = this._onDidTitleChange.event;
            this._onDidActiveGroupChange = new Emitter();
            this.onDidActiveGroupChange = this._onDidActiveGroupChange.event;
            this._onDidGroupChange = new Emitter();
            this.onDidGroupChange = this._onDidGroupChange.event;
            this._onDidRendererChange = new Emitter();
            this.onDidRendererChange = this._onDidRendererChange.event;
            this._onDidLocationChange = new Emitter();
            this.onDidLocationChange = this._onDidLocationChange.event;
            this.groupEventsDisposable = new MutableDisposable();
            this._tabComponent = tabComponent;
            this.initialize(panel);
            this._group = group;
            this.setupGroupEventListeners();
            this.addDisposables(this.groupEventsDisposable, this._onDidRendererChange, this._onDidTitleChange, this._onDidGroupChange, this._onDidActiveGroupChange, this._onDidLocationChange);
        }
        getWindow() {
            return this.group.api.getWindow();
        }
        moveTo(options) {
            var _a, _b;
            this.accessor.moveGroupOrPanel({
                from: { groupId: this._group.id, panelId: this.panel.id },
                to: {
                    group: (_a = options.group) !== null && _a !== void 0 ? _a : this._group,
                    position: options.group
                        ? (_b = options.position) !== null && _b !== void 0 ? _b : 'center'
                        : 'center',
                    index: options.index,
                },
            });
        }
        setTitle(title) {
            this.panel.setTitle(title);
        }
        setRenderer(renderer) {
            this.panel.setRenderer(renderer);
        }
        close() {
            this.group.model.closePanel(this.panel);
        }
        maximize() {
            this.group.api.maximize();
        }
        isMaximized() {
            return this.group.api.isMaximized();
        }
        exitMaximized() {
            this.group.api.exitMaximized();
        }
        setupGroupEventListeners(previousGroup) {
            var _a;
            let _trackGroupActive = (_a = previousGroup === null || previousGroup === void 0 ? void 0 : previousGroup.isActive) !== null && _a !== void 0 ? _a : false; // prevent duplicate events with same state
            this.groupEventsDisposable.value = new CompositeDisposable(this.group.api.onDidVisibilityChange((event) => {
                const hasBecomeHidden = !event.isVisible && this.isVisible;
                const hasBecomeVisible = event.isVisible && !this.isVisible;
                const isActivePanel = this.group.model.isPanelActive(this.panel);
                if (hasBecomeHidden || (hasBecomeVisible && isActivePanel)) {
                    this._onDidVisibilityChange.fire(event);
                }
            }), this.group.api.onDidLocationChange((event) => {
                if (this.group !== this.panel.group) {
                    return;
                }
                this._onDidLocationChange.fire(event);
            }), this.group.api.onDidActiveChange(() => {
                if (this.group !== this.panel.group) {
                    return;
                }
                if (_trackGroupActive !== this.isGroupActive) {
                    _trackGroupActive = this.isGroupActive;
                    this._onDidActiveGroupChange.fire({
                        isActive: this.isGroupActive,
                    });
                }
            }));
        }
    }

    class DockviewPanel extends CompositeDisposable {
        get params() {
            return this._params;
        }
        get title() {
            return this._title;
        }
        get group() {
            return this._group;
        }
        get renderer() {
            var _a;
            return (_a = this._renderer) !== null && _a !== void 0 ? _a : this.accessor.renderer;
        }
        get minimumWidth() {
            return this._minimumWidth;
        }
        get minimumHeight() {
            return this._minimumHeight;
        }
        get maximumWidth() {
            return this._maximumWidth;
        }
        get maximumHeight() {
            return this._maximumHeight;
        }
        constructor(id, component, tabComponent, accessor, containerApi, group, view, options) {
            super();
            this.id = id;
            this.accessor = accessor;
            this.containerApi = containerApi;
            this.view = view;
            this._renderer = options.renderer;
            this._group = group;
            this._minimumWidth = options.minimumWidth;
            this._minimumHeight = options.minimumHeight;
            this._maximumWidth = options.maximumWidth;
            this._maximumHeight = options.maximumHeight;
            this.api = new DockviewPanelApiImpl(this, this._group, accessor, component, tabComponent);
            this.addDisposables(this.api.onActiveChange(() => {
                accessor.setActivePanel(this);
            }), this.api.onDidSizeChange((event) => {
                // forward the resize event to the group since if you want to resize a panel
                // you are actually just resizing the panels parent which is the group
                this.group.api.setSize(event);
            }), this.api.onDidRendererChange(() => {
                this.group.model.rerender(this);
            }));
        }
        init(params) {
            this._params = params.params;
            this.view.init(Object.assign(Object.assign({}, params), { api: this.api, containerApi: this.containerApi }));
            this.setTitle(params.title);
        }
        focus() {
            const event = new WillFocusEvent();
            this.api._onWillFocus.fire(event);
            if (event.defaultPrevented) {
                return;
            }
            if (!this.api.isActive) {
                this.api.setActive();
            }
        }
        toJSON() {
            return {
                id: this.id,
                contentComponent: this.view.contentComponent,
                tabComponent: this.view.tabComponent,
                params: Object.keys(this._params || {}).length > 0
                    ? this._params
                    : undefined,
                title: this.title,
                renderer: this._renderer,
                minimumHeight: this._minimumHeight,
                maximumHeight: this._maximumHeight,
                minimumWidth: this._minimumWidth,
                maximumWidth: this._maximumWidth,
            };
        }
        setTitle(title) {
            const didTitleChange = title !== this.title;
            if (didTitleChange) {
                this._title = title;
                this.api._onDidTitleChange.fire({ title });
            }
        }
        setRenderer(renderer) {
            const didChange = renderer !== this.renderer;
            if (didChange) {
                this._renderer = renderer;
                this.api._onDidRendererChange.fire({
                    renderer: renderer,
                });
            }
        }
        update(event) {
            var _a;
            // merge the new parameters with the existing parameters
            this._params = Object.assign(Object.assign({}, ((_a = this._params) !== null && _a !== void 0 ? _a : {})), event.params);
            /**
             * delete new keys that have a value of undefined,
             * allow values of null
             */
            for (const key of Object.keys(event.params)) {
                if (event.params[key] === undefined) {
                    delete this._params[key];
                }
            }
            // update the view with the updated props
            this.view.update({
                params: this._params,
            });
        }
        updateParentGroup(group, options) {
            this._group = group;
            this.api.group = this._group;
            const isPanelVisible = this._group.model.isPanelActive(this);
            const isActive = this.group.api.isActive && isPanelVisible;
            if (!(options === null || options === void 0 ? void 0 : options.skipSetActive)) {
                if (this.api.isActive !== isActive) {
                    this.api._onDidActiveChange.fire({
                        isActive: this.group.api.isActive && isPanelVisible,
                    });
                }
            }
            if (this.api.isVisible !== isPanelVisible) {
                this.api._onDidVisibilityChange.fire({
                    isVisible: isPanelVisible,
                });
            }
        }
        runEvents() {
            const isPanelVisible = this._group.model.isPanelActive(this);
            const isActive = this.group.api.isActive && isPanelVisible;
            if (this.api.isActive !== isActive) {
                this.api._onDidActiveChange.fire({
                    isActive: this.group.api.isActive && isPanelVisible,
                });
            }
            if (this.api.isVisible !== isPanelVisible) {
                this.api._onDidVisibilityChange.fire({
                    isVisible: isPanelVisible,
                });
            }
        }
        layout(width, height) {
            // TODO: Can we somehow do height without header height or indicate what the header height is?
            this.api._onDidDimensionChange.fire({
                width,
                height: height,
            });
            this.view.layout(width, height);
        }
        dispose() {
            this.api.dispose();
            this.view.dispose();
        }
    }

    class DefaultTab extends CompositeDisposable {
        get element() {
            return this._element;
        }
        constructor() {
            super();
            this._element = document.createElement('div');
            this._element.className = 'dv-default-tab';
            this._content = document.createElement('div');
            this._content.className = 'dv-default-tab-content';
            this.action = document.createElement('div');
            this.action.className = 'dv-default-tab-action';
            this.action.appendChild(createCloseButton());
            this._element.appendChild(this._content);
            this._element.appendChild(this.action);
            this.render();
        }
        init(params) {
            this._title = params.title;
            this.addDisposables(params.api.onDidTitleChange((event) => {
                this._title = event.title;
                this.render();
            }), addDisposableListener(this.action, 'pointerdown', (ev) => {
                ev.preventDefault();
            }), addDisposableListener(this.action, 'click', (ev) => {
                if (ev.defaultPrevented) {
                    return;
                }
                ev.preventDefault();
                params.api.close();
            }));
            this.render();
        }
        render() {
            var _a;
            if (this._content.textContent !== this._title) {
                this._content.textContent = (_a = this._title) !== null && _a !== void 0 ? _a : '';
            }
        }
    }

    class DockviewPanelModel {
        get content() {
            return this._content;
        }
        get tab() {
            return this._tab;
        }
        constructor(accessor, id, contentComponent, tabComponent) {
            this.accessor = accessor;
            this.id = id;
            this.contentComponent = contentComponent;
            this.tabComponent = tabComponent;
            this._content = this.createContentComponent(this.id, contentComponent);
            this._tab = this.createTabComponent(this.id, tabComponent);
        }
        createTabRenderer(tabLocation) {
            var _a;
            const cmp = this.createTabComponent(this.id, this.tabComponent);
            if (this._params) {
                cmp.init(Object.assign(Object.assign({}, this._params), { tabLocation }));
            }
            if (this._updateEvent) {
                (_a = cmp.update) === null || _a === void 0 ? void 0 : _a.call(cmp, this._updateEvent);
            }
            return cmp;
        }
        init(params) {
            this._params = params;
            this.content.init(params);
            this.tab.init(Object.assign(Object.assign({}, params), { tabLocation: 'header' }));
        }
        layout(width, height) {
            var _a, _b;
            (_b = (_a = this.content).layout) === null || _b === void 0 ? void 0 : _b.call(_a, width, height);
        }
        update(event) {
            var _a, _b, _c, _d;
            this._updateEvent = event;
            (_b = (_a = this.content).update) === null || _b === void 0 ? void 0 : _b.call(_a, event);
            (_d = (_c = this.tab).update) === null || _d === void 0 ? void 0 : _d.call(_c, event);
        }
        dispose() {
            var _a, _b, _c, _d;
            (_b = (_a = this.content).dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
            (_d = (_c = this.tab).dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
        }
        createContentComponent(id, componentName) {
            return this.accessor.options.createComponent({
                id,
                name: componentName,
            });
        }
        createTabComponent(id, componentName) {
            const name = componentName !== null && componentName !== void 0 ? componentName : this.accessor.options.defaultTabComponent;
            if (name) {
                if (this.accessor.options.createTabComponent) {
                    const component = this.accessor.options.createTabComponent({
                        id,
                        name,
                    });
                    if (component) {
                        return component;
                    }
                    else {
                        return new DefaultTab();
                    }
                }
                console.warn(`dockview: tabComponent '${componentName}' was not found. falling back to the default tab.`);
            }
            return new DefaultTab();
        }
    }

    class DefaultDockviewDeserialzier {
        constructor(accessor) {
            this.accessor = accessor;
        }
        fromJSON(panelData, group) {
            var _a, _b;
            const panelId = panelData.id;
            const params = panelData.params;
            const title = panelData.title;
            const viewData = panelData.view;
            const contentComponent = viewData
                ? viewData.content.id
                : (_a = panelData.contentComponent) !== null && _a !== void 0 ? _a : 'unknown';
            const tabComponent = viewData
                ? (_b = viewData.tab) === null || _b === void 0 ? void 0 : _b.id
                : panelData.tabComponent;
            const view = new DockviewPanelModel(this.accessor, panelId, contentComponent, tabComponent);
            const panel = new DockviewPanel(panelId, contentComponent, tabComponent, this.accessor, new DockviewApi(this.accessor), group, view, {
                renderer: panelData.renderer,
                minimumWidth: panelData.minimumWidth,
                minimumHeight: panelData.minimumHeight,
                maximumWidth: panelData.maximumWidth,
                maximumHeight: panelData.maximumHeight,
            });
            panel.init({
                title: title !== null && title !== void 0 ? title : panelId,
                params: params !== null && params !== void 0 ? params : {},
            });
            return panel;
        }
    }

    class Watermark extends CompositeDisposable {
        get element() {
            return this._element;
        }
        constructor() {
            super();
            this._element = document.createElement('div');
            this._element.className = 'dv-watermark';
        }
        init(_params) {
            // noop
        }
    }

    class AriaLevelTracker {
        constructor() {
            this._orderedList = [];
        }
        push(element) {
            this._orderedList = [
                ...this._orderedList.filter((item) => item !== element),
                element,
            ];
            this.update();
        }
        destroy(element) {
            this._orderedList = this._orderedList.filter((item) => item !== element);
            this.update();
        }
        update() {
            for (let i = 0; i < this._orderedList.length; i++) {
                this._orderedList[i].setAttribute('aria-level', `${i}`);
                this._orderedList[i].style.zIndex = `calc(var(--dv-overlay-z-index, 999) + ${i * 2})`;
            }
        }
    }
    const arialLevelTracker = new AriaLevelTracker();
    class Overlay extends CompositeDisposable {
        set minimumInViewportWidth(value) {
            this.options.minimumInViewportWidth = value;
        }
        set minimumInViewportHeight(value) {
            this.options.minimumInViewportHeight = value;
        }
        get element() {
            return this._element;
        }
        get isVisible() {
            return this._isVisible;
        }
        constructor(options) {
            super();
            this.options = options;
            this._element = document.createElement('div');
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            this._onDidChangeEnd = new Emitter();
            this.onDidChangeEnd = this._onDidChangeEnd.event;
            this.addDisposables(this._onDidChange, this._onDidChangeEnd);
            this._element.className = 'dv-resize-container';
            this._isVisible = true;
            this.setupResize('top');
            this.setupResize('bottom');
            this.setupResize('left');
            this.setupResize('right');
            this.setupResize('topleft');
            this.setupResize('topright');
            this.setupResize('bottomleft');
            this.setupResize('bottomright');
            this._element.appendChild(this.options.content);
            this.options.container.appendChild(this._element);
            // if input bad resize within acceptable boundaries
            this.setBounds(Object.assign(Object.assign(Object.assign(Object.assign({ height: this.options.height, width: this.options.width }, ('top' in this.options && { top: this.options.top })), ('bottom' in this.options && { bottom: this.options.bottom })), ('left' in this.options && { left: this.options.left })), ('right' in this.options && { right: this.options.right })));
            arialLevelTracker.push(this._element);
        }
        setVisible(isVisible) {
            if (isVisible === this.isVisible) {
                return;
            }
            this._isVisible = isVisible;
            toggleClass(this.element, 'dv-hidden', !this.isVisible);
        }
        bringToFront() {
            arialLevelTracker.push(this._element);
        }
        setBounds(bounds = {}) {
            if (typeof bounds.height === 'number') {
                this._element.style.height = `${bounds.height}px`;
            }
            if (typeof bounds.width === 'number') {
                this._element.style.width = `${bounds.width}px`;
            }
            if ('top' in bounds && typeof bounds.top === 'number') {
                this._element.style.top = `${bounds.top}px`;
                this._element.style.bottom = 'auto';
                this.verticalAlignment = 'top';
            }
            if ('bottom' in bounds && typeof bounds.bottom === 'number') {
                this._element.style.bottom = `${bounds.bottom}px`;
                this._element.style.top = 'auto';
                this.verticalAlignment = 'bottom';
            }
            if ('left' in bounds && typeof bounds.left === 'number') {
                this._element.style.left = `${bounds.left}px`;
                this._element.style.right = 'auto';
                this.horiziontalAlignment = 'left';
            }
            if ('right' in bounds && typeof bounds.right === 'number') {
                this._element.style.right = `${bounds.right}px`;
                this._element.style.left = 'auto';
                this.horiziontalAlignment = 'right';
            }
            const containerRect = this.options.container.getBoundingClientRect();
            const overlayRect = this._element.getBoundingClientRect();
            // region: ensure bounds within allowable limits
            // a minimum width of minimumViewportWidth must be inside the viewport
            const xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
            // a minimum height of minimumViewportHeight must be inside the viewport
            const yOffset = Math.max(0, this.getMinimumHeight(overlayRect.height));
            if (this.verticalAlignment === 'top') {
                const top = clamp(overlayRect.top - containerRect.top, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
                this._element.style.top = `${top}px`;
                this._element.style.bottom = 'auto';
            }
            if (this.verticalAlignment === 'bottom') {
                const bottom = clamp(containerRect.bottom - overlayRect.bottom, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
                this._element.style.bottom = `${bottom}px`;
                this._element.style.top = 'auto';
            }
            if (this.horiziontalAlignment === 'left') {
                const left = clamp(overlayRect.left - containerRect.left, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
                this._element.style.left = `${left}px`;
                this._element.style.right = 'auto';
            }
            if (this.horiziontalAlignment === 'right') {
                const right = clamp(containerRect.right - overlayRect.right, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
                this._element.style.right = `${right}px`;
                this._element.style.left = 'auto';
            }
            this._onDidChange.fire();
        }
        toJSON() {
            const container = this.options.container.getBoundingClientRect();
            const element = this._element.getBoundingClientRect();
            const result = {};
            if (this.verticalAlignment === 'top') {
                result.top = parseFloat(this._element.style.top);
            }
            else if (this.verticalAlignment === 'bottom') {
                result.bottom = parseFloat(this._element.style.bottom);
            }
            else {
                result.top = element.top - container.top;
            }
            if (this.horiziontalAlignment === 'left') {
                result.left = parseFloat(this._element.style.left);
            }
            else if (this.horiziontalAlignment === 'right') {
                result.right = parseFloat(this._element.style.right);
            }
            else {
                result.left = element.left - container.left;
            }
            result.width = element.width;
            result.height = element.height;
            return result;
        }
        setupDrag(dragTarget, options = { inDragMode: false }) {
            const move = new MutableDisposable();
            const track = () => {
                let offset = null;
                const iframes = disableIframePointEvents();
                move.value = new CompositeDisposable({
                    dispose: () => {
                        iframes.release();
                    },
                }, addDisposableListener(window, 'pointermove', (e) => {
                    const containerRect = this.options.container.getBoundingClientRect();
                    const x = e.clientX - containerRect.left;
                    const y = e.clientY - containerRect.top;
                    toggleClass(this._element, 'dv-resize-container-dragging', true);
                    const overlayRect = this._element.getBoundingClientRect();
                    if (offset === null) {
                        offset = {
                            x: e.clientX - overlayRect.left,
                            y: e.clientY - overlayRect.top,
                        };
                    }
                    const xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
                    const yOffset = Math.max(0, this.getMinimumHeight(overlayRect.height));
                    const top = clamp(y - offset.y, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
                    const bottom = clamp(offset.y -
                        y +
                        containerRect.height -
                        overlayRect.height, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
                    const left = clamp(x - offset.x, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
                    const right = clamp(offset.x - x + containerRect.width - overlayRect.width, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
                    const bounds = {};
                    // Anchor to top or to bottom depending on which one is closer
                    if (top <= bottom) {
                        bounds.top = top;
                    }
                    else {
                        bounds.bottom = bottom;
                    }
                    // Anchor to left or to right depending on which one is closer
                    if (left <= right) {
                        bounds.left = left;
                    }
                    else {
                        bounds.right = right;
                    }
                    this.setBounds(bounds);
                }), addDisposableListener(window, 'pointerup', () => {
                    toggleClass(this._element, 'dv-resize-container-dragging', false);
                    move.dispose();
                    this._onDidChangeEnd.fire();
                }));
            };
            this.addDisposables(move, addDisposableListener(dragTarget, 'pointerdown', (event) => {
                if (event.defaultPrevented) {
                    event.preventDefault();
                    return;
                }
                // if somebody has marked this event then treat as a defaultPrevented
                // without actually calling event.preventDefault()
                if (quasiDefaultPrevented(event)) {
                    return;
                }
                track();
            }), addDisposableListener(this.options.content, 'pointerdown', (event) => {
                if (event.defaultPrevented) {
                    return;
                }
                // if somebody has marked this event then treat as a defaultPrevented
                // without actually calling event.preventDefault()
                if (quasiDefaultPrevented(event)) {
                    return;
                }
                if (event.shiftKey) {
                    track();
                }
            }), addDisposableListener(this.options.content, 'pointerdown', () => {
                arialLevelTracker.push(this._element);
            }, true));
            if (options.inDragMode) {
                track();
            }
        }
        setupResize(direction) {
            const resizeHandleElement = document.createElement('div');
            resizeHandleElement.className = `dv-resize-handle-${direction}`;
            this._element.appendChild(resizeHandleElement);
            const move = new MutableDisposable();
            this.addDisposables(move, addDisposableListener(resizeHandleElement, 'pointerdown', (e) => {
                e.preventDefault();
                let startPosition = null;
                const iframes = disableIframePointEvents();
                move.value = new CompositeDisposable(addDisposableListener(window, 'pointermove', (e) => {
                    const containerRect = this.options.container.getBoundingClientRect();
                    const overlayRect = this._element.getBoundingClientRect();
                    const y = e.clientY - containerRect.top;
                    const x = e.clientX - containerRect.left;
                    if (startPosition === null) {
                        // record the initial dimensions since as all subsequence moves are relative to this
                        startPosition = {
                            originalY: y,
                            originalHeight: overlayRect.height,
                            originalX: x,
                            originalWidth: overlayRect.width,
                        };
                    }
                    let top = undefined;
                    let bottom = undefined;
                    let height = undefined;
                    let left = undefined;
                    let right = undefined;
                    let width = undefined;
                    const moveTop = () => {
                        top = clamp(y, -Number.MAX_VALUE, startPosition.originalY +
                            startPosition.originalHeight >
                            containerRect.height
                            ? this.getMinimumHeight(containerRect.height)
                            : Math.max(0, startPosition.originalY +
                                startPosition.originalHeight -
                                Overlay.MINIMUM_HEIGHT));
                        height =
                            startPosition.originalY +
                                startPosition.originalHeight -
                                top;
                        bottom = containerRect.height - top - height;
                    };
                    const moveBottom = () => {
                        top =
                            startPosition.originalY -
                                startPosition.originalHeight;
                        height = clamp(y - top, top < 0 &&
                            typeof this.options
                                .minimumInViewportHeight === 'number'
                            ? -top +
                                this.options.minimumInViewportHeight
                            : Overlay.MINIMUM_HEIGHT, Number.MAX_VALUE);
                        bottom = containerRect.height - top - height;
                    };
                    const moveLeft = () => {
                        left = clamp(x, -Number.MAX_VALUE, startPosition.originalX +
                            startPosition.originalWidth >
                            containerRect.width
                            ? this.getMinimumWidth(containerRect.width)
                            : Math.max(0, startPosition.originalX +
                                startPosition.originalWidth -
                                Overlay.MINIMUM_WIDTH));
                        width =
                            startPosition.originalX +
                                startPosition.originalWidth -
                                left;
                        right = containerRect.width - left - width;
                    };
                    const moveRight = () => {
                        left =
                            startPosition.originalX -
                                startPosition.originalWidth;
                        width = clamp(x - left, left < 0 &&
                            typeof this.options
                                .minimumInViewportWidth === 'number'
                            ? -left +
                                this.options.minimumInViewportWidth
                            : Overlay.MINIMUM_WIDTH, Number.MAX_VALUE);
                        right = containerRect.width - left - width;
                    };
                    switch (direction) {
                        case 'top':
                            moveTop();
                            break;
                        case 'bottom':
                            moveBottom();
                            break;
                        case 'left':
                            moveLeft();
                            break;
                        case 'right':
                            moveRight();
                            break;
                        case 'topleft':
                            moveTop();
                            moveLeft();
                            break;
                        case 'topright':
                            moveTop();
                            moveRight();
                            break;
                        case 'bottomleft':
                            moveBottom();
                            moveLeft();
                            break;
                        case 'bottomright':
                            moveBottom();
                            moveRight();
                            break;
                    }
                    const bounds = {};
                    // Anchor to top or to bottom depending on which one is closer
                    if (top <= bottom) {
                        bounds.top = top;
                    }
                    else {
                        bounds.bottom = bottom;
                    }
                    // Anchor to left or to right depending on which one is closer
                    if (left <= right) {
                        bounds.left = left;
                    }
                    else {
                        bounds.right = right;
                    }
                    bounds.height = height;
                    bounds.width = width;
                    this.setBounds(bounds);
                }), {
                    dispose: () => {
                        iframes.release();
                    },
                }, addDisposableListener(window, 'pointerup', () => {
                    move.dispose();
                    this._onDidChangeEnd.fire();
                }));
            }));
        }
        getMinimumWidth(width) {
            if (typeof this.options.minimumInViewportWidth === 'number') {
                return width - this.options.minimumInViewportWidth;
            }
            return 0;
        }
        getMinimumHeight(height) {
            if (typeof this.options.minimumInViewportHeight === 'number') {
                return height - this.options.minimumInViewportHeight;
            }
            return 0;
        }
        dispose() {
            arialLevelTracker.destroy(this._element);
            this._element.remove();
            super.dispose();
        }
    }
    Overlay.MINIMUM_HEIGHT = 20;
    Overlay.MINIMUM_WIDTH = 20;

    class DockviewFloatingGroupPanel extends CompositeDisposable {
        constructor(group, overlay) {
            super();
            this.group = group;
            this.overlay = overlay;
            this.addDisposables(overlay);
        }
        position(bounds) {
            this.overlay.setBounds(bounds);
        }
    }

    const DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE = 100;
    const DEFAULT_FLOATING_GROUP_POSITION = { left: 100, top: 100, width: 300, height: 300 };

    function createFocusableElement() {
        const element = document.createElement('div');
        element.tabIndex = -1;
        return element;
    }
    class OverlayRenderContainer extends CompositeDisposable {
        constructor(element, accessor) {
            super();
            this.element = element;
            this.accessor = accessor;
            this.map = {};
            this._disposed = false;
            this.addDisposables(exports.DockviewDisposable.from(() => {
                for (const value of Object.values(this.map)) {
                    value.disposable.dispose();
                    value.destroy.dispose();
                }
                this._disposed = true;
            }));
        }
        detatch(panel) {
            if (this.map[panel.api.id]) {
                const { disposable, destroy } = this.map[panel.api.id];
                disposable.dispose();
                destroy.dispose();
                delete this.map[panel.api.id];
                return true;
            }
            return false;
        }
        attach(options) {
            const { panel, referenceContainer } = options;
            if (!this.map[panel.api.id]) {
                const element = createFocusableElement();
                element.className = 'dv-render-overlay';
                this.map[panel.api.id] = {
                    panel,
                    disposable: exports.DockviewDisposable.NONE,
                    destroy: exports.DockviewDisposable.NONE,
                    element,
                };
            }
            const focusContainer = this.map[panel.api.id].element;
            if (panel.view.content.element.parentElement !== focusContainer) {
                focusContainer.appendChild(panel.view.content.element);
            }
            if (focusContainer.parentElement !== this.element) {
                this.element.appendChild(focusContainer);
            }
            const resize = () => {
                // TODO propagate position to avoid getDomNodePagePosition calls, possible performance bottleneck?
                const box = getDomNodePagePosition(referenceContainer.element);
                const box2 = getDomNodePagePosition(this.element);
                focusContainer.style.left = `${box.left - box2.left}px`;
                focusContainer.style.top = `${box.top - box2.top}px`;
                focusContainer.style.width = `${box.width}px`;
                focusContainer.style.height = `${box.height}px`;
                toggleClass(focusContainer, 'dv-render-overlay-float', panel.group.api.location.type === 'floating');
            };
            const visibilityChanged = () => {
                if (panel.api.isVisible) {
                    resize();
                }
                focusContainer.style.display = panel.api.isVisible ? '' : 'none';
            };
            const observerDisposable = new MutableDisposable();
            const correctLayerPosition = () => {
                if (panel.api.location.type === 'floating') {
                    queueMicrotask(() => {
                        const floatingGroup = this.accessor.floatingGroups.find((group) => group.group === panel.api.group);
                        if (!floatingGroup) {
                            return;
                        }
                        const element = floatingGroup.overlay.element;
                        const update = () => {
                            const level = Number(element.getAttribute('aria-level'));
                            focusContainer.style.zIndex = `calc(var(--dv-overlay-z-index, 999) + ${level * 2 + 1})`;
                        };
                        const observer = new MutationObserver(() => {
                            update();
                        });
                        observerDisposable.value = exports.DockviewDisposable.from(() => observer.disconnect());
                        observer.observe(element, {
                            attributeFilter: ['aria-level'],
                            attributes: true,
                        });
                        update();
                    });
                }
                else {
                    focusContainer.style.zIndex = ''; // reset the z-index, perhaps CSS will take over here
                }
            };
            const disposable = new CompositeDisposable(observerDisposable, 
            /**
             * since container is positioned absoutely we must explicitly forward
             * the dnd events for the expect behaviours to continue to occur in terms of dnd
             *
             * the dnd observer does not need to be conditional on whether the panel is visible since
             * non-visible panels are 'display: none' and in such case the dnd observer will not fire.
             */
            new DragAndDropObserver(focusContainer, {
                onDragEnd: (e) => {
                    referenceContainer.dropTarget.dnd.onDragEnd(e);
                },
                onDragEnter: (e) => {
                    referenceContainer.dropTarget.dnd.onDragEnter(e);
                },
                onDragLeave: (e) => {
                    referenceContainer.dropTarget.dnd.onDragLeave(e);
                },
                onDrop: (e) => {
                    referenceContainer.dropTarget.dnd.onDrop(e);
                },
                onDragOver: (e) => {
                    referenceContainer.dropTarget.dnd.onDragOver(e);
                },
            }), panel.api.onDidVisibilityChange(() => {
                /**
                 * Control the visibility of the content, however even when not visible (display: none)
                 * the content is still maintained within the DOM hence DOM specific attributes
                 * such as scroll position are maintained when next made visible.
                 */
                visibilityChanged();
            }), panel.api.onDidDimensionsChange(() => {
                if (!panel.api.isVisible) {
                    return;
                }
                resize();
            }), panel.api.onDidLocationChange(() => {
                correctLayerPosition();
            }));
            this.map[panel.api.id].destroy = exports.DockviewDisposable.from(() => {
                var _a;
                if (panel.view.content.element.parentElement === focusContainer) {
                    focusContainer.removeChild(panel.view.content.element);
                }
                (_a = focusContainer.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(focusContainer);
            });
            correctLayerPosition();
            queueMicrotask(() => {
                if (this.isDisposed) {
                    return;
                }
                /**
                 * wait until everything has finished in the current stack-frame call before
                 * calling the first resize as other size-altering events may still occur before
                 * the end of the stack-frame.
                 */
                visibilityChanged();
            });
            // dispose of logic asoccciated with previous reference-container
            this.map[panel.api.id].disposable.dispose();
            // and reset the disposable to the active reference-container
            this.map[panel.api.id].disposable = disposable;
            return focusContainer;
        }
    }

    var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
        function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
        return new (P || (P = Promise))(function (resolve, reject) {
            function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
            function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
            function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
            step((generator = generator.apply(thisArg, _arguments || [])).next());
        });
    };
    class PopoutWindow extends CompositeDisposable {
        get window() {
            var _a, _b;
            return (_b = (_a = this._window) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null;
        }
        constructor(target, className, options) {
            super();
            this.target = target;
            this.className = className;
            this.options = options;
            this._onWillClose = new Emitter();
            this.onWillClose = this._onWillClose.event;
            this._onDidClose = new Emitter();
            this.onDidClose = this._onDidClose.event;
            this._window = null;
            this.addDisposables(this._onWillClose, this._onDidClose, {
                dispose: () => {
                    this.close();
                },
            });
        }
        dimensions() {
            if (!this._window) {
                return null;
            }
            const left = this._window.value.screenX;
            const top = this._window.value.screenY;
            const width = this._window.value.innerWidth;
            const height = this._window.value.innerHeight;
            return { top, left, width, height };
        }
        close() {
            var _a, _b;
            if (this._window) {
                this._onWillClose.fire();
                (_b = (_a = this.options).onWillClose) === null || _b === void 0 ? void 0 : _b.call(_a, {
                    id: this.target,
                    window: this._window.value,
                });
                this._window.disposable.dispose();
                this._window = null;
                this._onDidClose.fire();
            }
        }
        open() {
            var _a, _b;
            return __awaiter(this, void 0, void 0, function* () {
                if (this._window) {
                    throw new Error('instance of popout window is already open');
                }
                const url = `${this.options.url}`;
                const features = Object.entries({
                    top: this.options.top,
                    left: this.options.left,
                    width: this.options.width,
                    height: this.options.height,
                })
                    .map(([key, value]) => `${key}=${value}`)
                    .join(',');
                /**
                 * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/open
                 */
                const externalWindow = window.open(url, this.target, features);
                if (!externalWindow) {
                    /**
                     * Popup blocked
                     */
                    return null;
                }
                const disposable = new CompositeDisposable();
                this._window = { value: externalWindow, disposable };
                disposable.addDisposables(exports.DockviewDisposable.from(() => {
                    externalWindow.close();
                }), addDisposableListener(window, 'beforeunload', () => {
                    /**
                     * before the main window closes we should close this popup too
                     * to be good citizens
                     *
                     * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
                     */
                    this.close();
                }));
                const container = this.createPopoutWindowContainer();
                if (this.className) {
                    container.classList.add(this.className);
                }
                (_b = (_a = this.options).onDidOpen) === null || _b === void 0 ? void 0 : _b.call(_a, {
                    id: this.target,
                    window: externalWindow,
                });
                return new Promise((resolve, reject) => {
                    externalWindow.addEventListener('unload', (e) => {
                        // if page fails to load before unloading
                        // this.close();
                    });
                    externalWindow.addEventListener('load', () => {
                        /**
                         * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
                         */
                        try {
                            const externalDocument = externalWindow.document;
                            externalDocument.title = document.title;
                            externalDocument.body.appendChild(container);
                            addStyles(externalDocument, window.document.styleSheets);
                            /**
                             * beforeunload must be registered after load for reasons I could not determine
                             * otherwise the beforeunload event will not fire when the window is closed
                             */
                            addDisposableListener(externalWindow, 'beforeunload', () => {
                                /**
                                 * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
                                 */
                                this.close();
                            });
                            resolve(container);
                        }
                        catch (err) {
                            // only except this is the DOM isn't setup. e.g. in a in correctly configured test
                            reject(err);
                        }
                    });
                });
            });
        }
        createPopoutWindowContainer() {
            const el = document.createElement('div');
            el.classList.add('dv-popout-window');
            el.id = 'dv-popout-window';
            el.style.position = 'absolute';
            el.style.width = '100%';
            el.style.height = '100%';
            el.style.top = '0px';
            el.style.left = '0px';
            return el;
        }
    }

    class StrictEventsSequencing extends CompositeDisposable {
        constructor(accessor) {
            super();
            this.accessor = accessor;
            this.init();
        }
        init() {
            const panels = new Set();
            const groups = new Set();
            this.addDisposables(this.accessor.onDidAddPanel((panel) => {
                if (panels.has(panel.api.id)) {
                    throw new Error(`dockview: Invalid event sequence. [onDidAddPanel] called for panel ${panel.api.id} but panel already exists`);
                }
                else {
                    panels.add(panel.api.id);
                }
            }), this.accessor.onDidRemovePanel((panel) => {
                if (!panels.has(panel.api.id)) {
                    throw new Error(`dockview: Invalid event sequence. [onDidRemovePanel] called for panel ${panel.api.id} but panel does not exists`);
                }
                else {
                    panels.delete(panel.api.id);
                }
            }), this.accessor.onDidAddGroup((group) => {
                if (groups.has(group.api.id)) {
                    throw new Error(`dockview: Invalid event sequence. [onDidAddGroup] called for group ${group.api.id} but group already exists`);
                }
                else {
                    groups.add(group.api.id);
                }
            }), this.accessor.onDidRemoveGroup((group) => {
                if (!groups.has(group.api.id)) {
                    throw new Error(`dockview: Invalid event sequence. [onDidRemoveGroup] called for group ${group.api.id} but group does not exists`);
                }
                else {
                    groups.delete(group.api.id);
                }
            }));
        }
    }

    class PopupService extends CompositeDisposable {
        constructor(root) {
            super();
            this.root = root;
            this._active = null;
            this._activeDisposable = new MutableDisposable();
            this._element = document.createElement('div');
            this._element.className = 'dv-popover-anchor';
            this._element.style.position = 'relative';
            this.root.prepend(this._element);
            this.addDisposables(exports.DockviewDisposable.from(() => {
                this.close();
            }), this._activeDisposable);
        }
        openPopover(element, position) {
            this.close();
            const wrapper = document.createElement('div');
            wrapper.style.position = 'absolute';
            wrapper.style.zIndex = '99';
            wrapper.appendChild(element);
            const anchorBox = this._element.getBoundingClientRect();
            const offsetX = anchorBox.left;
            const offsetY = anchorBox.top;
            wrapper.style.top = `${position.y - offsetY}px`;
            wrapper.style.left = `${position.x - offsetX}px`;
            this._element.appendChild(wrapper);
            this._active = wrapper;
            this._activeDisposable.value = new CompositeDisposable(addDisposableListener(window, 'pointerdown', (event) => {
                var _a;
                const target = event.target;
                if (!(target instanceof HTMLElement)) {
                    return;
                }
                let el = target;
                while (el && el !== wrapper) {
                    el = (_a = el === null || el === void 0 ? void 0 : el.parentElement) !== null && _a !== void 0 ? _a : null;
                }
                if (el) {
                    return; // clicked within popover
                }
                this.close();
            }));
        }
        close() {
            if (this._active) {
                this._active.remove();
                this._activeDisposable.dispose();
                this._active = null;
            }
        }
    }

    class DropTargetAnchorContainer extends CompositeDisposable {
        get disabled() {
            return this._disabled;
        }
        set disabled(value) {
            var _a;
            if (this.disabled === value) {
                return;
            }
            this._disabled = value;
            if (value) {
                (_a = this.model) === null || _a === void 0 ? void 0 : _a.clear();
            }
        }
        get model() {
            if (this.disabled) {
                return undefined;
            }
            return {
                clear: () => {
                    var _a;
                    if (this._model) {
                        (_a = this._model.root.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(this._model.root);
                    }
                    this._model = undefined;
                },
                exists: () => {
                    return !!this._model;
                },
                getElements: (event, outline) => {
                    const changed = this._outline !== outline;
                    this._outline = outline;
                    if (this._model) {
                        this._model.changed = changed;
                        return this._model;
                    }
                    const container = this.createContainer();
                    const anchor = this.createAnchor();
                    this._model = { root: container, overlay: anchor, changed };
                    container.appendChild(anchor);
                    this.element.appendChild(container);
                    if ((event === null || event === void 0 ? void 0 : event.target) instanceof HTMLElement) {
                        const targetBox = event.target.getBoundingClientRect();
                        const box = this.element.getBoundingClientRect();
                        anchor.style.left = `${targetBox.left - box.left}px`;
                        anchor.style.top = `${targetBox.top - box.top}px`;
                    }
                    return this._model;
                },
            };
        }
        constructor(element, options) {
            super();
            this.element = element;
            this._disabled = false;
            this._disabled = options.disabled;
            this.addDisposables(exports.DockviewDisposable.from(() => {
                var _a;
                (_a = this.model) === null || _a === void 0 ? void 0 : _a.clear();
            }));
        }
        createContainer() {
            const el = document.createElement('div');
            el.className = 'dv-drop-target-container';
            return el;
        }
        createAnchor() {
            const el = document.createElement('div');
            el.className = 'dv-drop-target-anchor';
            el.style.visibility = 'hidden';
            return el;
        }
    }

    const DEFAULT_ROOT_OVERLAY_MODEL = {
        activationSize: { type: 'pixels', value: 10 },
        size: { type: 'pixels', value: 20 },
    };
    function moveGroupWithoutDestroying(options) {
        const activePanel = options.from.activePanel;
        const panels = [...options.from.panels].map((panel) => {
            const removedPanel = options.from.model.removePanel(panel);
            options.from.model.renderContainer.detatch(panel);
            return removedPanel;
        });
        panels.forEach((panel) => {
            options.to.model.openPanel(panel, {
                skipSetActive: activePanel !== panel,
                skipSetGroupActive: true,
            });
        });
    }
    class DockviewComponent extends BaseGrid {
        get orientation() {
            return this.gridview.orientation;
        }
        get totalPanels() {
            return this.panels.length;
        }
        get panels() {
            return this.groups.flatMap((group) => group.panels);
        }
        get options() {
            return this._options;
        }
        get activePanel() {
            const activeGroup = this.activeGroup;
            if (!activeGroup) {
                return undefined;
            }
            return activeGroup.activePanel;
        }
        get renderer() {
            var _a;
            return (_a = this.options.defaultRenderer) !== null && _a !== void 0 ? _a : 'onlyWhenVisible';
        }
        get api() {
            return this._api;
        }
        get floatingGroups() {
            return this._floatingGroups;
        }
        constructor(container, options) {
            var _a, _b, _c;
            super(container, {
                proportionalLayout: true,
                orientation: exports.Orientation.HORIZONTAL,
                styles: options.hideBorders
                    ? { separatorBorder: 'transparent' }
                    : undefined,
                disableAutoResizing: options.disableAutoResizing,
                locked: options.locked,
                margin: (_b = (_a = options.theme) === null || _a === void 0 ? void 0 : _a.gap) !== null && _b !== void 0 ? _b : 0,
                className: options.className,
            });
            this.nextGroupId = sequentialNumberGenerator();
            this._deserializer = new DefaultDockviewDeserialzier(this);
            this._watermark = null;
            this._onWillDragPanel = new Emitter();
            this.onWillDragPanel = this._onWillDragPanel.event;
            this._onWillDragGroup = new Emitter();
            this.onWillDragGroup = this._onWillDragGroup.event;
            this._onDidDrop = new Emitter();
            this.onDidDrop = this._onDidDrop.event;
            this._onWillDrop = new Emitter();
            this.onWillDrop = this._onWillDrop.event;
            this._onWillShowOverlay = new Emitter();
            this.onWillShowOverlay = this._onWillShowOverlay.event;
            this._onUnhandledDragOverEvent = new Emitter();
            this.onUnhandledDragOverEvent = this._onUnhandledDragOverEvent.event;
            this._onDidRemovePanel = new Emitter();
            this.onDidRemovePanel = this._onDidRemovePanel.event;
            this._onDidAddPanel = new Emitter();
            this.onDidAddPanel = this._onDidAddPanel.event;
            this._onDidPopoutGroupSizeChange = new Emitter();
            this.onDidPopoutGroupSizeChange = this._onDidPopoutGroupSizeChange.event;
            this._onDidPopoutGroupPositionChange = new Emitter();
            this.onDidPopoutGroupPositionChange = this._onDidPopoutGroupPositionChange.event;
            this._onDidLayoutFromJSON = new Emitter();
            this.onDidLayoutFromJSON = this._onDidLayoutFromJSON.event;
            this._onDidActivePanelChange = new Emitter();
            this.onDidActivePanelChange = this._onDidActivePanelChange.event;
            this._onDidMovePanel = new Emitter();
            this.onDidMovePanel = this._onDidMovePanel.event;
            this._onDidMaximizedGroupChange = new Emitter();
            this.onDidMaximizedGroupChange = this._onDidMaximizedGroupChange.event;
            this._floatingGroups = [];
            this._popoutGroups = [];
            this._onDidRemoveGroup = new Emitter();
            this.onDidRemoveGroup = this._onDidRemoveGroup.event;
            this._onDidAddGroup = new Emitter();
            this.onDidAddGroup = this._onDidAddGroup.event;
            this._onDidOptionsChange = new Emitter();
            this.onDidOptionsChange = this._onDidOptionsChange.event;
            this._onDidActiveGroupChange = new Emitter();
            this.onDidActiveGroupChange = this._onDidActiveGroupChange.event;
            this._moving = false;
            this._options = options;
            this.popupService = new PopupService(this.element);
            this._themeClassnames = new Classnames(this.element);
            this._api = new DockviewApi(this);
            this.rootDropTargetContainer = new DropTargetAnchorContainer(this.element, { disabled: true });
            this.overlayRenderContainer = new OverlayRenderContainer(this.gridview.element, this);
            this._rootDropTarget = new Droptarget(this.element, {
                className: 'dv-drop-target-edge',
                canDisplayOverlay: (event, position) => {
                    const data = getPanelData();
                    if (data) {
                        if (data.viewId !== this.id) {
                            return false;
                        }
                        if (position === 'center') {
                            // center drop target is only allowed if there are no panels in the grid
                            // floating panels are allowed
                            return this.gridview.length === 0;
                        }
                        return true;
                    }
                    if (position === 'center' && this.gridview.length !== 0) {
                        /**
                         * for external events only show the four-corner drag overlays, disable
                         * the center position so that external drag events can fall through to the group
                         * and panel drop target handlers
                         */
                        return false;
                    }
                    const firedEvent = new DockviewUnhandledDragOverEvent(event, 'edge', position, getPanelData);
                    this._onUnhandledDragOverEvent.fire(firedEvent);
                    return firedEvent.isAccepted;
                },
                acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
                overlayModel: (_c = options.rootOverlayModel) !== null && _c !== void 0 ? _c : DEFAULT_ROOT_OVERLAY_MODEL,
                getOverrideTarget: () => { var _a; return (_a = this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
            });
            this.updateDropTargetModel(options);
            toggleClass(this.gridview.element, 'dv-dockview', true);
            toggleClass(this.element, 'dv-debug', !!options.debug);
            this.updateTheme();
            this.updateWatermark();
            if (options.debug) {
                this.addDisposables(new StrictEventsSequencing(this));
            }
            this.addDisposables(this.rootDropTargetContainer, this.overlayRenderContainer, this._onWillDragPanel, this._onWillDragGroup, this._onWillShowOverlay, this._onDidActivePanelChange, this._onDidAddPanel, this._onDidRemovePanel, this._onDidLayoutFromJSON, this._onDidDrop, this._onWillDrop, this._onDidMovePanel, this._onDidAddGroup, this._onDidRemoveGroup, this._onDidActiveGroupChange, this._onUnhandledDragOverEvent, this._onDidMaximizedGroupChange, this._onDidOptionsChange, this._onDidPopoutGroupSizeChange, this._onDidPopoutGroupPositionChange, this.onDidViewVisibilityChangeMicroTaskQueue(() => {
                this.updateWatermark();
            }), this.onDidAdd((event) => {
                if (!this._moving) {
                    this._onDidAddGroup.fire(event);
                }
            }), this.onDidRemove((event) => {
                if (!this._moving) {
                    this._onDidRemoveGroup.fire(event);
                }
            }), this.onDidActiveChange((event) => {
                if (!this._moving) {
                    this._onDidActiveGroupChange.fire(event);
                }
            }), this.onDidMaximizedChange((event) => {
                this._onDidMaximizedGroupChange.fire({
                    group: event.panel,
                    isMaximized: event.isMaximized,
                });
            }), exports.DockviewEvent.any(this.onDidAdd, this.onDidRemove)(() => {
                this.updateWatermark();
            }), exports.DockviewEvent.any(this.onDidAddPanel, this.onDidRemovePanel, this.onDidAddGroup, this.onDidRemove, this.onDidMovePanel, this.onDidActivePanelChange, this.onDidPopoutGroupPositionChange, this.onDidPopoutGroupSizeChange)(() => {
                this._bufferOnDidLayoutChange.fire();
            }), exports.DockviewDisposable.from(() => {
                // iterate over a copy of the array since .dispose() mutates the original array
                for (const group of [...this._floatingGroups]) {
                    group.dispose();
                }
                // iterate over a copy of the array since .dispose() mutates the original array
                for (const group of [...this._popoutGroups]) {
                    group.disposable.dispose();
                }
            }), this._rootDropTarget, this._rootDropTarget.onWillShowOverlay((event) => {
                if (this.gridview.length > 0 && event.position === 'center') {
                    // option only available when no panels in primary grid
                    return;
                }
                this._onWillShowOverlay.fire(new WillShowOverlayLocationEvent(event, {
                    kind: 'edge',
                    panel: undefined,
                    api: this._api,
                    group: undefined,
                    getData: getPanelData,
                }));
            }), this._rootDropTarget.onDrop((event) => {
                var _a;
                const willDropEvent = new DockviewWillDropEvent({
                    nativeEvent: event.nativeEvent,
                    position: event.position,
                    panel: undefined,
                    api: this._api,
                    group: undefined,
                    getData: getPanelData,
                    kind: 'edge',
                });
                this._onWillDrop.fire(willDropEvent);
                if (willDropEvent.defaultPrevented) {
                    return;
                }
                const data = getPanelData();
                if (data) {
                    this.moveGroupOrPanel({
                        from: {
                            groupId: data.groupId,
                            panelId: (_a = data.panelId) !== null && _a !== void 0 ? _a : undefined,
                        },
                        to: {
                            group: this.orthogonalize(event.position),
                            position: 'center',
                        },
                    });
                }
                else {
                    this._onDidDrop.fire(new DockviewDidDropEvent({
                        nativeEvent: event.nativeEvent,
                        position: event.position,
                        panel: undefined,
                        api: this._api,
                        group: undefined,
                        getData: getPanelData,
                    }));
                }
            }), this._rootDropTarget);
        }
        setVisible(panel, visible) {
            switch (panel.api.location.type) {
                case 'grid':
                    super.setVisible(panel, visible);
                    break;
                case 'floating': {
                    const item = this.floatingGroups.find((floatingGroup) => floatingGroup.group === panel);
                    if (item) {
                        item.overlay.setVisible(visible);
                        panel.api._onDidVisibilityChange.fire({
                            isVisible: visible,
                        });
                    }
                    break;
                }
                case 'popout':
                    console.warn('dockview: You cannot hide a group that is in a popout window');
                    break;
            }
        }
        addPopoutGroup(itemToPopout, options) {
            var _a, _b, _c, _d, _e;
            if (itemToPopout instanceof DockviewPanel &&
                itemToPopout.group.size === 1) {
                return this.addPopoutGroup(itemToPopout.group, options);
            }
            const theme = getDockviewTheme(this.gridview.element);
            const element = this.element;
            function getBox() {
                if (options === null || options === void 0 ? void 0 : options.position) {
                    return options.position;
                }
                if (itemToPopout instanceof DockviewGroupPanel) {
                    return itemToPopout.element.getBoundingClientRect();
                }
                if (itemToPopout.group) {
                    return itemToPopout.group.element.getBoundingClientRect();
                }
                return element.getBoundingClientRect();
            }
            const box = getBox();
            const groupId = (_b = (_a = options === null || options === void 0 ? void 0 : options.overridePopoutGroup) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : this.getNextGroupId();
            const _window = new PopoutWindow(`${this.id}-${groupId}`, // unique id
            theme !== null && theme !== void 0 ? theme : '', {
                url: (_e = (_c = options === null || options === void 0 ? void 0 : options.popoutUrl) !== null && _c !== void 0 ? _c : (_d = this.options) === null || _d === void 0 ? void 0 : _d.popoutUrl) !== null && _e !== void 0 ? _e : '/popout.html',
                left: window.screenX + box.left,
                top: window.screenY + box.top,
                width: box.width,
                height: box.height,
                onDidOpen: options === null || options === void 0 ? void 0 : options.onDidOpen,
                onWillClose: options === null || options === void 0 ? void 0 : options.onWillClose,
            });
            const popoutWindowDisposable = new CompositeDisposable(_window, _window.onDidClose(() => {
                popoutWindowDisposable.dispose();
            }));
            return _window
                .open()
                .then((popoutContainer) => {
                var _a;
                if (_window.isDisposed) {
                    return false;
                }
                if (popoutContainer === null) {
                    popoutWindowDisposable.dispose();
                    return false;
                }
                const gready = document.createElement('div');
                gready.className = 'dv-overlay-render-container';
                const overlayRenderContainer = new OverlayRenderContainer(gready, this);
                const referenceGroup = itemToPopout instanceof DockviewPanel
                    ? itemToPopout.group
                    : itemToPopout;
                const referenceLocation = itemToPopout.api.location.type;
                /**
                 * The group that is being added doesn't already exist within the DOM, the most likely occurance
                 * of this case is when being called from the `fromJSON(...)` method
                 */
                const isGroupAddedToDom = referenceGroup.element.parentElement !== null;
                let group;
                if (!isGroupAddedToDom) {
                    group = referenceGroup;
                }
                else if (options === null || options === void 0 ? void 0 : options.overridePopoutGroup) {
                    group = options.overridePopoutGroup;
                }
                else {
                    group = this.createGroup({ id: groupId });
                    this._onDidAddGroup.fire(group);
                }
                group.model.renderContainer = overlayRenderContainer;
                group.layout(_window.window.innerWidth, _window.window.innerHeight);
                let floatingBox;
                if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && isGroupAddedToDom) {
                    if (itemToPopout instanceof DockviewPanel) {
                        this.movingLock(() => {
                            const panel = referenceGroup.model.removePanel(itemToPopout);
                            group.model.openPanel(panel);
                        });
                    }
                    else {
                        this.movingLock(() => moveGroupWithoutDestroying({
                            from: referenceGroup,
                            to: group,
                        }));
                        switch (referenceLocation) {
                            case 'grid':
                                referenceGroup.api.setVisible(false);
                                break;
                            case 'floating':
                            case 'popout':
                                floatingBox = (_a = this._floatingGroups
                                    .find((value) => value.group.api.id ===
                                    itemToPopout.api.id)) === null || _a === void 0 ? void 0 : _a.overlay.toJSON();
                                this.removeGroup(referenceGroup);
                                break;
                        }
                    }
                }
                popoutContainer.classList.add('dv-dockview');
                popoutContainer.style.overflow = 'hidden';
                popoutContainer.appendChild(gready);
                popoutContainer.appendChild(group.element);
                const anchor = document.createElement('div');
                const dropTargetContainer = new DropTargetAnchorContainer(anchor, { disabled: this.rootDropTargetContainer.disabled });
                popoutContainer.appendChild(anchor);
                group.model.dropTargetContainer = dropTargetContainer;
                group.model.location = {
                    type: 'popout',
                    getWindow: () => _window.window,
                    popoutUrl: options === null || options === void 0 ? void 0 : options.popoutUrl,
                };
                if (isGroupAddedToDom &&
                    itemToPopout.api.location.type === 'grid') {
                    itemToPopout.api.setVisible(false);
                }
                this.doSetGroupAndPanelActive(group);
                popoutWindowDisposable.addDisposables(group.api.onDidActiveChange((event) => {
                    var _a;
                    if (event.isActive) {
                        (_a = _window.window) === null || _a === void 0 ? void 0 : _a.focus();
                    }
                }), group.api.onWillFocus(() => {
                    var _a;
                    (_a = _window.window) === null || _a === void 0 ? void 0 : _a.focus();
                }));
                let returnedGroup;
                const isValidReferenceGroup = isGroupAddedToDom &&
                    referenceGroup &&
                    this.getPanel(referenceGroup.id);
                const value = {
                    window: _window,
                    popoutGroup: group,
                    referenceGroup: isValidReferenceGroup
                        ? referenceGroup.id
                        : undefined,
                    disposable: {
                        dispose: () => {
                            popoutWindowDisposable.dispose();
                            return returnedGroup;
                        },
                    },
                };
                const _onDidWindowPositionChange = onDidWindowMoveEnd(_window.window);
                popoutWindowDisposable.addDisposables(_onDidWindowPositionChange, onDidWindowResizeEnd(_window.window, () => {
                    this._onDidPopoutGroupSizeChange.fire({
                        width: _window.window.innerWidth,
                        height: _window.window.innerHeight,
                        group,
                    });
                }), _onDidWindowPositionChange.event(() => {
                    this._onDidPopoutGroupPositionChange.fire({
                        screenX: _window.window.screenX,
                        screenY: _window.window.screenX,
                        group,
                    });
                }), 
                /**
                 * ResizeObserver seems slow here, I do not know why but we don't need it
                 * since we can reply on the window resize event as we will occupy the full
                 * window dimensions
                 */
                addDisposableListener(_window.window, 'resize', () => {
                    group.layout(_window.window.innerWidth, _window.window.innerHeight);
                }), overlayRenderContainer, exports.DockviewDisposable.from(() => {
                    if (this.isDisposed) {
                        return; // cleanup may run after instance is disposed
                    }
                    if (isGroupAddedToDom &&
                        this.getPanel(referenceGroup.id)) {
                        this.movingLock(() => moveGroupWithoutDestroying({
                            from: group,
                            to: referenceGroup,
                        }));
                        if (!referenceGroup.api.isVisible) {
                            referenceGroup.api.setVisible(true);
                        }
                        if (this.getPanel(group.id)) {
                            this.doRemoveGroup(group, {
                                skipPopoutAssociated: true,
                            });
                        }
                    }
                    else if (this.getPanel(group.id)) {
                        group.model.renderContainer =
                            this.overlayRenderContainer;
                        group.model.dropTargetContainer =
                            this.rootDropTargetContainer;
                        returnedGroup = group;
                        const alreadyRemoved = !this._popoutGroups.find((p) => p.popoutGroup === group);
                        if (alreadyRemoved) {
                            /**
                             * If this popout group was explicitly removed then we shouldn't run the additional
                             * steps. To tell if the running of this disposable is the result of this popout group
                             * being explicitly removed we can check if this popout group is still referenced in
                             * the `this._popoutGroups` list.
                             */
                            return;
                        }
                        if (floatingBox) {
                            this.addFloatingGroup(group, {
                                height: floatingBox.height,
                                width: floatingBox.width,
                                position: floatingBox,
                            });
                        }
                        else {
                            this.doRemoveGroup(group, {
                                skipDispose: true,
                                skipActive: true,
                                skipPopoutReturn: true,
                            });
                            group.model.location = { type: 'grid' };
                            this.movingLock(() => {
                                // suppress group add events since the group already exists
                                this.doAddGroup(group, [0]);
                            });
                        }
                        this.doSetGroupAndPanelActive(group);
                    }
                }));
                this._popoutGroups.push(value);
                this.updateWatermark();
                return true;
            })
                .catch((err) => {
                console.error('dockview: failed to create popout window', err);
                return false;
            });
        }
        addFloatingGroup(item, options) {
            var _a, _b, _c, _d, _e;
            let group;
            if (item instanceof DockviewPanel) {
                group = this.createGroup();
                this._onDidAddGroup.fire(group);
                this.movingLock(() => this.removePanel(item, {
                    removeEmptyGroup: true,
                    skipDispose: true,
                    skipSetActiveGroup: true,
                }));
                this.movingLock(() => group.model.openPanel(item, { skipSetGroupActive: true }));
            }
            else {
                group = item;
                const popoutReferenceGroupId = (_a = this._popoutGroups.find((_) => _.popoutGroup === group)) === null || _a === void 0 ? void 0 : _a.referenceGroup;
                const popoutReferenceGroup = popoutReferenceGroupId
                    ? this.getPanel(popoutReferenceGroupId)
                    : undefined;
                const skip = typeof (options === null || options === void 0 ? void 0 : options.skipRemoveGroup) === 'boolean' &&
                    options.skipRemoveGroup;
                if (!skip) {
                    if (popoutReferenceGroup) {
                        this.movingLock(() => moveGroupWithoutDestroying({
                            from: item,
                            to: popoutReferenceGroup,
                        }));
                        this.doRemoveGroup(item, {
                            skipPopoutReturn: true,
                            skipPopoutAssociated: true,
                        });
                        this.doRemoveGroup(popoutReferenceGroup, {
                            skipDispose: true,
                        });
                        group = popoutReferenceGroup;
                    }
                    else {
                        this.doRemoveGroup(item, {
                            skipDispose: true,
                            skipPopoutReturn: true,
                            skipPopoutAssociated: false,
                        });
                    }
                }
            }
            function getAnchoredBox() {
                if (options === null || options === void 0 ? void 0 : options.position) {
                    const result = {};
                    if ('left' in options.position) {
                        result.left = Math.max(options.position.left, 0);
                    }
                    else if ('right' in options.position) {
                        result.right = Math.max(options.position.right, 0);
                    }
                    else {
                        result.left = DEFAULT_FLOATING_GROUP_POSITION.left;
                    }
                    if ('top' in options.position) {
                        result.top = Math.max(options.position.top, 0);
                    }
                    else if ('bottom' in options.position) {
                        result.bottom = Math.max(options.position.bottom, 0);
                    }
                    else {
                        result.top = DEFAULT_FLOATING_GROUP_POSITION.top;
                    }
                    if (typeof options.width === 'number') {
                        result.width = Math.max(options.width, 0);
                    }
                    else {
                        result.width = DEFAULT_FLOATING_GROUP_POSITION.width;
                    }
                    if (typeof options.height === 'number') {
                        result.height = Math.max(options.height, 0);
                    }
                    else {
                        result.height = DEFAULT_FLOATING_GROUP_POSITION.height;
                    }
                    return result;
                }
                return {
                    left: typeof (options === null || options === void 0 ? void 0 : options.x) === 'number'
                        ? Math.max(options.x, 0)
                        : DEFAULT_FLOATING_GROUP_POSITION.left,
                    top: typeof (options === null || options === void 0 ? void 0 : options.y) === 'number'
                        ? Math.max(options.y, 0)
                        : DEFAULT_FLOATING_GROUP_POSITION.top,
                    width: typeof (options === null || options === void 0 ? void 0 : options.width) === 'number'
                        ? Math.max(options.width, 0)
                        : DEFAULT_FLOATING_GROUP_POSITION.width,
                    height: typeof (options === null || options === void 0 ? void 0 : options.height) === 'number'
                        ? Math.max(options.height, 0)
                        : DEFAULT_FLOATING_GROUP_POSITION.height,
                };
            }
            const anchoredBox = getAnchoredBox();
            const overlay = new Overlay(Object.assign(Object.assign({ container: this.gridview.element, content: group.element }, anchoredBox), { minimumInViewportWidth: this.options.floatingGroupBounds === 'boundedWithinViewport'
                    ? undefined
                    : (_c = (_b = this.options.floatingGroupBounds) === null || _b === void 0 ? void 0 : _b.minimumWidthWithinViewport) !== null && _c !== void 0 ? _c : DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE, minimumInViewportHeight: this.options.floatingGroupBounds === 'boundedWithinViewport'
                    ? undefined
                    : (_e = (_d = this.options.floatingGroupBounds) === null || _d === void 0 ? void 0 : _d.minimumHeightWithinViewport) !== null && _e !== void 0 ? _e : DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE }));
            const el = group.element.querySelector('.dv-void-container');
            if (!el) {
                throw new Error('failed to find drag handle');
            }
            overlay.setupDrag(el, {
                inDragMode: typeof (options === null || options === void 0 ? void 0 : options.inDragMode) === 'boolean'
                    ? options.inDragMode
                    : false,
            });
            const floatingGroupPanel = new DockviewFloatingGroupPanel(group, overlay);
            const disposable = new CompositeDisposable(group.api.onDidActiveChange((event) => {
                if (event.isActive) {
                    overlay.bringToFront();
                }
            }), watchElementResize(group.element, (entry) => {
                const { width, height } = entry.contentRect;
                group.layout(width, height); // let the group know it's size is changing so it can fire events to the panel
            }));
            floatingGroupPanel.addDisposables(overlay.onDidChange(() => {
                // this is either a resize or a move
                // to inform the panels .layout(...) the group with it's current size
                // don't care about resize since the above watcher handles that
                group.layout(group.width, group.height);
            }), overlay.onDidChangeEnd(() => {
                this._bufferOnDidLayoutChange.fire();
            }), group.onDidChange((event) => {
                overlay.setBounds({
                    height: event === null || event === void 0 ? void 0 : event.height,
                    width: event === null || event === void 0 ? void 0 : event.width,
                });
            }), {
                dispose: () => {
                    disposable.dispose();
                    remove(this._floatingGroups, floatingGroupPanel);
                    group.model.location = { type: 'grid' };
                    this.updateWatermark();
                },
            });
            this._floatingGroups.push(floatingGroupPanel);
            group.model.location = { type: 'floating' };
            if (!(options === null || options === void 0 ? void 0 : options.skipActiveGroup)) {
                this.doSetGroupAndPanelActive(group);
            }
            this.updateWatermark();
        }
        orthogonalize(position, options) {
            switch (position) {
                case 'top':
                case 'bottom':
                    if (this.gridview.orientation === exports.Orientation.HORIZONTAL) {
                        // we need to add to a vertical splitview but the current root is a horizontal splitview.
                        // insert a vertical splitview at the root level and add the existing view as a child
                        this.gridview.insertOrthogonalSplitviewAtRoot();
                    }
                    break;
                case 'left':
                case 'right':
                    if (this.gridview.orientation === exports.Orientation.VERTICAL) {
                        // we need to add to a horizontal splitview but the current root is a vertical splitview.
                        // insert a horiziontal splitview at the root level and add the existing view as a child
                        this.gridview.insertOrthogonalSplitviewAtRoot();
                    }
                    break;
            }
            switch (position) {
                case 'top':
                case 'left':
                case 'center':
                    return this.createGroupAtLocation([0], undefined, options); // insert into first position
                case 'bottom':
                case 'right':
                    return this.createGroupAtLocation([this.gridview.length], undefined, options); // insert into last position
                default:
                    throw new Error(`unsupported position ${position}`);
            }
        }
        updateOptions(options) {
            var _a, _b;
            super.updateOptions(options);
            if ('floatingGroupBounds' in options) {
                for (const group of this._floatingGroups) {
                    switch (options.floatingGroupBounds) {
                        case 'boundedWithinViewport':
                            group.overlay.minimumInViewportHeight = undefined;
                            group.overlay.minimumInViewportWidth = undefined;
                            break;
                        case undefined:
                            group.overlay.minimumInViewportHeight =
                                DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
                            group.overlay.minimumInViewportWidth =
                                DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
                            break;
                        default:
                            group.overlay.minimumInViewportHeight =
                                (_a = options.floatingGroupBounds) === null || _a === void 0 ? void 0 : _a.minimumHeightWithinViewport;
                            group.overlay.minimumInViewportWidth =
                                (_b = options.floatingGroupBounds) === null || _b === void 0 ? void 0 : _b.minimumWidthWithinViewport;
                    }
                    group.overlay.setBounds();
                }
            }
            this.updateDropTargetModel(options);
            this._options = Object.assign(Object.assign({}, this.options), options);
            if ('theme' in options) {
                this.updateTheme();
            }
            this.layout(this.gridview.width, this.gridview.height, true);
        }
        layout(width, height, forceResize) {
            super.layout(width, height, forceResize);
            if (this._floatingGroups) {
                for (const floating of this._floatingGroups) {
                    // ensure floting groups stay within visible boundaries
                    floating.overlay.setBounds();
                }
            }
        }
        focus() {
            var _a;
            (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.focus();
        }
        getGroupPanel(id) {
            return this.panels.find((panel) => panel.id === id);
        }
        setActivePanel(panel) {
            panel.group.model.openPanel(panel);
            this.doSetGroupAndPanelActive(panel.group);
        }
        moveToNext(options = {}) {
            var _a;
            if (!options.group) {
                if (!this.activeGroup) {
                    return;
                }
                options.group = this.activeGroup;
            }
            if (options.includePanel && options.group) {
                if (options.group.activePanel !==
                    options.group.panels[options.group.panels.length - 1]) {
                    options.group.model.moveToNext({ suppressRoll: true });
                    return;
                }
            }
            const location = getGridLocation(options.group.element);
            const next = (_a = this.gridview.next(location)) === null || _a === void 0 ? void 0 : _a.view;
            this.doSetGroupAndPanelActive(next);
        }
        moveToPrevious(options = {}) {
            var _a;
            if (!options.group) {
                if (!this.activeGroup) {
                    return;
                }
                options.group = this.activeGroup;
            }
            if (options.includePanel && options.group) {
                if (options.group.activePanel !== options.group.panels[0]) {
                    options.group.model.moveToPrevious({ suppressRoll: true });
                    return;
                }
            }
            const location = getGridLocation(options.group.element);
            const next = (_a = this.gridview.previous(location)) === null || _a === void 0 ? void 0 : _a.view;
            if (next) {
                this.doSetGroupAndPanelActive(next);
            }
        }
        /**
         * Serialize the current state of the layout
         *
         * @returns A JSON respresentation of the layout
         */
        toJSON() {
            var _a;
            const data = this.gridview.serialize();
            const panels = this.panels.reduce((collection, panel) => {
                collection[panel.id] = panel.toJSON();
                return collection;
            }, {});
            const floats = this._floatingGroups.map((group) => {
                return {
                    data: group.group.toJSON(),
                    position: group.overlay.toJSON(),
                };
            });
            const popoutGroups = this._popoutGroups.map((group) => {
                return {
                    data: group.popoutGroup.toJSON(),
                    gridReferenceGroup: group.referenceGroup,
                    position: group.window.dimensions(),
                    url: group.popoutGroup.api.location.type === 'popout'
                        ? group.popoutGroup.api.location.popoutUrl
                        : undefined,
                };
            });
            const result = {
                grid: data,
                panels,
                activeGroup: (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.id,
            };
            if (floats.length > 0) {
                result.floatingGroups = floats;
            }
            if (popoutGroups.length > 0) {
                result.popoutGroups = popoutGroups;
            }
            return result;
        }
        fromJSON(data) {
            var _a, _b, _c;
            this.clear();
            if (typeof data !== 'object' || data === null) {
                throw new Error('serialized layout must be a non-null object');
            }
            const { grid, panels, activeGroup } = data;
            if (grid.root.type !== 'branch' || !Array.isArray(grid.root.data)) {
                throw new Error('root must be of type branch');
            }
            try {
                // take note of the existing dimensions
                const width = this.width;
                const height = this.height;
                const createGroupFromSerializedState = (data) => {
                    const { id, locked, hideHeader, views, activeView } = data;
                    if (typeof id !== 'string') {
                        throw new Error('group id must be of type string');
                    }
                    const group = this.createGroup({
                        id,
                        locked: !!locked,
                        hideHeader: !!hideHeader,
                    });
                    this._onDidAddGroup.fire(group);
                    const createdPanels = [];
                    for (const child of views) {
                        /**
                         * Run the deserializer step seperately since this may fail to due corrupted external state.
                         * In running this section first we avoid firing lots of 'add' events in the event of a failure
                         * due to a corruption of input data.
                         */
                        const panel = this._deserializer.fromJSON(panels[child], group);
                        createdPanels.push(panel);
                    }
                    for (let i = 0; i < views.length; i++) {
                        const panel = createdPanels[i];
                        const isActive = typeof activeView === 'string' &&
                            activeView === panel.id;
                        group.model.openPanel(panel, {
                            skipSetActive: !isActive,
                            skipSetGroupActive: true,
                        });
                    }
                    if (!group.activePanel && group.panels.length > 0) {
                        group.model.openPanel(group.panels[group.panels.length - 1], {
                            skipSetGroupActive: true,
                        });
                    }
                    return group;
                };
                this.gridview.deserialize(grid, {
                    fromJSON: (node) => {
                        return createGroupFromSerializedState(node.data);
                    },
                });
                this.layout(width, height, true);
                const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
                for (const serializedFloatingGroup of serializedFloatingGroups) {
                    const { data, position } = serializedFloatingGroup;
                    const group = createGroupFromSerializedState(data);
                    this.addFloatingGroup(group, {
                        position: position,
                        width: position.width,
                        height: position.height,
                        skipRemoveGroup: true,
                        inDragMode: false,
                    });
                }
                const serializedPopoutGroups = (_b = data.popoutGroups) !== null && _b !== void 0 ? _b : [];
                for (const serializedPopoutGroup of serializedPopoutGroups) {
                    const { data, position, gridReferenceGroup, url } = serializedPopoutGroup;
                    const group = createGroupFromSerializedState(data);
                    this.addPopoutGroup((_c = (gridReferenceGroup
                        ? this.getPanel(gridReferenceGroup)
                        : undefined)) !== null && _c !== void 0 ? _c : group, {
                        position: position !== null && position !== void 0 ? position : undefined,
                        overridePopoutGroup: gridReferenceGroup
                            ? group
                            : undefined,
                        popoutUrl: url,
                    });
                }
                for (const floatingGroup of this._floatingGroups) {
                    floatingGroup.overlay.setBounds();
                }
                if (typeof activeGroup === 'string') {
                    const panel = this.getPanel(activeGroup);
                    if (panel) {
                        this.doSetGroupAndPanelActive(panel);
                    }
                }
            }
            catch (err) {
                console.error('dockview: failed to deserialize layout. Reverting changes', err);
                /**
                 * Takes all the successfully created groups and remove all of their panels.
                 */
                for (const group of this.groups) {
                    for (const panel of group.panels) {
                        this.removePanel(panel, {
                            removeEmptyGroup: false,
                            skipDispose: false,
                        });
                    }
                }
                /**
                 * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
                 * the underlying HTMLElement existing in the Gridview.
                 */
                for (const group of this.groups) {
                    group.dispose();
                    this._groups.delete(group.id);
                    this._onDidRemoveGroup.fire(group);
                }
                // iterate over a reassigned array since original array will be modified
                for (const floatingGroup of [...this._floatingGroups]) {
                    floatingGroup.dispose();
                }
                // fires clean-up events and clears the underlying HTML gridview.
                this.clear();
                /**
                 * even though we have cleaned-up we still want to inform the caller of their error
                 * and we'll do this through re-throwing the original error since afterall you would
                 * expect trying to load a corrupted layout to result in an error and not silently fail...
                 */
                throw err;
            }
            this.updateWatermark();
            this._onDidLayoutFromJSON.fire();
        }
        clear() {
            const groups = Array.from(this._groups.values()).map((_) => _.value);
            const hasActiveGroup = !!this.activeGroup;
            for (const group of groups) {
                // remove the group will automatically remove the panels
                this.removeGroup(group, { skipActive: true });
            }
            if (hasActiveGroup) {
                this.doSetGroupAndPanelActive(undefined);
            }
            this.gridview.clear();
        }
        closeAllGroups() {
            for (const entry of this._groups.entries()) {
                const [_, group] = entry;
                group.value.model.closeAllPanels();
            }
        }
        addPanel(options) {
            var _a, _b;
            if (this.panels.find((_) => _.id === options.id)) {
                throw new Error(`panel with id ${options.id} already exists`);
            }
            let referenceGroup;
            if (options.position && options.floating) {
                throw new Error('you can only provide one of: position, floating as arguments to .addPanel(...)');
            }
            const initial = {
                width: options.initialWidth,
                height: options.initialHeight,
            };
            let index;
            if (options.position) {
                if (isPanelOptionsWithPanel(options.position)) {
                    const referencePanel = typeof options.position.referencePanel === 'string'
                        ? this.getGroupPanel(options.position.referencePanel)
                        : options.position.referencePanel;
                    index = options.position.index;
                    if (!referencePanel) {
                        throw new Error(`referencePanel '${options.position.referencePanel}' does not exist`);
                    }
                    referenceGroup = this.findGroup(referencePanel);
                }
                else if (isPanelOptionsWithGroup(options.position)) {
                    referenceGroup =
                        typeof options.position.referenceGroup === 'string'
                            ? (_a = this._groups.get(options.position.referenceGroup)) === null || _a === void 0 ? void 0 : _a.value
                            : options.position.referenceGroup;
                    index = options.position.index;
                    if (!referenceGroup) {
                        throw new Error(`referenceGroup '${options.position.referenceGroup}' does not exist`);
                    }
                }
                else {
                    const group = this.orthogonalize(directionToPosition(options.position.direction));
                    const panel = this.createPanel(options, group);
                    group.model.openPanel(panel, {
                        skipSetActive: options.inactive,
                        skipSetGroupActive: options.inactive,
                        index,
                    });
                    if (!options.inactive) {
                        this.doSetGroupAndPanelActive(group);
                    }
                    group.api.setSize({
                        height: initial === null || initial === void 0 ? void 0 : initial.height,
                        width: initial === null || initial === void 0 ? void 0 : initial.width,
                    });
                    return panel;
                }
            }
            else {
                referenceGroup = this.activeGroup;
            }
            let panel;
            if (referenceGroup) {
                const target = toTarget(((_b = options.position) === null || _b === void 0 ? void 0 : _b.direction) || 'within');
                if (options.floating) {
                    const group = this.createGroup();
                    this._onDidAddGroup.fire(group);
                    const floatingGroupOptions = typeof options.floating === 'object' &&
                        options.floating !== null
                        ? options.floating
                        : {};
                    this.addFloatingGroup(group, Object.assign(Object.assign({}, floatingGroupOptions), { inDragMode: false, skipRemoveGroup: true, skipActiveGroup: true }));
                    panel = this.createPanel(options, group);
                    group.model.openPanel(panel, {
                        skipSetActive: options.inactive,
                        skipSetGroupActive: options.inactive,
                        index,
                    });
                }
                else if (referenceGroup.api.location.type === 'floating' ||
                    target === 'center') {
                    panel = this.createPanel(options, referenceGroup);
                    referenceGroup.model.openPanel(panel, {
                        skipSetActive: options.inactive,
                        skipSetGroupActive: options.inactive,
                        index,
                    });
                    referenceGroup.api.setSize({
                        width: initial === null || initial === void 0 ? void 0 : initial.width,
                        height: initial === null || initial === void 0 ? void 0 : initial.height,
                    });
                    if (!options.inactive) {
                        this.doSetGroupAndPanelActive(referenceGroup);
                    }
                }
                else {
                    const location = getGridLocation(referenceGroup.element);
                    const relativeLocation = getRelativeLocation(this.gridview.orientation, location, target);
                    const group = this.createGroupAtLocation(relativeLocation, this.orientationAtLocation(relativeLocation) ===
                        exports.Orientation.VERTICAL
                        ? initial === null || initial === void 0 ? void 0 : initial.height
                        : initial === null || initial === void 0 ? void 0 : initial.width);
                    panel = this.createPanel(options, group);
                    group.model.openPanel(panel, {
                        skipSetActive: options.inactive,
                        skipSetGroupActive: options.inactive,
                        index,
                    });
                    if (!options.inactive) {
                        this.doSetGroupAndPanelActive(group);
                    }
                }
            }
            else if (options.floating) {
                const group = this.createGroup();
                this._onDidAddGroup.fire(group);
                const coordinates = typeof options.floating === 'object' &&
                    options.floating !== null
                    ? options.floating
                    : {};
                this.addFloatingGroup(group, Object.assign(Object.assign({}, coordinates), { inDragMode: false, skipRemoveGroup: true, skipActiveGroup: true }));
                panel = this.createPanel(options, group);
                group.model.openPanel(panel, {
                    skipSetActive: options.inactive,
                    skipSetGroupActive: options.inactive,
                    index,
                });
            }
            else {
                const group = this.createGroupAtLocation([0], this.gridview.orientation === exports.Orientation.VERTICAL
                    ? initial === null || initial === void 0 ? void 0 : initial.height
                    : initial === null || initial === void 0 ? void 0 : initial.width);
                panel = this.createPanel(options, group);
                group.model.openPanel(panel, {
                    skipSetActive: options.inactive,
                    skipSetGroupActive: options.inactive,
                    index,
                });
                if (!options.inactive) {
                    this.doSetGroupAndPanelActive(group);
                }
            }
            return panel;
        }
        removePanel(panel, options = {
            removeEmptyGroup: true,
        }) {
            const group = panel.group;
            if (!group) {
                throw new Error(`cannot remove panel ${panel.id}. it's missing a group.`);
            }
            group.model.removePanel(panel, {
                skipSetActiveGroup: options.skipSetActiveGroup,
            });
            if (!options.skipDispose) {
                panel.group.model.renderContainer.detatch(panel);
                panel.dispose();
            }
            if (group.size === 0 && options.removeEmptyGroup) {
                this.removeGroup(group, { skipActive: options.skipSetActiveGroup });
            }
        }
        createWatermarkComponent() {
            if (this.options.createWatermarkComponent) {
                return this.options.createWatermarkComponent();
            }
            return new Watermark();
        }
        updateWatermark() {
            var _a, _b;
            if (this.groups.filter((x) => x.api.location.type === 'grid' && x.api.isVisible).length === 0) {
                if (!this._watermark) {
                    this._watermark = this.createWatermarkComponent();
                    this._watermark.init({
                        containerApi: new DockviewApi(this),
                    });
                    const watermarkContainer = document.createElement('div');
                    watermarkContainer.className = 'dv-watermark-container';
                    addTestId(watermarkContainer, 'watermark-component');
                    watermarkContainer.appendChild(this._watermark.element);
                    this.gridview.element.appendChild(watermarkContainer);
                }
            }
            else if (this._watermark) {
                this._watermark.element.parentElement.remove();
                (_b = (_a = this._watermark).dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
                this._watermark = null;
            }
        }
        addGroup(options) {
            var _a;
            if (options) {
                let referenceGroup;
                if (isGroupOptionsWithPanel(options)) {
                    const referencePanel = typeof options.referencePanel === 'string'
                        ? this.panels.find((panel) => panel.id === options.referencePanel)
                        : options.referencePanel;
                    if (!referencePanel) {
                        throw new Error(`reference panel ${options.referencePanel} does not exist`);
                    }
                    referenceGroup = this.findGroup(referencePanel);
                    if (!referenceGroup) {
                        throw new Error(`reference group for reference panel ${options.referencePanel} does not exist`);
                    }
                }
                else if (isGroupOptionsWithGroup(options)) {
                    referenceGroup =
                        typeof options.referenceGroup === 'string'
                            ? (_a = this._groups.get(options.referenceGroup)) === null || _a === void 0 ? void 0 : _a.value
                            : options.referenceGroup;
                    if (!referenceGroup) {
                        throw new Error(`reference group ${options.referenceGroup} does not exist`);
                    }
                }
                else {
                    const group = this.orthogonalize(directionToPosition(options.direction), options);
                    if (!options.skipSetActive) {
                        this.doSetGroupAndPanelActive(group);
                    }
                    return group;
                }
                const target = toTarget(options.direction || 'within');
                const location = getGridLocation(referenceGroup.element);
                const relativeLocation = getRelativeLocation(this.gridview.orientation, location, target);
                const group = this.createGroup(options);
                const size = this.getLocationOrientation(relativeLocation) ===
                    exports.Orientation.VERTICAL
                    ? options.initialHeight
                    : options.initialWidth;
                this.doAddGroup(group, relativeLocation, size);
                if (!options.skipSetActive) {
                    this.doSetGroupAndPanelActive(group);
                }
                return group;
            }
            else {
                const group = this.createGroup(options);
                this.doAddGroup(group);
                this.doSetGroupAndPanelActive(group);
                return group;
            }
        }
        getLocationOrientation(location) {
            return location.length % 2 == 0 &&
                this.gridview.orientation === exports.Orientation.HORIZONTAL
                ? exports.Orientation.HORIZONTAL
                : exports.Orientation.VERTICAL;
        }
        removeGroup(group, options) {
            this.doRemoveGroup(group, options);
        }
        doRemoveGroup(group, options) {
            var _a;
            const panels = [...group.panels]; // reassign since group panels will mutate
            if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
                for (const panel of panels) {
                    this.removePanel(panel, {
                        removeEmptyGroup: false,
                        skipDispose: (_a = options === null || options === void 0 ? void 0 : options.skipDispose) !== null && _a !== void 0 ? _a : false,
                    });
                }
            }
            const activePanel = this.activePanel;
            if (group.api.location.type === 'floating') {
                const floatingGroup = this._floatingGroups.find((_) => _.group === group);
                if (floatingGroup) {
                    if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
                        floatingGroup.group.dispose();
                        this._groups.delete(group.id);
                        this._onDidRemoveGroup.fire(group);
                    }
                    remove(this._floatingGroups, floatingGroup);
                    floatingGroup.dispose();
                    if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
                        const groups = Array.from(this._groups.values());
                        this.doSetGroupAndPanelActive(groups.length > 0 ? groups[0].value : undefined);
                    }
                    return floatingGroup.group;
                }
                throw new Error('failed to find floating group');
            }
            if (group.api.location.type === 'popout') {
                const selectedGroup = this._popoutGroups.find((_) => _.popoutGroup === group);
                if (selectedGroup) {
                    if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
                        if (!(options === null || options === void 0 ? void 0 : options.skipPopoutAssociated)) {
                            const refGroup = selectedGroup.referenceGroup
                                ? this.getPanel(selectedGroup.referenceGroup)
                                : undefined;
                            if (refGroup && refGroup.panels.length === 0) {
                                this.removeGroup(refGroup);
                            }
                        }
                        selectedGroup.popoutGroup.dispose();
                        this._groups.delete(group.id);
                        this._onDidRemoveGroup.fire(group);
                    }
                    remove(this._popoutGroups, selectedGroup);
                    const removedGroup = selectedGroup.disposable.dispose();
                    if (!(options === null || options === void 0 ? void 0 : options.skipPopoutReturn) && removedGroup) {
                        this.doAddGroup(removedGroup, [0]);
                        this.doSetGroupAndPanelActive(removedGroup);
                    }
                    if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
                        const groups = Array.from(this._groups.values());
                        this.doSetGroupAndPanelActive(groups.length > 0 ? groups[0].value : undefined);
                    }
                    this.updateWatermark();
                    return selectedGroup.popoutGroup;
                }
                throw new Error('failed to find popout group');
            }
            const re = super.doRemoveGroup(group, options);
            if (!(options === null || options === void 0 ? void 0 : options.skipActive)) {
                if (this.activePanel !== activePanel) {
                    this._onDidActivePanelChange.fire(this.activePanel);
                }
            }
            return re;
        }
        movingLock(func) {
            const isMoving = this._moving;
            try {
                this._moving = true;
                return func();
            }
            finally {
                this._moving = isMoving;
            }
        }
        moveGroupOrPanel(options) {
            var _a;
            const destinationGroup = options.to.group;
            const sourceGroupId = options.from.groupId;
            const sourceItemId = options.from.panelId;
            const destinationTarget = options.to.position;
            const destinationIndex = options.to.index;
            const sourceGroup = sourceGroupId
                ? (_a = this._groups.get(sourceGroupId)) === null || _a === void 0 ? void 0 : _a.value
                : undefined;
            if (!sourceGroup) {
                throw new Error(`Failed to find group id ${sourceGroupId}`);
            }
            if (sourceItemId === undefined) {
                /**
                 * Moving an entire group into another group
                 */
                this.moveGroup({
                    from: { group: sourceGroup },
                    to: {
                        group: destinationGroup,
                        position: destinationTarget,
                    },
                });
                return;
            }
            if (!destinationTarget || destinationTarget === 'center') {
                /**
                 * Dropping a panel within another group
                 */
                const removedPanel = this.movingLock(() => sourceGroup.model.removePanel(sourceItemId, {
                    skipSetActive: false,
                    skipSetActiveGroup: true,
                }));
                if (!removedPanel) {
                    throw new Error(`No panel with id ${sourceItemId}`);
                }
                if (sourceGroup.model.size === 0) {
                    // remove the group and do not set a new group as active
                    this.doRemoveGroup(sourceGroup, { skipActive: true });
                }
                this.movingLock(() => destinationGroup.model.openPanel(removedPanel, {
                    index: destinationIndex,
                    skipSetGroupActive: true,
                }));
                this.doSetGroupAndPanelActive(destinationGroup);
                this._onDidMovePanel.fire({
                    panel: removedPanel,
                    from: sourceGroup,
                });
            }
            else {
                /**
                 * Dropping a panel to the extremities of a group which will place that panel
                 * into an adjacent group
                 */
                const referenceLocation = getGridLocation(destinationGroup.element);
                const targetLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
                if (sourceGroup.size < 2) {
                    /**
                     * If we are moving from a group which only has one panel left we will consider
                     * moving the group itself rather than moving the panel into a newly created group
                     */
                    const [targetParentLocation, to] = tail(targetLocation);
                    if (sourceGroup.api.location.type === 'grid') {
                        const sourceLocation = getGridLocation(sourceGroup.element);
                        const [sourceParentLocation, from] = tail(sourceLocation);
                        if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
                            // special case when 'swapping' two views within same grid location
                            // if a group has one tab - we are essentially moving the 'group'
                            // which is equivalent to swapping two views in this case
                            this.gridview.moveView(sourceParentLocation, from, to);
                            this._onDidMovePanel.fire({
                                panel: this.getGroupPanel(sourceItemId),
                                from: sourceGroup,
                            });
                            return;
                        }
                    }
                    if (sourceGroup.api.location.type === 'popout') {
                        /**
                         * the source group is a popout group with a single panel
                         *
                         * 1. remove the panel from the group without triggering any events
                         * 2. remove the popout group
                         * 3. create a new group at the requested location and add that panel
                         */
                        const popoutGroup = this._popoutGroups.find((group) => group.popoutGroup === sourceGroup);
                        const removedPanel = this.movingLock(() => popoutGroup.popoutGroup.model.removePanel(popoutGroup.popoutGroup.panels[0], {
                            skipSetActive: true,
                            skipSetActiveGroup: true,
                        }));
                        this.doRemoveGroup(sourceGroup, { skipActive: true });
                        const newGroup = this.createGroupAtLocation(targetLocation);
                        this.movingLock(() => newGroup.model.openPanel(removedPanel));
                        this.doSetGroupAndPanelActive(newGroup);
                        this._onDidMovePanel.fire({
                            panel: this.getGroupPanel(sourceItemId),
                            from: sourceGroup,
                        });
                        return;
                    }
                    // source group will become empty so delete the group
                    const targetGroup = this.movingLock(() => this.doRemoveGroup(sourceGroup, {
                        skipActive: true,
                        skipDispose: true,
                    }));
                    // after deleting the group we need to re-evaulate the ref location
                    const updatedReferenceLocation = getGridLocation(destinationGroup.element);
                    const location = getRelativeLocation(this.gridview.orientation, updatedReferenceLocation, destinationTarget);
                    this.movingLock(() => this.doAddGroup(targetGroup, location));
                    this.doSetGroupAndPanelActive(targetGroup);
                    this._onDidMovePanel.fire({
                        panel: this.getGroupPanel(sourceItemId),
                        from: sourceGroup,
                    });
                }
                else {
                    /**
                     * The group we are removing from has many panels, we need to remove the panels we are moving,
                     * create a new group, add the panels to that new group and add the new group in an appropiate position
                     */
                    const removedPanel = this.movingLock(() => sourceGroup.model.removePanel(sourceItemId, {
                        skipSetActive: false,
                        skipSetActiveGroup: true,
                    }));
                    if (!removedPanel) {
                        throw new Error(`No panel with id ${sourceItemId}`);
                    }
                    const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
                    const group = this.createGroupAtLocation(dropLocation);
                    this.movingLock(() => group.model.openPanel(removedPanel, {
                        skipSetGroupActive: true,
                    }));
                    this.doSetGroupAndPanelActive(group);
                    this._onDidMovePanel.fire({
                        panel: removedPanel,
                        from: sourceGroup,
                    });
                }
            }
        }
        moveGroup(options) {
            const from = options.from.group;
            const to = options.to.group;
            const target = options.to.position;
            if (target === 'center') {
                const activePanel = from.activePanel;
                const panels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, {
                    skipSetActive: true,
                })));
                if ((from === null || from === void 0 ? void 0 : from.model.size) === 0) {
                    this.doRemoveGroup(from, { skipActive: true });
                }
                this.movingLock(() => {
                    for (const panel of panels) {
                        to.model.openPanel(panel, {
                            skipSetActive: panel !== activePanel,
                            skipSetGroupActive: true,
                        });
                    }
                });
                this.doSetGroupAndPanelActive(to);
            }
            else {
                switch (from.api.location.type) {
                    case 'grid':
                        this.gridview.removeView(getGridLocation(from.element));
                        break;
                    case 'floating': {
                        const selectedFloatingGroup = this._floatingGroups.find((x) => x.group === from);
                        if (!selectedFloatingGroup) {
                            throw new Error('failed to find floating group');
                        }
                        selectedFloatingGroup.dispose();
                        break;
                    }
                    case 'popout': {
                        const selectedPopoutGroup = this._popoutGroups.find((x) => x.popoutGroup === from);
                        if (!selectedPopoutGroup) {
                            throw new Error('failed to find popout group');
                        }
                        selectedPopoutGroup.disposable.dispose();
                    }
                }
                const referenceLocation = getGridLocation(to.element);
                const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, target);
                let size;
                switch (this.gridview.orientation) {
                    case exports.Orientation.VERTICAL:
                        size =
                            referenceLocation.length % 2 == 0
                                ? from.api.width
                                : from.api.height;
                        break;
                    case exports.Orientation.HORIZONTAL:
                        size =
                            referenceLocation.length % 2 == 0
                                ? from.api.height
                                : from.api.width;
                        break;
                }
                this.gridview.addView(from, size, dropLocation);
            }
            from.panels.forEach((panel) => {
                this._onDidMovePanel.fire({ panel, from });
            });
        }
        doSetGroupActive(group) {
            super.doSetGroupActive(group);
            const activePanel = this.activePanel;
            if (!this._moving &&
                activePanel !== this._onDidActivePanelChange.value) {
                this._onDidActivePanelChange.fire(activePanel);
            }
        }
        doSetGroupAndPanelActive(group) {
            super.doSetGroupActive(group);
            const activePanel = this.activePanel;
            if (group &&
                this.hasMaximizedGroup() &&
                !this.isMaximizedGroup(group)) {
                this.exitMaximizedGroup();
            }
            if (!this._moving &&
                activePanel !== this._onDidActivePanelChange.value) {
                this._onDidActivePanelChange.fire(activePanel);
            }
        }
        getNextGroupId() {
            let id = this.nextGroupId.next();
            while (this._groups.has(id)) {
                id = this.nextGroupId.next();
            }
            return id;
        }
        createGroup(options) {
            if (!options) {
                options = {};
            }
            let id = options === null || options === void 0 ? void 0 : options.id;
            if (id && this._groups.has(options.id)) {
                console.warn(`dockview: Duplicate group id ${options === null || options === void 0 ? void 0 : options.id}. reassigning group id to avoid errors`);
                id = undefined;
            }
            if (!id) {
                id = this.nextGroupId.next();
                while (this._groups.has(id)) {
                    id = this.nextGroupId.next();
                }
            }
            const view = new DockviewGroupPanel(this, id, options);
            view.init({ params: {}, accessor: this });
            if (!this._groups.has(view.id)) {
                const disposable = new CompositeDisposable(view.model.onTabDragStart((event) => {
                    this._onWillDragPanel.fire(event);
                }), view.model.onGroupDragStart((event) => {
                    this._onWillDragGroup.fire(event);
                }), view.model.onMove((event) => {
                    const { groupId, itemId, target, index } = event;
                    this.moveGroupOrPanel({
                        from: { groupId: groupId, panelId: itemId },
                        to: {
                            group: view,
                            position: target,
                            index,
                        },
                    });
                }), view.model.onDidDrop((event) => {
                    this._onDidDrop.fire(event);
                }), view.model.onWillDrop((event) => {
                    this._onWillDrop.fire(event);
                }), view.model.onWillShowOverlay((event) => {
                    if (this.options.disableDnd) {
                        event.preventDefault();
                        return;
                    }
                    this._onWillShowOverlay.fire(event);
                }), view.model.onUnhandledDragOverEvent((event) => {
                    this._onUnhandledDragOverEvent.fire(event);
                }), view.model.onDidAddPanel((event) => {
                    if (this._moving) {
                        return;
                    }
                    this._onDidAddPanel.fire(event.panel);
                }), view.model.onDidRemovePanel((event) => {
                    if (this._moving) {
                        return;
                    }
                    this._onDidRemovePanel.fire(event.panel);
                }), view.model.onDidActivePanelChange((event) => {
                    if (this._moving) {
                        return;
                    }
                    if (event.panel !== this.activePanel) {
                        return;
                    }
                    if (this._onDidActivePanelChange.value !== event.panel) {
                        this._onDidActivePanelChange.fire(event.panel);
                    }
                }), exports.DockviewEvent.any(view.model.onDidPanelTitleChange, view.model.onDidPanelParametersChange)(() => {
                    this._bufferOnDidLayoutChange.fire();
                }));
                this._groups.set(view.id, { value: view, disposable });
            }
            // TODO: must be called after the above listeners have been setup, not an ideal pattern
            view.initialize();
            return view;
        }
        createPanel(options, group) {
            var _a, _b, _c;
            const contentComponent = options.component;
            const tabComponent = (_a = options.tabComponent) !== null && _a !== void 0 ? _a : this.options.defaultTabComponent;
            const view = new DockviewPanelModel(this, options.id, contentComponent, tabComponent);
            const panel = new DockviewPanel(options.id, contentComponent, tabComponent, this, this._api, group, view, {
                renderer: options.renderer,
                minimumWidth: options.minimumWidth,
                minimumHeight: options.minimumHeight,
                maximumWidth: options.maximumWidth,
                maximumHeight: options.maximumHeight,
            });
            panel.init({
                title: (_b = options.title) !== null && _b !== void 0 ? _b : options.id,
                params: (_c = options === null || options === void 0 ? void 0 : options.params) !== null && _c !== void 0 ? _c : {},
            });
            return panel;
        }
        createGroupAtLocation(location, size, options) {
            const group = this.createGroup(options);
            this.doAddGroup(group, location, size);
            return group;
        }
        findGroup(panel) {
            var _a;
            return (_a = Array.from(this._groups.values()).find((group) => group.value.model.containsPanel(panel))) === null || _a === void 0 ? void 0 : _a.value;
        }
        orientationAtLocation(location) {
            const rootOrientation = this.gridview.orientation;
            return location.length % 2 == 1
                ? rootOrientation
                : orthogonal(rootOrientation);
        }
        updateDropTargetModel(options) {
            if ('dndEdges' in options) {
                this._rootDropTarget.disabled =
                    typeof options.dndEdges === 'boolean' &&
                        options.dndEdges === false;
                if (typeof options.dndEdges === 'object' &&
                    options.dndEdges !== null) {
                    this._rootDropTarget.setOverlayModel(options.dndEdges);
                }
                else {
                    this._rootDropTarget.setOverlayModel(DEFAULT_ROOT_OVERLAY_MODEL);
                }
            }
            if ('rootOverlayModel' in options) {
                this.updateDropTargetModel({ dndEdges: options.dndEdges });
            }
        }
        updateTheme() {
            var _a, _b;
            const theme = (_a = this._options.theme) !== null && _a !== void 0 ? _a : themeAbyss;
            this._themeClassnames.setClassNames(theme.className);
            this.gridview.margin = (_b = theme.gap) !== null && _b !== void 0 ? _b : 0;
            switch (theme.dndOverlayMounting) {
                case 'absolute':
                    this.rootDropTargetContainer.disabled = false;
                    break;
                case 'relative':
                default:
                    this.rootDropTargetContainer.disabled = true;
                    break;
            }
        }
    }

    class GridviewComponent extends BaseGrid {
        get orientation() {
            return this.gridview.orientation;
        }
        set orientation(value) {
            this.gridview.orientation = value;
        }
        get options() {
            return this._options;
        }
        get deserializer() {
            return this._deserializer;
        }
        set deserializer(value) {
            this._deserializer = value;
        }
        constructor(container, options) {
            var _a;
            super(container, {
                proportionalLayout: (_a = options.proportionalLayout) !== null && _a !== void 0 ? _a : true,
                orientation: options.orientation,
                styles: options.hideBorders
                    ? { separatorBorder: 'transparent' }
                    : undefined,
                disableAutoResizing: options.disableAutoResizing,
                className: options.className,
            });
            this._onDidLayoutfromJSON = new Emitter();
            this.onDidLayoutFromJSON = this._onDidLayoutfromJSON.event;
            this._onDidRemoveGroup = new Emitter();
            this.onDidRemoveGroup = this._onDidRemoveGroup.event;
            this._onDidAddGroup = new Emitter();
            this.onDidAddGroup = this._onDidAddGroup.event;
            this._onDidActiveGroupChange = new Emitter();
            this.onDidActiveGroupChange = this._onDidActiveGroupChange.event;
            this._options = options;
            this.addDisposables(this._onDidAddGroup, this._onDidRemoveGroup, this._onDidActiveGroupChange, this.onDidAdd((event) => {
                this._onDidAddGroup.fire(event);
            }), this.onDidRemove((event) => {
                this._onDidRemoveGroup.fire(event);
            }), this.onDidActiveChange((event) => {
                this._onDidActiveGroupChange.fire(event);
            }));
        }
        updateOptions(options) {
            super.updateOptions(options);
            const hasOrientationChanged = typeof options.orientation === 'string' &&
                this.gridview.orientation !== options.orientation;
            this._options = Object.assign(Object.assign({}, this.options), options);
            if (hasOrientationChanged) {
                this.gridview.orientation = options.orientation;
            }
            this.layout(this.gridview.width, this.gridview.height, true);
        }
        removePanel(panel) {
            this.removeGroup(panel);
        }
        /**
         * Serialize the current state of the layout
         *
         * @returns A JSON respresentation of the layout
         */
        toJSON() {
            var _a;
            const data = this.gridview.serialize();
            return {
                grid: data,
                activePanel: (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.id,
            };
        }
        setVisible(panel, visible) {
            this.gridview.setViewVisible(getGridLocation(panel.element), visible);
        }
        setActive(panel) {
            this._groups.forEach((value, _key) => {
                value.value.setActive(panel === value.value);
            });
        }
        focus() {
            var _a;
            (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.focus();
        }
        fromJSON(serializedGridview) {
            this.clear();
            const { grid, activePanel } = serializedGridview;
            try {
                const queue = [];
                // take note of the existing dimensions
                const width = this.width;
                const height = this.height;
                this.gridview.deserialize(grid, {
                    fromJSON: (node) => {
                        const { data } = node;
                        const view = this.options.createComponent({
                            id: data.id,
                            name: data.component,
                        });
                        queue.push(() => view.init({
                            params: data.params,
                            minimumWidth: data.minimumWidth,
                            maximumWidth: data.maximumWidth,
                            minimumHeight: data.minimumHeight,
                            maximumHeight: data.maximumHeight,
                            priority: data.priority,
                            snap: !!data.snap,
                            accessor: this,
                            isVisible: node.visible,
                        }));
                        this._onDidAddGroup.fire(view);
                        this.registerPanel(view);
                        return view;
                    },
                });
                this.layout(width, height, true);
                queue.forEach((f) => f());
                if (typeof activePanel === 'string') {
                    const panel = this.getPanel(activePanel);
                    if (panel) {
                        this.doSetGroupActive(panel);
                    }
                }
            }
            catch (err) {
                /**
                 * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
                 * the underlying HTMLElement existing in the Gridview.
                 */
                for (const group of this.groups) {
                    group.dispose();
                    this._groups.delete(group.id);
                    this._onDidRemoveGroup.fire(group);
                }
                // fires clean-up events and clears the underlying HTML gridview.
                this.clear();
                /**
                 * even though we have cleaned-up we still want to inform the caller of their error
                 * and we'll do this through re-throwing the original error since afterall you would
                 * expect trying to load a corrupted layout to result in an error and not silently fail...
                 */
                throw err;
            }
            this._onDidLayoutfromJSON.fire();
        }
        clear() {
            const hasActiveGroup = this.activeGroup;
            const groups = Array.from(this._groups.values()); // reassign since group panels will mutate
            for (const group of groups) {
                group.disposable.dispose();
                this.doRemoveGroup(group.value, { skipActive: true });
            }
            if (hasActiveGroup) {
                this.doSetGroupActive(undefined);
            }
            this.gridview.clear();
        }
        movePanel(panel, options) {
            var _a;
            let relativeLocation;
            const removedPanel = this.gridview.remove(panel);
            const referenceGroup = (_a = this._groups.get(options.reference)) === null || _a === void 0 ? void 0 : _a.value;
            if (!referenceGroup) {
                throw new Error(`reference group ${options.reference} does not exist`);
            }
            const target = toTarget(options.direction);
            if (target === 'center') {
                throw new Error(`${target} not supported as an option`);
            }
            else {
                const location = getGridLocation(referenceGroup.element);
                relativeLocation = getRelativeLocation(this.gridview.orientation, location, target);
            }
            this.doAddGroup(removedPanel, relativeLocation, options.size);
        }
        addPanel(options) {
            var _a, _b, _c, _d;
            let relativeLocation = (_a = options.location) !== null && _a !== void 0 ? _a : [0];
            if ((_b = options.position) === null || _b === void 0 ? void 0 : _b.referencePanel) {
                const referenceGroup = (_c = this._groups.get(options.position.referencePanel)) === null || _c === void 0 ? void 0 : _c.value;
                if (!referenceGroup) {
                    throw new Error(`reference group ${options.position.referencePanel} does not exist`);
                }
                const target = toTarget(options.position.direction);
                if (target === 'center') {
                    throw new Error(`${target} not supported as an option`);
                }
                else {
                    const location = getGridLocation(referenceGroup.element);
                    relativeLocation = getRelativeLocation(this.gridview.orientation, location, target);
                }
            }
            const view = this.options.createComponent({
                id: options.id,
                name: options.component,
            });
            view.init({
                params: (_d = options.params) !== null && _d !== void 0 ? _d : {},
                minimumWidth: options.minimumWidth,
                maximumWidth: options.maximumWidth,
                minimumHeight: options.minimumHeight,
                maximumHeight: options.maximumHeight,
                priority: options.priority,
                snap: !!options.snap,
                accessor: this,
                isVisible: true,
            });
            this.registerPanel(view);
            this.doAddGroup(view, relativeLocation, options.size);
            this.doSetGroupActive(view);
            return view;
        }
        registerPanel(panel) {
            const disposable = new CompositeDisposable(panel.api.onDidFocusChange((event) => {
                if (!event.isFocused) {
                    return;
                }
                this._groups.forEach((groupItem) => {
                    const group = groupItem.value;
                    if (group !== panel) {
                        group.setActive(false);
                    }
                    else {
                        group.setActive(true);
                    }
                });
            }));
            this._groups.set(panel.id, {
                value: panel,
                disposable,
            });
        }
        moveGroup(referenceGroup, groupId, target) {
            const sourceGroup = this.getPanel(groupId);
            if (!sourceGroup) {
                throw new Error('invalid operation');
            }
            const referenceLocation = getGridLocation(referenceGroup.element);
            const targetLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, target);
            const [targetParentLocation, to] = tail(targetLocation);
            const sourceLocation = getGridLocation(sourceGroup.element);
            const [sourceParentLocation, from] = tail(sourceLocation);
            if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
                // special case when 'swapping' two views within same grid location
                // if a group has one tab - we are essentially moving the 'group'
                // which is equivalent to swapping two views in this case
                this.gridview.moveView(sourceParentLocation, from, to);
                return;
            }
            // source group will become empty so delete the group
            const targetGroup = this.doRemoveGroup(sourceGroup, {
                skipActive: true,
                skipDispose: true,
            });
            // after deleting the group we need to re-evaulate the ref location
            const updatedReferenceLocation = getGridLocation(referenceGroup.element);
            const location = getRelativeLocation(this.gridview.orientation, updatedReferenceLocation, target);
            this.doAddGroup(targetGroup, location);
        }
        removeGroup(group) {
            super.removeGroup(group);
        }
        dispose() {
            super.dispose();
            this._onDidLayoutfromJSON.dispose();
        }
    }

    /**
     * A high-level implementation of splitview that works using 'panels'
     */
    class SplitviewComponent extends Resizable {
        get panels() {
            return this.splitview.getViews();
        }
        get options() {
            return this._options;
        }
        get length() {
            return this._panels.size;
        }
        get orientation() {
            return this.splitview.orientation;
        }
        get splitview() {
            return this._splitview;
        }
        set splitview(value) {
            if (this._splitview) {
                this._splitview.dispose();
            }
            this._splitview = value;
            this._splitviewChangeDisposable.value = new CompositeDisposable(this._splitview.onDidSashEnd(() => {
                this._onDidLayoutChange.fire(undefined);
            }), this._splitview.onDidAddView((e) => this._onDidAddView.fire(e)), this._splitview.onDidRemoveView((e) => this._onDidRemoveView.fire(e)));
        }
        get minimumSize() {
            return this.splitview.minimumSize;
        }
        get maximumSize() {
            return this.splitview.maximumSize;
        }
        get height() {
            return this.splitview.orientation === exports.Orientation.HORIZONTAL
                ? this.splitview.orthogonalSize
                : this.splitview.size;
        }
        get width() {
            return this.splitview.orientation === exports.Orientation.HORIZONTAL
                ? this.splitview.size
                : this.splitview.orthogonalSize;
        }
        constructor(container, options) {
            var _a;
            super(document.createElement('div'), options.disableAutoResizing);
            this._splitviewChangeDisposable = new MutableDisposable();
            this._panels = new Map();
            this._onDidLayoutfromJSON = new Emitter();
            this.onDidLayoutFromJSON = this._onDidLayoutfromJSON.event;
            this._onDidAddView = new Emitter();
            this.onDidAddView = this._onDidAddView.event;
            this._onDidRemoveView = new Emitter();
            this.onDidRemoveView = this._onDidRemoveView.event;
            this._onDidLayoutChange = new Emitter();
            this.onDidLayoutChange = this._onDidLayoutChange.event;
            this.element.style.height = '100%';
            this.element.style.width = '100%';
            this._classNames = new Classnames(this.element);
            this._classNames.setClassNames((_a = options.className) !== null && _a !== void 0 ? _a : '');
            // the container is owned by the third-party, do not modify/delete it
            container.appendChild(this.element);
            this._options = options;
            this.splitview = new Splitview(this.element, options);
            this.addDisposables(this._onDidAddView, this._onDidLayoutfromJSON, this._onDidRemoveView, this._onDidLayoutChange);
        }
        updateOptions(options) {
            var _a, _b;
            if ('className' in options) {
                this._classNames.setClassNames((_a = options.className) !== null && _a !== void 0 ? _a : '');
            }
            if ('disableResizing' in options) {
                this.disableResizing = (_b = options.disableAutoResizing) !== null && _b !== void 0 ? _b : false;
            }
            if (typeof options.orientation === 'string') {
                this.splitview.orientation = options.orientation;
            }
            this._options = Object.assign(Object.assign({}, this.options), options);
            this.splitview.layout(this.splitview.size, this.splitview.orthogonalSize);
        }
        focus() {
            var _a;
            (_a = this._activePanel) === null || _a === void 0 ? void 0 : _a.focus();
        }
        movePanel(from, to) {
            this.splitview.moveView(from, to);
        }
        setVisible(panel, visible) {
            const index = this.panels.indexOf(panel);
            this.splitview.setViewVisible(index, visible);
        }
        setActive(panel, skipFocus) {
            this._activePanel = panel;
            this.panels
                .filter((v) => v !== panel)
                .forEach((v) => {
                v.api._onDidActiveChange.fire({ isActive: false });
                if (!skipFocus) {
                    v.focus();
                }
            });
            panel.api._onDidActiveChange.fire({ isActive: true });
            if (!skipFocus) {
                panel.focus();
            }
        }
        removePanel(panel, sizing) {
            const item = this._panels.get(panel.id);
            if (!item) {
                throw new Error(`unknown splitview panel ${panel.id}`);
            }
            item.dispose();
            this._panels.delete(panel.id);
            const index = this.panels.findIndex((_) => _ === panel);
            const removedView = this.splitview.removeView(index, sizing);
            removedView.dispose();
            const panels = this.panels;
            if (panels.length > 0) {
                this.setActive(panels[panels.length - 1]);
            }
        }
        getPanel(id) {
            return this.panels.find((view) => view.id === id);
        }
        addPanel(options) {
            var _a;
            if (this._panels.has(options.id)) {
                throw new Error(`panel ${options.id} already exists`);
            }
            const view = this.options.createComponent({
                id: options.id,
                name: options.component,
            });
            view.orientation = this.splitview.orientation;
            view.init({
                params: (_a = options.params) !== null && _a !== void 0 ? _a : {},
                minimumSize: options.minimumSize,
                maximumSize: options.maximumSize,
                snap: options.snap,
                priority: options.priority,
                accessor: this,
            });
            const size = typeof options.size === 'number' ? options.size : exports.Sizing.Distribute;
            const index = typeof options.index === 'number' ? options.index : undefined;
            this.splitview.addView(view, size, index);
            this.doAddView(view);
            this.setActive(view);
            return view;
        }
        layout(width, height) {
            const [size, orthogonalSize] = this.splitview.orientation === exports.Orientation.HORIZONTAL
                ? [width, height]
                : [height, width];
            this.splitview.layout(size, orthogonalSize);
        }
        doAddView(view) {
            const disposable = view.api.onDidFocusChange((event) => {
                if (!event.isFocused) {
                    return;
                }
                this.setActive(view, true);
            });
            this._panels.set(view.id, disposable);
        }
        toJSON() {
            var _a;
            const views = this.splitview
                .getViews()
                .map((view, i) => {
                const size = this.splitview.getViewSize(i);
                return {
                    size,
                    data: view.toJSON(),
                    snap: !!view.snap,
                    priority: view.priority,
                };
            });
            return {
                views,
                activeView: (_a = this._activePanel) === null || _a === void 0 ? void 0 : _a.id,
                size: this.splitview.size,
                orientation: this.splitview.orientation,
            };
        }
        fromJSON(serializedSplitview) {
            this.clear();
            const { views, orientation, size, activeView } = serializedSplitview;
            const queue = [];
            // take note of the existing dimensions
            const width = this.width;
            const height = this.height;
            this.splitview = new Splitview(this.element, {
                orientation,
                proportionalLayout: this.options.proportionalLayout,
                descriptor: {
                    size,
                    views: views.map((view) => {
                        const data = view.data;
                        if (this._panels.has(data.id)) {
                            throw new Error(`panel ${data.id} already exists`);
                        }
                        const panel = this.options.createComponent({
                            id: data.id,
                            name: data.component,
                        });
                        queue.push(() => {
                            var _a;
                            panel.init({
                                params: (_a = data.params) !== null && _a !== void 0 ? _a : {},
                                minimumSize: data.minimumSize,
                                maximumSize: data.maximumSize,
                                snap: view.snap,
                                priority: view.priority,
                                accessor: this,
                            });
                        });
                        panel.orientation = orientation;
                        this.doAddView(panel);
                        setTimeout(() => {
                            // the original onDidAddView events are missed since they are fired before we can subcribe to them
                            this._onDidAddView.fire(panel);
                        }, 0);
                        return { size: view.size, view: panel };
                    }),
                },
            });
            this.layout(width, height);
            queue.forEach((f) => f());
            if (typeof activeView === 'string') {
                const panel = this.getPanel(activeView);
                if (panel) {
                    this.setActive(panel);
                }
            }
            this._onDidLayoutfromJSON.fire();
        }
        clear() {
            for (const disposable of this._panels.values()) {
                disposable.dispose();
            }
            this._panels.clear();
            while (this.splitview.length > 0) {
                const view = this.splitview.removeView(0, exports.Sizing.Distribute, true);
                view.dispose();
            }
        }
        dispose() {
            for (const disposable of this._panels.values()) {
                disposable.dispose();
            }
            this._panels.clear();
            const views = this.splitview.getViews();
            this._splitviewChangeDisposable.dispose();
            this.splitview.dispose();
            for (const view of views) {
                view.dispose();
            }
            this.element.remove();
            super.dispose();
        }
    }

    class DefaultHeader extends CompositeDisposable {
        get element() {
            return this._element;
        }
        constructor() {
            super();
            this._expandedIcon = createExpandMoreButton();
            this._collapsedIcon = createChevronRightButton();
            this.disposable = new MutableDisposable();
            this.apiRef = {
                api: null,
            };
            this._element = document.createElement('div');
            this.element.className = 'dv-default-header';
            this._content = document.createElement('span');
            this._expander = document.createElement('div');
            this._expander.className = 'dv-pane-header-icon';
            this.element.appendChild(this._expander);
            this.element.appendChild(this._content);
            this.addDisposables(addDisposableListener(this._element, 'click', () => {
                var _a;
                (_a = this.apiRef.api) === null || _a === void 0 ? void 0 : _a.setExpanded(!this.apiRef.api.isExpanded);
            }));
        }
        init(params) {
            this.apiRef.api = params.api;
            this._content.textContent = params.title;
            this.updateIcon();
            this.disposable.value = params.api.onDidExpansionChange(() => {
                this.updateIcon();
            });
        }
        updateIcon() {
            var _a;
            const isExpanded = !!((_a = this.apiRef.api) === null || _a === void 0 ? void 0 : _a.isExpanded);
            toggleClass(this._expander, 'collapsed', !isExpanded);
            if (isExpanded) {
                if (this._expander.contains(this._collapsedIcon)) {
                    this._collapsedIcon.remove();
                }
                if (!this._expander.contains(this._expandedIcon)) {
                    this._expander.appendChild(this._expandedIcon);
                }
            }
            else {
                if (this._expander.contains(this._expandedIcon)) {
                    this._expandedIcon.remove();
                }
                if (!this._expander.contains(this._collapsedIcon)) {
                    this._expander.appendChild(this._collapsedIcon);
                }
            }
        }
        update(_params) {
            //
        }
        dispose() {
            this.disposable.dispose();
            super.dispose();
        }
    }

    const nextLayoutId = sequentialNumberGenerator();
    const HEADER_SIZE = 22;
    const MINIMUM_BODY_SIZE = 0;
    const MAXIMUM_BODY_SIZE = Number.MAX_SAFE_INTEGER;
    class PaneFramework extends DraggablePaneviewPanel {
        constructor(options) {
            super({
                accessor: options.accessor,
                id: options.id,
                component: options.component,
                headerComponent: options.headerComponent,
                orientation: options.orientation,
                isExpanded: options.isExpanded,
                disableDnd: options.disableDnd,
                headerSize: options.headerSize,
                minimumBodySize: options.minimumBodySize,
                maximumBodySize: options.maximumBodySize,
            });
            this.options = options;
        }
        getBodyComponent() {
            return this.options.body;
        }
        getHeaderComponent() {
            return this.options.header;
        }
    }
    class PaneviewComponent extends Resizable {
        get id() {
            return this._id;
        }
        get panels() {
            return this.paneview.getPanes();
        }
        set paneview(value) {
            this._paneview = value;
            this._disposable.value = new CompositeDisposable(this._paneview.onDidChange(() => {
                this._onDidLayoutChange.fire(undefined);
            }), this._paneview.onDidAddView((e) => this._onDidAddView.fire(e)), this._paneview.onDidRemoveView((e) => this._onDidRemoveView.fire(e)));
        }
        get paneview() {
            return this._paneview;
        }
        get minimumSize() {
            return this.paneview.minimumSize;
        }
        get maximumSize() {
            return this.paneview.maximumSize;
        }
        get height() {
            return this.paneview.orientation === exports.Orientation.HORIZONTAL
                ? this.paneview.orthogonalSize
                : this.paneview.size;
        }
        get width() {
            return this.paneview.orientation === exports.Orientation.HORIZONTAL
                ? this.paneview.size
                : this.paneview.orthogonalSize;
        }
        get options() {
            return this._options;
        }
        constructor(container, options) {
            var _a;
            super(document.createElement('div'), options.disableAutoResizing);
            this._id = nextLayoutId.next();
            this._disposable = new MutableDisposable();
            this._viewDisposables = new Map();
            this._onDidLayoutfromJSON = new Emitter();
            this.onDidLayoutFromJSON = this._onDidLayoutfromJSON.event;
            this._onDidLayoutChange = new Emitter();
            this.onDidLayoutChange = this._onDidLayoutChange.event;
            this._onDidDrop = new Emitter();
            this.onDidDrop = this._onDidDrop.event;
            this._onDidAddView = new Emitter();
            this.onDidAddView = this._onDidAddView.event;
            this._onDidRemoveView = new Emitter();
            this.onDidRemoveView = this._onDidRemoveView.event;
            this._onUnhandledDragOverEvent = new Emitter();
            this.onUnhandledDragOverEvent = this._onUnhandledDragOverEvent.event;
            this.element.style.height = '100%';
            this.element.style.width = '100%';
            this.addDisposables(this._onDidLayoutChange, this._onDidLayoutfromJSON, this._onDidDrop, this._onDidAddView, this._onDidRemoveView, this._onUnhandledDragOverEvent);
            this._classNames = new Classnames(this.element);
            this._classNames.setClassNames((_a = options.className) !== null && _a !== void 0 ? _a : '');
            // the container is owned by the third-party, do not modify/delete it
            container.appendChild(this.element);
            this._options = options;
            this.paneview = new Paneview(this.element, {
                // only allow paneview in the vertical orientation for now
                orientation: exports.Orientation.VERTICAL,
            });
            this.addDisposables(this._disposable);
        }
        setVisible(panel, visible) {
            const index = this.panels.indexOf(panel);
            this.paneview.setViewVisible(index, visible);
        }
        focus() {
            //noop
        }
        updateOptions(options) {
            var _a, _b;
            if ('className' in options) {
                this._classNames.setClassNames((_a = options.className) !== null && _a !== void 0 ? _a : '');
            }
            if ('disableResizing' in options) {
                this.disableResizing = (_b = options.disableAutoResizing) !== null && _b !== void 0 ? _b : false;
            }
            this._options = Object.assign(Object.assign({}, this.options), options);
        }
        addPanel(options) {
            var _a, _b;
            const body = this.options.createComponent({
                id: options.id,
                name: options.component,
            });
            let header;
            if (options.headerComponent && this.options.createHeaderComponent) {
                header = this.options.createHeaderComponent({
                    id: options.id,
                    name: options.headerComponent,
                });
            }
            if (!header) {
                header = new DefaultHeader();
            }
            const view = new PaneFramework({
                id: options.id,
                component: options.component,
                headerComponent: options.headerComponent,
                header,
                body,
                orientation: exports.Orientation.VERTICAL,
                isExpanded: !!options.isExpanded,
                disableDnd: !!this.options.disableDnd,
                accessor: this,
                headerSize: (_a = options.headerSize) !== null && _a !== void 0 ? _a : HEADER_SIZE,
                minimumBodySize: MINIMUM_BODY_SIZE,
                maximumBodySize: MAXIMUM_BODY_SIZE,
            });
            this.doAddPanel(view);
            const size = typeof options.size === 'number' ? options.size : exports.Sizing.Distribute;
            const index = typeof options.index === 'number' ? options.index : undefined;
            view.init({
                params: (_b = options.params) !== null && _b !== void 0 ? _b : {},
                minimumBodySize: options.minimumBodySize,
                maximumBodySize: options.maximumBodySize,
                isExpanded: options.isExpanded,
                title: options.title,
                containerApi: new PaneviewApi(this),
                accessor: this,
            });
            this.paneview.addPane(view, size, index);
            view.orientation = this.paneview.orientation;
            return view;
        }
        removePanel(panel) {
            const views = this.panels;
            const index = views.findIndex((_) => _ === panel);
            this.paneview.removePane(index);
            this.doRemovePanel(panel);
        }
        movePanel(from, to) {
            this.paneview.moveView(from, to);
        }
        getPanel(id) {
            return this.panels.find((view) => view.id === id);
        }
        layout(width, height) {
            const [size, orthogonalSize] = this.paneview.orientation === exports.Orientation.HORIZONTAL
                ? [width, height]
                : [height, width];
            this.paneview.layout(size, orthogonalSize);
        }
        toJSON() {
            const maximum = (value) => value === Number.MAX_SAFE_INTEGER ||
                value === Number.POSITIVE_INFINITY
                ? undefined
                : value;
            const minimum = (value) => (value <= 0 ? undefined : value);
            const views = this.paneview
                .getPanes()
                .map((view, i) => {
                const size = this.paneview.getViewSize(i);
                return {
                    size,
                    data: view.toJSON(),
                    minimumSize: minimum(view.minimumBodySize),
                    maximumSize: maximum(view.maximumBodySize),
                    headerSize: view.headerSize,
                    expanded: view.isExpanded(),
                };
            });
            return {
                views,
                size: this.paneview.size,
            };
        }
        fromJSON(serializedPaneview) {
            this.clear();
            const { views, size } = serializedPaneview;
            const queue = [];
            // take note of the existing dimensions
            const width = this.width;
            const height = this.height;
            this.paneview = new Paneview(this.element, {
                orientation: exports.Orientation.VERTICAL,
                descriptor: {
                    size,
                    views: views.map((view) => {
                        var _a, _b, _c;
                        const data = view.data;
                        const body = this.options.createComponent({
                            id: data.id,
                            name: data.component,
                        });
                        let header;
                        if (data.headerComponent &&
                            this.options.createHeaderComponent) {
                            header = this.options.createHeaderComponent({
                                id: data.id,
                                name: data.headerComponent,
                            });
                        }
                        if (!header) {
                            header = new DefaultHeader();
                        }
                        const panel = new PaneFramework({
                            id: data.id,
                            component: data.component,
                            headerComponent: data.headerComponent,
                            header,
                            body,
                            orientation: exports.Orientation.VERTICAL,
                            isExpanded: !!view.expanded,
                            disableDnd: !!this.options.disableDnd,
                            accessor: this,
                            headerSize: (_a = view.headerSize) !== null && _a !== void 0 ? _a : HEADER_SIZE,
                            minimumBodySize: (_b = view.minimumSize) !== null && _b !== void 0 ? _b : MINIMUM_BODY_SIZE,
                            maximumBodySize: (_c = view.maximumSize) !== null && _c !== void 0 ? _c : MAXIMUM_BODY_SIZE,
                        });
                        this.doAddPanel(panel);
                        queue.push(() => {
                            var _a;
                            panel.init({
                                params: (_a = data.params) !== null && _a !== void 0 ? _a : {},
                                minimumBodySize: view.minimumSize,
                                maximumBodySize: view.maximumSize,
                                title: data.title,
                                isExpanded: !!view.expanded,
                                containerApi: new PaneviewApi(this),
                                accessor: this,
                            });
                            panel.orientation = this.paneview.orientation;
                        });
                        setTimeout(() => {
                            // the original onDidAddView events are missed since they are fired before we can subcribe to them
                            this._onDidAddView.fire(panel);
                        }, 0);
                        return { size: view.size, view: panel };
                    }),
                },
            });
            this.layout(width, height);
            queue.forEach((f) => f());
            this._onDidLayoutfromJSON.fire();
        }
        clear() {
            for (const [_, value] of this._viewDisposables.entries()) {
                value.dispose();
            }
            this._viewDisposables.clear();
            this.paneview.dispose();
        }
        doAddPanel(panel) {
            const disposable = new CompositeDisposable(panel.onDidDrop((event) => {
                this._onDidDrop.fire(event);
            }), panel.onUnhandledDragOverEvent((event) => {
                this._onUnhandledDragOverEvent.fire(event);
            }));
            this._viewDisposables.set(panel.id, disposable);
        }
        doRemovePanel(panel) {
            const disposable = this._viewDisposables.get(panel.id);
            if (disposable) {
                disposable.dispose();
                this._viewDisposables.delete(panel.id);
            }
        }
        dispose() {
            super.dispose();
            for (const [_, value] of this._viewDisposables.entries()) {
                value.dispose();
            }
            this._viewDisposables.clear();
            this.element.remove();
            this.paneview.dispose();
        }
    }

    class SplitviewPanel extends BasePanelView {
        get priority() {
            return this._priority;
        }
        set orientation(value) {
            this._orientation = value;
        }
        get orientation() {
            return this._orientation;
        }
        get minimumSize() {
            const size = typeof this._minimumSize === 'function'
                ? this._minimumSize()
                : this._minimumSize;
            if (size !== this._evaluatedMinimumSize) {
                this._evaluatedMinimumSize = size;
                this.updateConstraints();
            }
            return size;
        }
        get maximumSize() {
            const size = typeof this._maximumSize === 'function'
                ? this._maximumSize()
                : this._maximumSize;
            if (size !== this._evaluatedMaximumSize) {
                this._evaluatedMaximumSize = size;
                this.updateConstraints();
            }
            return size;
        }
        get snap() {
            return this._snap;
        }
        constructor(id, componentName) {
            super(id, componentName, new SplitviewPanelApiImpl(id, componentName));
            this._evaluatedMinimumSize = 0;
            this._evaluatedMaximumSize = Number.POSITIVE_INFINITY;
            this._minimumSize = 0;
            this._maximumSize = Number.POSITIVE_INFINITY;
            this._snap = false;
            this._onDidChange = new Emitter();
            this.onDidChange = this._onDidChange.event;
            this.api.initialize(this);
            this.addDisposables(this._onDidChange, this.api.onWillVisibilityChange((event) => {
                const { isVisible } = event;
                const { accessor } = this._params;
                accessor.setVisible(this, isVisible);
            }), this.api.onActiveChange(() => {
                const { accessor } = this._params;
                accessor.setActive(this);
            }), this.api.onDidConstraintsChangeInternal((event) => {
                if (typeof event.minimumSize === 'number' ||
                    typeof event.minimumSize === 'function') {
                    this._minimumSize = event.minimumSize;
                }
                if (typeof event.maximumSize === 'number' ||
                    typeof event.maximumSize === 'function') {
                    this._maximumSize = event.maximumSize;
                }
                this.updateConstraints();
            }), this.api.onDidSizeChange((event) => {
                this._onDidChange.fire({ size: event.size });
            }));
        }
        setVisible(isVisible) {
            this.api._onDidVisibilityChange.fire({ isVisible });
        }
        setActive(isActive) {
            this.api._onDidActiveChange.fire({ isActive });
        }
        layout(size, orthogonalSize) {
            const [width, height] = this.orientation === exports.Orientation.HORIZONTAL
                ? [size, orthogonalSize]
                : [orthogonalSize, size];
            super.layout(width, height);
        }
        init(parameters) {
            super.init(parameters);
            this._priority = parameters.priority;
            if (parameters.minimumSize) {
                this._minimumSize = parameters.minimumSize;
            }
            if (parameters.maximumSize) {
                this._maximumSize = parameters.maximumSize;
            }
            if (parameters.snap) {
                this._snap = parameters.snap;
            }
        }
        toJSON() {
            const maximum = (value) => value === Number.MAX_SAFE_INTEGER ||
                value === Number.POSITIVE_INFINITY
                ? undefined
                : value;
            const minimum = (value) => (value <= 0 ? undefined : value);
            return Object.assign(Object.assign({}, super.toJSON()), { minimumSize: minimum(this.minimumSize), maximumSize: maximum(this.maximumSize) });
        }
        updateConstraints() {
            this.api._onDidConstraintsChange.fire({
                maximumSize: this._evaluatedMaximumSize,
                minimumSize: this._evaluatedMinimumSize,
            });
        }
    }

    function createDockview(element, options) {
        const component = new DockviewComponent(element, options);
        return component.api;
    }
    function createSplitview(element, options) {
        const component = new SplitviewComponent(element, options);
        return new SplitviewApi(component);
    }
    function createGridview(element, options) {
        const component = new GridviewComponent(element, options);
        return new GridviewApi(component);
    }
    function createPaneview(element, options) {
        const component = new PaneviewComponent(element, options);
        return new PaneviewApi(component);
    }

    /**
     * This component is intended to interface between vanilla-js and React hence we need to be
     * creative in how we update props.
     * A ref of the component is exposed with an update method; which when called stores the props
     * as a ref within this component and forcefully triggers a re-render of the component using
     * the ref of props we just set on the renderered component as the props passed to the inner
     * component
     */
    const ReactComponentBridge = (props, ref) => {
        const [_, triggerRender] = React.useState();
        const _props = React.useRef(props.componentProps);
        React.useImperativeHandle(ref, () => ({
            update: (componentProps) => {
                _props.current = Object.assign(Object.assign({}, _props.current), componentProps);
                /**
                 * setting a arbitrary piece of state within this component will
                 * trigger a re-render.
                 * we use this rather than updating through a prop since we can
                 * pass a ref into the vanilla-js world.
                 */
                triggerRender(Date.now());
            },
        }), []);
        return React.createElement(props.component, _props.current);
    };
    ReactComponentBridge.displayName = 'DockviewReactJsBridge';
    /**
     * Since we are storing the React.Portal references in a rendered array they
     * require a key property like any other React element rendered in an array
     * to prevent excessive re-rendering
     */
    const uniquePortalKeyGenerator = (() => {
        let value = 1;
        return { next: () => `dockview_react_portal_key_${(value++).toString()}` };
    })();
    const ReactPartContext = React.createContext({});
    class ReactPart {
        constructor(parent, portalStore, component, parameters, context) {
            this.parent = parent;
            this.portalStore = portalStore;
            this.component = component;
            this.parameters = parameters;
            this.context = context;
            this._initialProps = {};
            this.disposed = false;
            this.createPortal();
        }
        update(props) {
            if (this.disposed) {
                throw new Error('invalid operation: resource is already disposed');
            }
            if (!this.componentInstance) {
                // if the component is yet to be mounted store the props
                this._initialProps = Object.assign(Object.assign({}, this._initialProps), props);
            }
            else {
                this.componentInstance.update(props);
            }
        }
        createPortal() {
            if (this.disposed) {
                throw new Error('invalid operation: resource is already disposed');
            }
            if (!isReactComponent(this.component)) {
                /**
                 * we know this isn't a React.FunctionComponent so throw an error here.
                 * if we do not intercept then React library will throw a very obsure error
                 * for the same reason... at least at this point we will emit a sensible stacktrace.
                 */
                throw new Error('Dockview: Only React.memo(...), React.ForwardRef(...) and functional components are accepted as components');
            }
            const bridgeComponent = React.createElement(React.forwardRef(ReactComponentBridge), {
                component: this
                    .component,
                componentProps: this.parameters,
                ref: (element) => {
                    this.componentInstance = element;
                    if (Object.keys(this._initialProps).length > 0) {
                        this.componentInstance.update(this._initialProps);
                        this._initialProps = {}; // don't keep a reference to the users object once no longer required
                    }
                },
            });
            const node = this.context
                ? React.createElement(ReactPartContext.Provider, { value: this.context }, bridgeComponent)
                : bridgeComponent;
            const portal = ReactDOM.createPortal(node, this.parent, uniquePortalKeyGenerator.next());
            this.ref = {
                portal,
                disposable: this.portalStore.addPortal(portal),
            };
        }
        dispose() {
            var _a;
            (_a = this.ref) === null || _a === void 0 ? void 0 : _a.disposable.dispose();
            this.disposed = true;
        }
    }
    /**
     * A React Hook that returns an array of portals to be rendered by the user of this hook
     * and a disposable function to add a portal. Calling dispose removes this portal from the
     * portal array
     */
    const usePortalsLifecycle = () => {
        const [portals, setPortals] = React.useState([]);
        React.useDebugValue(`Portal count: ${portals.length}`);
        const addPortal = React.useCallback((portal) => {
            setPortals((existingPortals) => [...existingPortals, portal]);
            let disposed = false;
            return exports.DockviewDisposable.from(() => {
                if (disposed) {
                    throw new Error('invalid operation: resource already disposed');
                }
                disposed = true;
                setPortals((existingPortals) => existingPortals.filter((p) => p !== portal));
            });
        }, []);
        return [portals, addPortal];
    };
    function isReactComponent(component) {
        /**
         * Yes, we could use "react-is" but that would introduce an unwanted peer dependency
         * so for now we will check in a rather crude fashion...
         */
        return (typeof component === 'function' /** Functional Componnts */ ||
            !!(component === null || component === void 0 ? void 0 : component.$$typeof) /** React.memo(...) Components */);
    }

    class ReactPanelContentPart {
        get element() {
            return this._element;
        }
        constructor(id, component, reactPortalStore) {
            this.id = id;
            this.component = component;
            this.reactPortalStore = reactPortalStore;
            this._onDidFocus = new Emitter();
            this.onDidFocus = this._onDidFocus.event;
            this._onDidBlur = new Emitter();
            this.onDidBlur = this._onDidBlur.event;
            this._element = document.createElement('div');
            this._element.className = 'dv-react-part';
            this._element.style.height = '100%';
            this._element.style.width = '100%';
        }
        focus() {
            // TODO
        }
        init(parameters) {
            this.part = new ReactPart(this.element, this.reactPortalStore, this.component, {
                params: parameters.params,
                api: parameters.api,
                containerApi: parameters.containerApi,
            });
        }
        update(event) {
            var _a;
            (_a = this.part) === null || _a === void 0 ? void 0 : _a.update({ params: event.params });
        }
        layout(_width, _height) {
            // noop
        }
        dispose() {
            var _a;
            this._onDidFocus.dispose();
            this._onDidBlur.dispose();
            (_a = this.part) === null || _a === void 0 ? void 0 : _a.dispose();
        }
    }

    class ReactPanelHeaderPart {
        get element() {
            return this._element;
        }
        constructor(id, component, reactPortalStore) {
            this.id = id;
            this.component = component;
            this.reactPortalStore = reactPortalStore;
            this._element = document.createElement('div');
            this._element.className = 'dv-react-part';
            this._element.style.height = '100%';
            this._element.style.width = '100%';
        }
        focus() {
            //noop
        }
        init(parameters) {
            this.part = new ReactPart(this.element, this.reactPortalStore, this.component, {
                params: parameters.params,
                api: parameters.api,
                containerApi: parameters.containerApi,
                tabLocation: parameters.tabLocation,
            });
        }
        update(event) {
            var _a;
            (_a = this.part) === null || _a === void 0 ? void 0 : _a.update({ params: event.params });
        }
        layout(_width, _height) {
            // noop - retrieval from api
        }
        dispose() {
            var _a;
            (_a = this.part) === null || _a === void 0 ? void 0 : _a.dispose();
        }
    }

    class ReactWatermarkPart {
        get element() {
            return this._element;
        }
        constructor(id, component, reactPortalStore) {
            this.id = id;
            this.component = component;
            this.reactPortalStore = reactPortalStore;
            this._element = document.createElement('div');
            this._element.className = 'dv-react-part';
            this._element.style.height = '100%';
            this._element.style.width = '100%';
        }
        init(parameters) {
            this.part = new ReactPart(this.element, this.reactPortalStore, this.component, {
                group: parameters.group,
                containerApi: parameters.containerApi,
            });
        }
        focus() {
            // noop
        }
        update(params) {
            var _a, _b, _c;
            if (this.parameters) {
                this.parameters.params = params.params;
            }
            (_a = this.part) === null || _a === void 0 ? void 0 : _a.update({ params: (_c = (_b = this.parameters) === null || _b === void 0 ? void 0 : _b.params) !== null && _c !== void 0 ? _c : {} });
        }
        layout(_width, _height) {
            // noop - retrieval from api
        }
        dispose() {
            var _a;
            (_a = this.part) === null || _a === void 0 ? void 0 : _a.dispose();
        }
    }

    class ReactHeaderActionsRendererPart {
        get element() {
            return this._element;
        }
        get part() {
            return this._part;
        }
        constructor(component, reactPortalStore, _group) {
            this.component = component;
            this.reactPortalStore = reactPortalStore;
            this._group = _group;
            this.mutableDisposable = new MutableDisposable();
            this._element = document.createElement('div');
            this._element.className = 'dv-react-part';
            this._element.style.height = '100%';
            this._element.style.width = '100%';
        }
        init(parameters) {
            this.mutableDisposable.value = new CompositeDisposable(this._group.model.onDidAddPanel(() => {
                this.updatePanels();
            }), this._group.model.onDidRemovePanel(() => {
                this.updatePanels();
            }), this._group.model.onDidActivePanelChange(() => {
                this.updateActivePanel();
            }), parameters.api.onDidActiveChange(() => {
                this.updateGroupActive();
            }));
            this._part = new ReactPart(this.element, this.reactPortalStore, this.component, {
                api: parameters.api,
                containerApi: parameters.containerApi,
                panels: this._group.model.panels,
                activePanel: this._group.model.activePanel,
                isGroupActive: this._group.api.isActive,
                group: this._group,
            });
        }
        dispose() {
            var _a;
            this.mutableDisposable.dispose();
            (_a = this._part) === null || _a === void 0 ? void 0 : _a.dispose();
        }
        update(event) {
            var _a;
            (_a = this._part) === null || _a === void 0 ? void 0 : _a.update(event.params);
        }
        updatePanels() {
            this.update({ params: { panels: this._group.model.panels } });
        }
        updateActivePanel() {
            this.update({
                params: {
                    activePanel: this._group.model.activePanel,
                },
            });
        }
        updateGroupActive() {
            this.update({
                params: {
                    isGroupActive: this._group.api.isActive,
                },
            });
        }
    }

    function createGroupControlElement(component, store) {
        return component
            ? (groupPanel) => {
                return new ReactHeaderActionsRendererPart(component, store, groupPanel);
            }
            : undefined;
    }
    const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
    function extractCoreOptions$3(props) {
        const coreOptions = PROPERTY_KEYS_DOCKVIEW.reduce((obj, key) => {
            if (key in props) {
                obj[key] = props[key];
            }
            return obj;
        }, {});
        return coreOptions;
    }
    const DockviewReact = React.forwardRef((props, ref) => {
        const domRef = React.useRef(null);
        const dockviewRef = React.useRef();
        const [portals, addPortal] = usePortalsLifecycle();
        React.useImperativeHandle(ref, () => domRef.current, []);
        const prevProps = React.useRef({});
        React.useEffect(() => {
            const changes = {};
            PROPERTY_KEYS_DOCKVIEW.forEach((propKey) => {
                const key = propKey;
                const propValue = props[key];
                if (key in props && propValue !== prevProps.current[key]) {
                    changes[key] = propValue;
                }
            });
            if (dockviewRef.current) {
                dockviewRef.current.updateOptions(changes);
            }
            prevProps.current = props;
        }, PROPERTY_KEYS_DOCKVIEW.map((key) => props[key]));
        React.useEffect(() => {
            var _a;
            if (!domRef.current) {
                return;
            }
            const frameworkTabComponents = (_a = props.tabComponents) !== null && _a !== void 0 ? _a : {};
            if (props.defaultTabComponent) {
                frameworkTabComponents[DEFAULT_REACT_TAB] =
                    props.defaultTabComponent;
            }
            const frameworkOptions = {
                createLeftHeaderActionComponent: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
                createRightHeaderActionComponent: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
                createPrefixHeaderActionComponent: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
                createComponent: (options) => {
                    return new ReactPanelContentPart(options.id, props.components[options.name], {
                        addPortal,
                    });
                },
                createTabComponent(options) {
                    return new ReactPanelHeaderPart(options.id, frameworkTabComponents[options.name], {
                        addPortal,
                    });
                },
                createWatermarkComponent: props.watermarkComponent
                    ? () => {
                        return new ReactWatermarkPart('watermark', props.watermarkComponent, {
                            addPortal,
                        });
                    }
                    : undefined,
                defaultTabComponent: props.defaultTabComponent
                    ? DEFAULT_REACT_TAB
                    : undefined,
            };
            const api = createDockview(domRef.current, Object.assign(Object.assign({}, extractCoreOptions$3(props)), frameworkOptions));
            const { clientWidth, clientHeight } = domRef.current;
            api.layout(clientWidth, clientHeight);
            if (props.onReady) {
                props.onReady({ api });
            }
            dockviewRef.current = api;
            return () => {
                api.dispose();
            };
        }, []);
        React.useEffect(() => {
            if (!dockviewRef.current) {
                return () => {
                    // noop
                };
            }
            const disposable = dockviewRef.current.onDidDrop((event) => {
                if (props.onDidDrop) {
                    props.onDidDrop(event);
                }
            });
            return () => {
                disposable.dispose();
            };
        }, [props.onDidDrop]);
        React.useEffect(() => {
            if (!dockviewRef.current) {
                return () => {
                    // noop
                };
            }
            const disposable = dockviewRef.current.onWillDrop((event) => {
                if (props.onWillDrop) {
                    props.onWillDrop(event);
                }
            });
            return () => {
                disposable.dispose();
            };
        }, [props.onWillDrop]);
        React.useEffect(() => {
            if (!dockviewRef.current) {
                return;
            }
            dockviewRef.current.updateOptions({
                createComponent: (options) => {
                    return new ReactPanelContentPart(options.id, props.components[options.name], {
                        addPortal,
                    });
                },
            });
        }, [props.components]);
        React.useEffect(() => {
            var _a;
            if (!dockviewRef.current) {
                return;
            }
            const frameworkTabComponents = (_a = props.tabComponents) !== null && _a !== void 0 ? _a : {};
            if (props.defaultTabComponent) {
                frameworkTabComponents[DEFAULT_REACT_TAB] =
                    props.defaultTabComponent;
            }
            dockviewRef.current.updateOptions({
                defaultTabComponent: props.defaultTabComponent
                    ? DEFAULT_REACT_TAB
                    : undefined,
                createTabComponent(options) {
                    return new ReactPanelHeaderPart(options.id, frameworkTabComponents[options.name], {
                        addPortal,
                    });
                },
            });
        }, [props.tabComponents, props.defaultTabComponent]);
        React.useEffect(() => {
            if (!dockviewRef.current) {
                return;
            }
            dockviewRef.current.updateOptions({
                createWatermarkComponent: props.watermarkComponent
                    ? () => {
                        return new ReactWatermarkPart('watermark', props.watermarkComponent, {
                            addPortal,
                        });
                    }
                    : undefined,
            });
        }, [props.watermarkComponent]);
        React.useEffect(() => {
            if (!dockviewRef.current) {
                return;
            }
            dockviewRef.current.updateOptions({
                createRightHeaderActionComponent: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
            });
        }, [props.rightHeaderActionsComponent]);
        React.useEffect(() => {
            if (!dockviewRef.current) {
                return;
            }
            dockviewRef.current.updateOptions({
                createLeftHeaderActionComponent: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
            });
        }, [props.leftHeaderActionsComponent]);
        React.useEffect(() => {
            if (!dockviewRef.current) {
                return;
            }
            dockviewRef.current.updateOptions({
                createPrefixHeaderActionComponent: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
            });
        }, [props.prefixHeaderActionsComponent]);
        return (React.createElement("div", { style: { height: '100%', width: '100%' }, ref: domRef }, portals));
    });
    DockviewReact.displayName = 'DockviewComponent';

    const CloseButton = () => (React.createElement("svg", { height: "11", width: "11", viewBox: "0 0 28 28", "aria-hidden": 'false', focusable: false, className: "dv-svg" },
        React.createElement("path", { d: "M2.1 27.3L0 25.2L11.55 13.65L0 2.1L2.1 0L13.65 11.55L25.2 0L27.3 2.1L15.75 13.65L27.3 25.2L25.2 27.3L13.65 15.75L2.1 27.3Z" })));

    var __rest = (undefined && undefined.__rest) || function (s, e) {
        var t = {};
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
            t[p] = s[p];
        if (s != null && typeof Object.getOwnPropertySymbols === "function")
            for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
                if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                    t[p[i]] = s[p[i]];
            }
        return t;
    };
    function useTitle(api) {
        const [title, setTitle] = React.useState(api.title);
        React.useEffect(() => {
            const disposable = api.onDidTitleChange((event) => {
                setTitle(event.title);
            });
            return () => {
                disposable.dispose();
            };
        }, [api]);
        return title;
    }
    const DockviewDefaultTab = (_a) => {
        var { api, containerApi: _containerApi, params: _params, hideClose, closeActionOverride, onPointerDown, onPointerUp, onPointerLeave, tabLocation } = _a, rest = __rest(_a, ["api", "containerApi", "params", "hideClose", "closeActionOverride", "onPointerDown", "onPointerUp", "onPointerLeave", "tabLocation"]);
        const title = useTitle(api);
        const isMiddleMouseButton = React.useRef(false);
        const onClose = React.useCallback((event) => {
            event.preventDefault();
            if (closeActionOverride) {
                closeActionOverride();
            }
            else {
                api.close();
            }
        }, [api, closeActionOverride]);
        const onBtnPointerDown = React.useCallback((event) => {
            event.preventDefault();
        }, []);
        const _onPointerDown = React.useCallback((event) => {
            isMiddleMouseButton.current = event.button === 1;
            onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
        }, [onPointerDown]);
        const _onPointerUp = React.useCallback((event) => {
            if (isMiddleMouseButton && event.button === 1 && !hideClose) {
                isMiddleMouseButton.current = false;
                onClose(event);
            }
            onPointerUp === null || onPointerUp === void 0 ? void 0 : onPointerUp(event);
        }, [onPointerUp, onClose, hideClose]);
        const _onPointerLeave = React.useCallback((event) => {
            isMiddleMouseButton.current = false;
            onPointerLeave === null || onPointerLeave === void 0 ? void 0 : onPointerLeave(event);
        }, [onPointerLeave]);
        return (React.createElement("div", Object.assign({ "data-testid": "dockview-dv-default-tab" }, rest, { onPointerDown: _onPointerDown, onPointerUp: _onPointerUp, onPointerLeave: _onPointerLeave, className: "dv-default-tab" }),
            React.createElement("span", { className: "dv-default-tab-content" }, title),
            !hideClose && tabLocation !== 'headerOverflow' && (React.createElement("div", { className: "dv-default-tab-action", onPointerDown: onBtnPointerDown, onClick: onClose },
                React.createElement(CloseButton, null)))));
    };

    class ReactPanelView extends SplitviewPanel {
        constructor(id, component, reactComponent, reactPortalStore) {
            super(id, component);
            this.reactComponent = reactComponent;
            this.reactPortalStore = reactPortalStore;
        }
        getComponent() {
            var _a, _b;
            return new ReactPart(this.element, this.reactPortalStore, this.reactComponent, {
                params: (_b = (_a = this._params) === null || _a === void 0 ? void 0 : _a.params) !== null && _b !== void 0 ? _b : {},
                api: this.api,
                containerApi: new SplitviewApi(this._params.accessor),
            });
        }
    }

    function extractCoreOptions$2(props) {
        const coreOptions = PROPERTY_KEYS_SPLITVIEW.reduce((obj, key) => {
            if (key in props) {
                obj[key] = props[key];
            }
            return obj;
        }, {});
        return coreOptions;
    }
    const SplitviewReact = React.forwardRef((props, ref) => {
        const domRef = React.useRef(null);
        const splitviewRef = React.useRef();
        const [portals, addPortal] = usePortalsLifecycle();
        React.useImperativeHandle(ref, () => domRef.current, []);
        const prevProps = React.useRef({});
        React.useEffect(() => {
            const changes = {};
            PROPERTY_KEYS_SPLITVIEW.forEach((propKey) => {
                const key = propKey;
                const propValue = props[key];
                if (key in props && propValue !== prevProps.current[key]) {
                    changes[key] = propValue;
                }
            });
            if (splitviewRef.current) {
                splitviewRef.current.updateOptions(changes);
            }
            prevProps.current = props;
        }, PROPERTY_KEYS_SPLITVIEW.map((key) => props[key]));
        React.useEffect(() => {
            if (!domRef.current) {
                return () => {
                    // noop
                };
            }
            const frameworkOptions = {
                createComponent: (options) => {
                    return new ReactPanelView(options.id, options.name, props.components[options.name], { addPortal });
                },
            };
            const api = createSplitview(domRef.current, Object.assign(Object.assign({}, extractCoreOptions$2(props)), frameworkOptions));
            const { clientWidth, clientHeight } = domRef.current;
            api.layout(clientWidth, clientHeight);
            if (props.onReady) {
                props.onReady({ api });
            }
            splitviewRef.current = api;
            return () => {
                api.dispose();
            };
        }, []);
        React.useEffect(() => {
            if (!splitviewRef.current) {
                return;
            }
            splitviewRef.current.updateOptions({
                createComponent: (options) => {
                    return new ReactPanelView(options.id, options.name, props.components[options.name], { addPortal });
                },
            });
        }, [props.components]);
        return (React.createElement("div", { style: { height: '100%', width: '100%' }, ref: domRef }, portals));
    });
    SplitviewReact.displayName = 'SplitviewComponent';

    class ReactGridPanelView extends GridviewPanel {
        constructor(id, component, reactComponent, reactPortalStore) {
            super(id, component);
            this.reactComponent = reactComponent;
            this.reactPortalStore = reactPortalStore;
        }
        getComponent() {
            var _a, _b;
            return new ReactPart(this.element, this.reactPortalStore, this.reactComponent, {
                params: (_b = (_a = this._params) === null || _a === void 0 ? void 0 : _a.params) !== null && _b !== void 0 ? _b : {},
                api: this.api,
                // TODO: fix casting hack
                containerApi: new GridviewApi(this._params
                    .accessor),
            });
        }
    }

    function extractCoreOptions$1(props) {
        const coreOptions = PROPERTY_KEYS_GRIDVIEW.reduce((obj, key) => {
            if (key in props) {
                obj[key] = props[key];
            }
            return obj;
        }, {});
        return coreOptions;
    }
    const GridviewReact = React.forwardRef((props, ref) => {
        const domRef = React.useRef(null);
        const gridviewRef = React.useRef();
        const [portals, addPortal] = usePortalsLifecycle();
        React.useImperativeHandle(ref, () => domRef.current, []);
        const prevProps = React.useRef({});
        React.useEffect(() => {
            const changes = {};
            PROPERTY_KEYS_GRIDVIEW.forEach((propKey) => {
                const key = propKey;
                const propValue = props[key];
                if (key in props && propValue !== prevProps.current[key]) {
                    changes[key] = propValue;
                }
            });
            if (gridviewRef.current) {
                gridviewRef.current.updateOptions(changes);
            }
            prevProps.current = props;
        }, PROPERTY_KEYS_GRIDVIEW.map((key) => props[key]));
        React.useEffect(() => {
            if (!domRef.current) {
                return () => {
                    // noop
                };
            }
            const frameworkOptions = {
                createComponent: (options) => {
                    return new ReactGridPanelView(options.id, options.name, props.components[options.name], { addPortal });
                },
            };
            const api = createGridview(domRef.current, Object.assign(Object.assign({}, extractCoreOptions$1(props)), frameworkOptions));
            const { clientWidth, clientHeight } = domRef.current;
            api.layout(clientWidth, clientHeight);
            if (props.onReady) {
                props.onReady({ api });
            }
            gridviewRef.current = api;
            return () => {
                api.dispose();
            };
        }, []);
        React.useEffect(() => {
            if (!gridviewRef.current) {
                return;
            }
            gridviewRef.current.updateOptions({
                createComponent: (options) => {
                    return new ReactGridPanelView(options.id, options.name, props.components[options.name], { addPortal });
                },
            });
        }, [props.components]);
        return (React.createElement("div", { style: { height: '100%', width: '100%' }, ref: domRef }, portals));
    });
    GridviewReact.displayName = 'GridviewComponent';

    class PanePanelSection {
        get element() {
            return this._element;
        }
        constructor(id, component, reactPortalStore) {
            this.id = id;
            this.component = component;
            this.reactPortalStore = reactPortalStore;
            this._element = document.createElement('div');
            this._element.style.height = '100%';
            this._element.style.width = '100%';
        }
        init(parameters) {
            this.part = new ReactPart(this.element, this.reactPortalStore, this.component, {
                params: parameters.params,
                api: parameters.api,
                title: parameters.title,
                containerApi: parameters.containerApi,
            });
        }
        toJSON() {
            return {
                id: this.id,
            };
        }
        update(params) {
            var _a;
            (_a = this.part) === null || _a === void 0 ? void 0 : _a.update(params.params);
        }
        dispose() {
            var _a;
            (_a = this.part) === null || _a === void 0 ? void 0 : _a.dispose();
        }
    }

    function extractCoreOptions(props) {
        const coreOptions = PROPERTY_KEYS_PANEVIEW.reduce((obj, key) => {
            if (key in props) {
                obj[key] = props[key];
            }
            return obj;
        }, {});
        return coreOptions;
    }
    const PaneviewReact = React.forwardRef((props, ref) => {
        const domRef = React.useRef(null);
        const paneviewRef = React.useRef();
        const [portals, addPortal] = usePortalsLifecycle();
        React.useImperativeHandle(ref, () => domRef.current, []);
        const prevProps = React.useRef({});
        React.useEffect(() => {
            const changes = {};
            PROPERTY_KEYS_PANEVIEW.forEach((propKey) => {
                const key = propKey;
                const propValue = props[key];
                if (key in props && propValue !== prevProps.current[key]) {
                    changes[key] = propValue;
                }
            });
            if (paneviewRef.current) {
                paneviewRef.current.updateOptions(changes);
            }
            prevProps.current = props;
        }, PROPERTY_KEYS_PANEVIEW.map((key) => props[key]));
        React.useEffect(() => {
            var _a;
            if (!domRef.current) {
                return () => {
                    // noop
                };
            }
            const headerComponents = (_a = props.headerComponents) !== null && _a !== void 0 ? _a : {};
            const frameworkOptions = {
                createComponent: (options) => {
                    return new PanePanelSection(options.id, props.components[options.name], { addPortal });
                },
                createHeaderComponent: (options) => {
                    return new PanePanelSection(options.id, headerComponents[options.name], { addPortal });
                },
            };
            const api = createPaneview(domRef.current, Object.assign(Object.assign({}, extractCoreOptions(props)), frameworkOptions));
            const { clientWidth, clientHeight } = domRef.current;
            api.layout(clientWidth, clientHeight);
            if (props.onReady) {
                props.onReady({ api });
            }
            paneviewRef.current = api;
            return () => {
                api.dispose();
            };
        }, []);
        React.useEffect(() => {
            if (!paneviewRef.current) {
                return;
            }
            paneviewRef.current.updateOptions({
                createComponent: (options) => {
                    return new PanePanelSection(options.id, props.components[options.name], { addPortal });
                },
            });
        }, [props.components]);
        React.useEffect(() => {
            var _a;
            if (!paneviewRef.current) {
                return;
            }
            const headerComponents = (_a = props.headerComponents) !== null && _a !== void 0 ? _a : {};
            paneviewRef.current.updateOptions({
                createHeaderComponent: (options) => {
                    return new PanePanelSection(options.id, headerComponents[options.name], { addPortal });
                },
            });
        }, [props.headerComponents]);
        React.useEffect(() => {
            if (!paneviewRef.current) {
                return () => {
                    // noop
                };
            }
            const disposable = paneviewRef.current.onDidDrop((event) => {
                if (props.onDidDrop) {
                    props.onDidDrop(event);
                }
            });
            return () => {
                disposable.dispose();
            };
        }, [props.onDidDrop]);
        return (React.createElement("div", { style: { height: '100%', width: '100%' }, ref: domRef }, portals));
    });
    PaneviewReact.displayName = 'PaneviewComponent';

    exports.BaseGrid = BaseGrid;
    exports.ContentContainer = ContentContainer;
    exports.DefaultDockviewDeserialzier = DefaultDockviewDeserialzier;
    exports.DefaultTab = DefaultTab;
    exports.DockviewApi = DockviewApi;
    exports.DockviewComponent = DockviewComponent;
    exports.DockviewCompositeDisposable = CompositeDisposable;
    exports.DockviewDefaultTab = DockviewDefaultTab;
    exports.DockviewDidDropEvent = DockviewDidDropEvent;
    exports.DockviewEmitter = Emitter;
    exports.DockviewGroupPanel = DockviewGroupPanel;
    exports.DockviewGroupPanelModel = DockviewGroupPanelModel;
    exports.DockviewMutableDisposable = MutableDisposable;
    exports.DockviewPanel = DockviewPanel;
    exports.DockviewReact = DockviewReact;
    exports.DockviewUnhandledDragOverEvent = DockviewUnhandledDragOverEvent;
    exports.DockviewWillDropEvent = DockviewWillDropEvent;
    exports.DraggablePaneviewPanel = DraggablePaneviewPanel;
    exports.Gridview = Gridview;
    exports.GridviewApi = GridviewApi;
    exports.GridviewComponent = GridviewComponent;
    exports.GridviewPanel = GridviewPanel;
    exports.GridviewReact = GridviewReact;
    exports.PROPERTY_KEYS_DOCKVIEW = PROPERTY_KEYS_DOCKVIEW;
    exports.PROPERTY_KEYS_GRIDVIEW = PROPERTY_KEYS_GRIDVIEW;
    exports.PROPERTY_KEYS_PANEVIEW = PROPERTY_KEYS_PANEVIEW;
    exports.PROPERTY_KEYS_SPLITVIEW = PROPERTY_KEYS_SPLITVIEW;
    exports.PaneFramework = PaneFramework;
    exports.PaneTransfer = PaneTransfer;
    exports.PanelTransfer = PanelTransfer;
    exports.Paneview = Paneview;
    exports.PaneviewApi = PaneviewApi;
    exports.PaneviewComponent = PaneviewComponent;
    exports.PaneviewPanel = PaneviewPanel;
    exports.PaneviewReact = PaneviewReact;
    exports.PaneviewUnhandledDragOverEvent = PaneviewUnhandledDragOverEvent;
    exports.ReactPart = ReactPart;
    exports.ReactPartContext = ReactPartContext;
    exports.Splitview = Splitview;
    exports.SplitviewApi = SplitviewApi;
    exports.SplitviewComponent = SplitviewComponent;
    exports.SplitviewPanel = SplitviewPanel;
    exports.SplitviewReact = SplitviewReact;
    exports.Tab = Tab;
    exports.WillShowOverlayLocationEvent = WillShowOverlayLocationEvent;
    exports.createDockview = createDockview;
    exports.createGridview = createGridview;
    exports.createPaneview = createPaneview;
    exports.createSplitview = createSplitview;
    exports.directionToPosition = directionToPosition;
    exports.getDirectionOrientation = getDirectionOrientation;
    exports.getGridLocation = getGridLocation;
    exports.getLocationOrientation = getLocationOrientation;
    exports.getPaneData = getPaneData;
    exports.getPanelData = getPanelData;
    exports.getRelativeLocation = getRelativeLocation;
    exports.indexInParent = indexInParent;
    exports.isGridBranchNode = isGridBranchNode;
    exports.isGroupOptionsWithGroup = isGroupOptionsWithGroup;
    exports.isGroupOptionsWithPanel = isGroupOptionsWithPanel;
    exports.isPanelOptionsWithGroup = isPanelOptionsWithGroup;
    exports.isPanelOptionsWithPanel = isPanelOptionsWithPanel;
    exports.isReactComponent = isReactComponent;
    exports.orthogonal = orthogonal;
    exports.positionToDirection = positionToDirection;
    exports.themeAbyss = themeAbyss;
    exports.themeAbyssSpaced = themeAbyssSpaced;
    exports.themeDark = themeDark;
    exports.themeDracula = themeDracula;
    exports.themeLight = themeLight;
    exports.themeLightSpaced = themeLightSpaced;
    exports.themeReplit = themeReplit;
    exports.themeVisualStudio = themeVisualStudio;
    exports.toTarget = toTarget;
    exports.usePortalsLifecycle = usePortalsLifecycle;

}));
//# sourceMappingURL=dockview-react.amd.noStyle.js.map