import { __esDecorate, __runInitializers } from "tslib";
import { html, LitElement, nothing } from 'lit';
import { eventOptions, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { SplitDirection, SplitRegion } from './type.js';
let SplitView = (() => {
    let _classSuper = LitElement;
    let _instanceExtraInitializers = [];
    let _layout_decorators;
    let _layout_initializers = [];
    let _layout_extraInitializers = [];
    let _key_decorators;
    let _key_initializers = [];
    let _key_extraInitializers = [];
    let _dragTypes_decorators;
    let _dragTypes_initializers = [];
    let _dragTypes_extraInitializers = [];
    let _inDrag_decorators;
    let _inDrag_initializers = [];
    let _inDrag_extraInitializers = [];
    let _dragRegion_decorators;
    let _dragRegion_initializers = [];
    let _dragRegion_extraInitializers = [];
    let _panel_decorators;
    let _panel_initializers = [];
    let _panel_extraInitializers = [];
    let _constrain_decorators;
    let _constrain_initializers = [];
    let _constrain_extraInitializers = [];
    let _handleTabTouchStart_decorators;
    return class SplitView extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _layout_decorators = [property({ type: String, reflect: true })];
            _key_decorators = [property({ type: Number, reflect: true })];
            _dragTypes_decorators = [property({ type: Array })];
            _inDrag_decorators = [state()];
            _dragRegion_decorators = [state()];
            _panel_decorators = [property({ type: Object })];
            _constrain_decorators = [property({ type: Boolean, reflect: true })];
            _handleTabTouchStart_decorators = [eventOptions({ passive: true })];
            __esDecorate(this, null, _layout_decorators, { kind: "accessor", name: "layout", static: false, private: false, access: { has: obj => "layout" in obj, get: obj => obj.layout, set: (obj, value) => { obj.layout = value; } }, metadata: _metadata }, _layout_initializers, _layout_extraInitializers);
            __esDecorate(this, null, _key_decorators, { kind: "accessor", name: "key", static: false, private: false, access: { has: obj => "key" in obj, get: obj => obj.key, set: (obj, value) => { obj.key = value; } }, metadata: _metadata }, _key_initializers, _key_extraInitializers);
            __esDecorate(this, null, _dragTypes_decorators, { kind: "accessor", name: "dragTypes", static: false, private: false, access: { has: obj => "dragTypes" in obj, get: obj => obj.dragTypes, set: (obj, value) => { obj.dragTypes = value; } }, metadata: _metadata }, _dragTypes_initializers, _dragTypes_extraInitializers);
            __esDecorate(this, null, _inDrag_decorators, { kind: "accessor", name: "inDrag", static: false, private: false, access: { has: obj => "inDrag" in obj, get: obj => obj.inDrag, set: (obj, value) => { obj.inDrag = value; } }, metadata: _metadata }, _inDrag_initializers, _inDrag_extraInitializers);
            __esDecorate(this, null, _dragRegion_decorators, { kind: "accessor", name: "dragRegion", static: false, private: false, access: { has: obj => "dragRegion" in obj, get: obj => obj.dragRegion, set: (obj, value) => { obj.dragRegion = value; } }, metadata: _metadata }, _dragRegion_initializers, _dragRegion_extraInitializers);
            __esDecorate(this, null, _panel_decorators, { kind: "accessor", name: "panel", static: false, private: false, access: { has: obj => "panel" in obj, get: obj => obj.panel, set: (obj, value) => { obj.panel = value; } }, metadata: _metadata }, _panel_initializers, _panel_extraInitializers);
            __esDecorate(this, null, _constrain_decorators, { kind: "accessor", name: "constrain", static: false, private: false, access: { has: obj => "constrain" in obj, get: obj => obj.constrain, set: (obj, value) => { obj.constrain = value; } }, metadata: _metadata }, _constrain_initializers, _constrain_extraInitializers);
            __esDecorate(this, null, _handleTabTouchStart_decorators, { kind: "method", name: "handleTabTouchStart", static: false, private: false, access: { has: obj => "handleTabTouchStart" in obj, get: obj => obj.handleTabTouchStart }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #layout_accessor_storage = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _layout_initializers, SplitDirection.horizontal
        /**
         * @attribute
         */
        ));
        /**
         * @attribute
         */
        get layout() { return this.#layout_accessor_storage; }
        set layout(value) { this.#layout_accessor_storage = value; }
        #key_accessor_storage = (__runInitializers(this, _layout_extraInitializers), __runInitializers(this, _key_initializers, void 0));
        /**
         * @attribute
         */
        get key() { return this.#key_accessor_storage; }
        set key(value) { this.#key_accessor_storage = value; }
        #dragTypes_accessor_storage = (__runInitializers(this, _key_extraInitializers), __runInitializers(this, _dragTypes_initializers, void 0));
        get dragTypes() { return this.#dragTypes_accessor_storage; }
        set dragTypes(value) { this.#dragTypes_accessor_storage = value; }
        #inDrag_accessor_storage = (__runInitializers(this, _dragTypes_extraInitializers), __runInitializers(this, _inDrag_initializers, false
        /**
         * The region the drag is leaning to.
         */
        ));
        /**
         * Whether dragging is occurring over the element
         */
        get inDrag() { return this.#inDrag_accessor_storage; }
        set inDrag(value) { this.#inDrag_accessor_storage = value; }
        #dragRegion_accessor_storage = (__runInitializers(this, _inDrag_extraInitializers), __runInitializers(this, _dragRegion_initializers, SplitRegion.center
        /**
         * A reference to the split panel that owns this view.
         */
        ));
        /**
         * The region the drag is leaning to.
         */
        get dragRegion() { return this.#dragRegion_accessor_storage; }
        set dragRegion(value) { this.#dragRegion_accessor_storage = value; }
        #panel_accessor_storage = (__runInitializers(this, _dragRegion_extraInitializers), __runInitializers(this, _panel_initializers, void 0));
        /**
         * A reference to the split panel that owns this view.
         */
        get panel() { return this.#panel_accessor_storage; }
        set panel(value) { this.#panel_accessor_storage = value; }
        #constrain_accessor_storage = (__runInitializers(this, _panel_extraInitializers), __runInitializers(this, _constrain_initializers, false));
        /**
         * When set it adds the `overflow` hidden on the container that holds the tab contents.
         * @attribute
         */
        get constrain() { return this.#constrain_accessor_storage; }
        set constrain(value) { this.#constrain_accessor_storage = value; }
        constructor() {
            super();
            __runInitializers(this, _constrain_extraInitializers);
            this.handleDragleave = this.handleDragleave.bind(this);
            this.handleDragEnd = this.handleDragEnd.bind(this);
            this.addEventListener('dragenter', this.handleDragEnter.bind(this));
            this.addEventListener('dragover', this.handleDragOver.bind(this));
            this.addEventListener('drop', this.handleDrop.bind(this));
        }
        connectedCallback() {
            super.connectedCallback();
            document.body.addEventListener('dragleave', this.handleDragleave);
            document.body.addEventListener('dragend', this.handleDragEnd);
        }
        disconnectedCallback() {
            super.disconnectedCallback();
            document.body.removeEventListener('dragleave', this.handleDragleave);
            document.body.removeEventListener('dragend', this.handleDragEnd);
        }
        handleDragEnter(e) {
            const { dataTransfer } = e;
            if (!dataTransfer || !this.panelCanDrop(e)) {
                return;
            }
            e.preventDefault();
            e.stopPropagation();
            dataTransfer.dropEffect = 'copy';
        }
        handleDragOver(e) {
            const { dataTransfer } = e;
            if (!dataTransfer || !this.panelCanDrop(e)) {
                return;
            }
            e.preventDefault();
            e.stopPropagation();
            const region = this.getDropRegionFromEvent(e);
            if (!region) {
                this.inDrag = false;
                return;
            }
            dataTransfer.dropEffect = 'copy';
            this.inDrag = true;
            this.dragRegion = region;
        }
        handleDrop(e) {
            const { dataTransfer } = e;
            const { panel } = this;
            if (!dataTransfer || !panel || !this.panelCanDrop(e)) {
                return;
            }
            e.preventDefault();
            e.stopPropagation();
            const kind = dataTransfer.getData('text/kind');
            const key = dataTransfer.getData('text/key');
            if (!kind || !key) {
                return;
            }
            const layoutKey = dataTransfer.getData('layout/key');
            this.inDrag = false;
            // TODO: When the drag originated in another panel then we
            // move the panel between them. Otherwise we add the item to the panel.
            if (layoutKey) {
                // move operation not add.
                panel.manager.moveItem(layoutKey, panel.key, key, { region: this.dragRegion });
            }
            else {
                panel.addItem({ key, kind, label: 'New tab' }, { region: this.dragRegion });
                panel.manager.requestNameUpdate(key);
            }
            this.dispatchEvent(new CustomEvent('datadrop', {
                detail: { kind, key, region: this.dragRegion },
                composed: true,
                bubbles: true,
                cancelable: true,
            }));
            this.requestUpdate();
        }
        handleDragleave(e) {
            const elm = this.findLayout(e);
            if (!elm || elm !== this) {
                this.inDrag = false;
                this.dragRegion = SplitRegion.center;
            }
        }
        handleDragEnd() {
            this.inDrag = false;
            this.dragRegion = SplitRegion.center;
        }
        getDropRegionFromEvent(e) {
            const layout = this.findLayout(e);
            if (!layout) {
                return undefined;
            }
            return this.getDropRegion(layout, e);
        }
        getDropRegion(element, e) {
            const { pageX, pageY } = e;
            const rect = element.getBoundingClientRect();
            const quarterWidth = rect.width / 4;
            const quarterHeight = rect.height / 4;
            if (pageX < rect.left + quarterWidth) {
                return SplitRegion.west;
            }
            if (pageX > rect.right - quarterWidth) {
                return SplitRegion.east;
            }
            if (pageY < rect.top + quarterHeight) {
                return SplitRegion.north;
            }
            if (pageY > rect.bottom - quarterHeight) {
                return SplitRegion.south;
            }
            const withingCenterX = pageX >= rect.left + quarterWidth && pageX <= rect.right - quarterWidth;
            const withingCenterY = pageY >= rect.top + quarterHeight && pageY <= rect.bottom - quarterHeight;
            if (withingCenterX && withingCenterY) {
                return SplitRegion.center;
            }
            return undefined;
        }
        findLayout(e) {
            const path = e.composedPath();
            while (path.length) {
                const node = path.shift();
                if (node.nodeType !== Node.ELEMENT_NODE) {
                    continue;
                }
                if (node.localName === this.localName) {
                    return node;
                }
            }
            return undefined;
        }
        hasDropTypes(dt) {
            const { dragTypes } = this;
            if (!Array.isArray(dragTypes)) {
                return true;
            }
            const eventTypes = [...dt.types];
            const allowedTypes = dragTypes.map((i) => i.toLowerCase());
            return !allowedTypes.some((type) => !eventTypes.includes(type));
        }
        panelCanDrop(e) {
            if (e.defaultPrevented) {
                return false;
            }
            if (e.dataTransfer && !this.hasDropTypes(e.dataTransfer)) {
                return false;
            }
            const { panel } = this;
            if (!panel) {
                return true;
            }
            return panel.canDrop();
        }
        handleTabDragStart(e) {
            const dt = e.dataTransfer;
            if (!dt || this.key === undefined) {
                return;
            }
            dt.effectAllowed = 'copyMove';
            dt.dropEffect = 'move';
            const node = e.target;
            dt.setData('text/kind', node.dataset.kind);
            dt.setData('text/key', node.dataset.key);
            dt.setData('text/source', this.localName);
            dt.setData('layout/key', this.key);
        }
        handleTabsDragEnter(e) {
            const dt = e.dataTransfer;
            if (!dt || !this.panelCanDrop(e)) {
                return;
            }
            e.stopPropagation();
            e.preventDefault();
            dt.effectAllowed = 'move';
            dt.dropEffect = 'move';
        }
        handleTabsDragover(e) {
            const dt = e.dataTransfer;
            if (!dt || !this.panelCanDrop(e)) {
                return;
            }
            e.stopPropagation();
            e.preventDefault();
            dt.effectAllowed = 'move';
            dt.dropEffect = 'move';
        }
        handleTabDrop(e) {
            const dt = e.dataTransfer;
            if (!dt || !this.panelCanDrop(e) || this.key === undefined) {
                return;
            }
            e.stopPropagation();
            e.preventDefault();
            const src = dt.getData('text/source');
            const key = dt.getData('text/key');
            const kind = dt.getData('text/kind');
            const srcPanelKey = dt.getData('layout/key');
            const movingTab = src === this.localName;
            const overTab = this.findTab(e);
            const toIndex = overTab ? Number(overTab.dataset.index) : undefined;
            if (movingTab) {
                if (!srcPanelKey) {
                    return;
                }
                this.moveTab(srcPanelKey, this.key, key, toIndex);
            }
            else {
                let dispatch = true;
                if (this.panel) {
                    this.panel.addItem({ key, kind, label: 'New tab' }, { index: toIndex });
                    dispatch = true;
                }
                if (dispatch) {
                    this.dispatchEvent(new CustomEvent('datadrop', {
                        detail: { kind, key, index: toIndex },
                        composed: true,
                        bubbles: true,
                        cancelable: true,
                    }));
                }
                this.requestUpdate();
            }
        }
        moveTab(fromLayout, toLayout, key, toIndex) {
            const { panel } = this;
            if (panel) {
                panel.manager.moveItem(fromLayout, toLayout, key, { index: toIndex });
            }
        }
        findTab(e) {
            const path = e.composedPath();
            while (path.length) {
                const node = path.shift();
                if (node.nodeType !== Node.ELEMENT_NODE) {
                    continue;
                }
                if (node.classList.contains('layout-tab')) {
                    return node;
                }
            }
            return undefined;
        }
        async handleTabClick(e) {
            if (!this.panel) {
                return;
            }
            const key = e.currentTarget.dataset.key;
            if (!key) {
                return;
            }
            if (this.panel.selected === key) {
                return;
            }
            this.panel.selected = key;
            this.panel.manager.notifyChange();
            this.requestUpdate();
            await this.updateComplete;
            const child = this.querySelector(`[data-key="${key}"]`);
            if (child) {
                child.dispatchEvent(new Event('resize'));
            }
        }
        /**
         * Closes a panel with right pointer configuration
         */
        handleTabPointerDown(e) {
            // the configuration of a middle button click which is
            // equal to 3 fingers click on a track pad.
            if (e.button === 1 && e.buttons === 4) {
                e.preventDefault();
                e.stopPropagation();
                const key = e.target.dataset.key;
                this.closeTab(key);
            }
        }
        handleTabClose(e) {
            const icon = e.target;
            const button = icon.parentElement;
            const key = button.dataset.key;
            if (key) {
                e.preventDefault();
                e.stopPropagation();
                this.closeTab(key);
            }
        }
        handleTabTouchStart(e) {
            if (e.targetTouches.length === 3) {
                e.preventDefault();
                e.stopPropagation();
                const key = e.target.dataset.key;
                this.closeTab(key);
            }
        }
        closeTab(key) {
            const { panel } = this;
            if (!panel) {
                return;
            }
            const item = panel.manager.findItem(key);
            if (!item) {
                return;
            }
            if (item.persistent && item.pinned) {
                return;
            }
            panel.removeItem(key);
            this.requestUpdate();
            this.dispatchEvent(new CustomEvent('closetab', {
                bubbles: true,
                cancelable: true,
                composed: true,
                detail: key,
            }));
        }
        handleTabKeyDown(e) {
            if (e.key === 'Enter') {
                this.handleTabClick(e);
            }
        }
        render() {
            return html `
      ${this.dragRegionTemplate()} ${this.tabsTemplate()}
      <div class="content">
        <slot></slot>
      </div>
    `;
        }
        dragRegionTemplate() {
            const { inDrag, dragRegion } = this;
            if (!inDrag) {
                return nothing;
            }
            return html ` <div class="drag-region ${dragRegion}"></div> `;
        }
        tabsTemplate() {
            const { panel } = this;
            if (!panel) {
                return '';
            }
            const items = panel.sortedItems();
            if (!items) {
                return '';
            }
            const size = items.length;
            return html `
      <div
        class="layout-tabs"
        role="tablist"
        @dragenter="${this.handleTabsDragEnter}"
        @dragover="${this.handleTabsDragover}"
        @drop="${this.handleTabDrop}"
      >
        ${items.map((tab, i) => this.tabTemplate(tab, i + 1 === size, items[i + 1]?.key))}
      </div>
    `;
        }
        tabTemplate(item, last, nextKey) {
            const { key, kind, label = '', index = 0, icon, isDirty = false, parent } = item;
            const { panel } = this;
            const selected = !!panel && panel.selected === key;
            const nextSelected = !!nextKey && !!panel && panel.selected === nextKey;
            const closable = !item.persistent && !item.pinned;
            const classes = {
                'layout-tab': true,
                'is-dirty': isDirty,
                selected,
                'surface1': selected,
            };
            let title = label;
            if (isDirty) {
                title = 'Unsaved changes';
            }
            const dividerHidden = last || selected || nextSelected;
            return html `
      <div
        data-key="${key}"
        data-kind="${kind}"
        data-index="${index}"
        data-parent="${ifDefined(parent)}"
        data-dirty="${isDirty}"
        data-panel="${ifDefined(panel?.key)}"
        role="tab"
        class="${classMap(classes)}"
        draggable="true"
        tabindex="0"
        @dragstart="${this.handleTabDragStart}"
        @click="${this.handleTabClick}"
        @pointerdown="${this.handleTabPointerDown}"
        @touchstart="${this.handleTabTouchStart}"
        @keydown="${this.handleTabKeyDown}"
      >
        ${icon ? html `<ui-icon icon="${icon}" class="tab-favicon"></ui-icon>` : ''}
        <span class="tab-label" title="${title}">${label}</span>
        ${closable ? html `<ui-icon icon="close" class="close-icon" @click="${this.handleTabClose}"></ui-icon>` : ''}
      </div>
      <div class="tab-divider ${dividerHidden ? 'hidden' : ''}"></div>
    `;
        }
    };
})();
export default SplitView;
//# sourceMappingURL=SplitView.js.map