/*!
 * Copyright (c) 2026 Vertex Software LLC. All rights reserved.
 */
import { r as registerInstance, c as createEvent, h, H as Host, a as getElement } from './index-EpnuuCxl.js';
import { c as classname } from './index-DI7z7TKn.js';
import { d as debounceEvent, r as readDOM } from './stencil-CEl7wGvE.js';
import { _ as __assign, p as point } from './bundle-DfdVaPrt.js';
import { a as getSceneTreeViewportHeight } from './dom-DX6pEG54.js';
import { i as isLoadedRow } from './row-CiSHWNC4.js';
import { E as EventDispatcher } from './bundle-DLfw87TV.js';
import './_commonjsHelpers-CG9AChtV.js';

const sceneTreeNotificationBannerCss = () => `.notification-banner{background-color:var(--blue-200);padding-top:0px;padding-bottom:0px;padding-right:16px;padding-left:8px;display:flex;justify-content:space-between;font-size:0.875rem;line-height:0.5;color:var(--neutral-600)}.notification-banner-info{display:flex;align-items:center;gap:8px}.notification-banner-info .icon{color:var(--blue-600)}.notification-banner-actions{display:flex;align-items:center}.notification-banner-button{background:none;border:none;padding:0;margin:0;cursor:pointer;color:var(--blue-600);font-size:0.875rem;display:flex;align-items:center}.notification-banner-button:hover{color:var(--blue-800)}`;

const SceneTreeNotificationBanner = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.action = createEvent(this, "action");
    }
    render() {
        return (h(Host, { key: 'faf3e2e84a60db63b158747e649f43900b1f0930' }, h("div", { key: '9180eb1f7472d5a5d0742117dee5b75734ac3232', class: "notification-banner" }, h("div", { key: '02171b4cc5f7e5ef924eb96e4ba0403f3fd59f4e', class: "notification-banner-info" }, h("vertex-viewer-icon", { key: 'caa522489ce767d52c07d7007802c8fb40457f6d', class: "icon", name: "info", size: "sm" }), h("p", { key: '0836efb7b9f56f926315ba232fe1b4d8fa52aefe' }, this.message)), this.actionLabel != null && (h("div", { key: 'c5ae434c28810c205ab5806a0689cbaa371c0933', class: "notification-banner-actions" }, h("button", { key: 'd3fcbe8eb211ac453701c7fd179becfc03f8b1c2', class: "notification-banner-button", onClick: () => this.action.emit() }, this.actionLabel))))));
    }
};
SceneTreeNotificationBanner.style = sceneTreeNotificationBannerCss();

const sceneTreeSearchCss = () => `button{border:none;background:transparent;cursor:pointer;margin:0;padding:0}:host{--scene-tree-search-search-icon-offset:8px;--scene-tree-search-clear-button-offset:8px;--scene-tree-search-input-padding:0.5rem 32px;--scene-tree-search-input-border:none;--scene-tree-search-input-border-radius:0.25rem;--scene-tree-search-input-background:none;--scene-tree-search-focused-input-background:var(--neutral-200);--scene-tree-search-focused-input-outline:none;display:block;width:100%;font-size:0.875rem}.root{width:100%;position:relative}.input{background:var(--scene-tree-search-input-background);border:var(--scene-tree-search-input-border);border-radius:var(--scene-tree-search-input-border-radius);box-sizing:border-box;font-size:inherit;padding:var(--scene-tree-search-input-padding);outline:none;width:100%}.input.background{background:var(--scene-tree-search-focused-input-background);outline:var(--scene-tree-search-focused-input-outline)}.overlay{position:absolute;top:0;bottom:0;display:flex;align-items:center;justify-content:center;pointer-events:none}.overlay-clear{display:none;right:var(--scene-tree-search-clear-button-offset)}.overlay-clear.show{display:flex}.icon{color:var(--neutral-700)}.icon-search{position:absolute;left:var(--scene-tree-search-search-icon-offset);pointer-events:none}.clear-btn{display:flex;align-items:center;justify-content:center;pointer-events:initial;cursor:pointer}.clear-btn:hover{color:var(--neutral-800)}.clear-btn:disabled{pointer-events:none;opacity:0.5}`;

const SceneTreeSearch = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.search = createEvent(this, "search");
        this.searchCompleted = createEvent(this, "searchCompleted");
        /**
         * If `true`, disables user interaction of the component.
         */
        this.disabled = false;
        /**
         * Placeholder text if `value` is empty.
         */
        this.placeholder = undefined;
        /**
         * The current text value of the component. Value is updated on user
         * interaction.
         */
        this.value = '';
        this.focused = false;
        this.isSearching = false;
        this.handleTextInput = (event) => {
            const input = event.target;
            this.value = input.value;
            if (this.debounce != null || this.value === '') {
                this.emitCurrentValue();
            }
        };
        this.handleTextFocus = () => {
            this.focused = true;
        };
        this.handleTextBlur = () => {
            var _a;
            this.focused = false;
            (_a = this.searchDisposable) === null || _a === void 0 ? void 0 : _a.dispose();
            if (this.value !== this.lastEmittedValue) {
                this.emitCurrentValue();
            }
        };
        this.handleKeyPress = (event) => {
            var _a;
            if (event.key === 'Enter') {
                (_a = this.searchDisposable) === null || _a === void 0 ? void 0 : _a.dispose();
                this.emitCurrentValue();
            }
        };
        this.handleClear = (event) => {
            var _a;
            event.preventDefault();
            this.value = '';
            (_a = this.searchDisposable) === null || _a === void 0 ? void 0 : _a.dispose();
            this.emitCurrentValue();
            this.setFocus();
        };
    }
    /**
     * Gives focus to the component's internal text input.
     */
    async setFocus() {
        var _a, _b;
        // HTMLInputElement.focus() doesn't exist in tests.
        if (typeof ((_a = this.inputEl) === null || _a === void 0 ? void 0 : _a.focus) === 'function') {
            (_b = this.inputEl) === null || _b === void 0 ? void 0 : _b.focus();
        }
    }
    /**
     * @ignore
     */
    controllerChanged(controller) {
        this.setupController();
    }
    /**
     * @ignore
     */
    componentDidLoad() {
        this.handleDebounceChanged();
        this.setupController();
    }
    /**
     * @ignore
     */
    disconnectedCallback() {
        var _a;
        (_a = this.onStateChangeDisposable) === null || _a === void 0 ? void 0 : _a.dispose();
    }
    /**
     * Clears the current search term and clears any debounced filters.
     */
    async clear() {
        var _a;
        this.value = '';
        (_a = this.searchDisposable) === null || _a === void 0 ? void 0 : _a.dispose();
        this.emitCurrentValue();
    }
    /**
     * @ignore
     */
    render() {
        return (h(Host, { key: 'a147f41b6d1bee253edfea73854697fd48ce713b' }, h("div", { key: '68fb61c2e5310d6f52c696e466661fe75b8119fd', class: "root" }, h("div", { key: 'a19f9bebb23dd3c89547d36dcb251ec8525f3aae', class: "overlay icon icon-search" }, h("slot", { key: '99a2c8c0d48b01e43b2b8717a73652845298442a', name: "search-icon" }, this.isSearching ? (h("vertex-viewer-spinner", { slot: "search-icon", size: "xs" })) : (h("vertex-viewer-icon", { name: "search", size: "sm" })))), h("input", { key: 'feb34cbc91c5813bee85a32c60bf28da1d6069b0', class: classname('input', {
                background: this.focused || this.value.length > 0,
            }), type: "text", ref: (ref) => (this.inputEl = ref), placeholder: this.placeholder, disabled: this.disabled, value: this.value, onInput: this.handleTextInput, onFocus: this.handleTextFocus, onBlur: this.handleTextBlur, onKeyPress: this.handleKeyPress }), h("div", { key: '0c06291d8c4e7b88e67b720951cd0c46ddd1daf6', class: classname('overlay overlay-clear', {
                show: this.value.length > 0,
            }) }, h("button", { key: 'c0a1394058c36939f167d84b42070939fad85f83', class: "clear-btn icon", tabIndex: -1, onMouseDown: this.handleClear, disabled: this.disabled }, h("slot", { key: 'afa2e6eb99ddcbb2d1e53138296264ae7620dc51', name: "clear-icon" }, h("vertex-viewer-icon", { key: 'faa225a4caa66374a69e88fb9bb5c48af7a2d4ed', name: "close-circle", size: "sm" })))))));
    }
    handleDebounceChanged() {
        var _a, _b;
        (_a = this.searchDisposable) === null || _a === void 0 ? void 0 : _a.dispose();
        const emitter = debounceEvent(this.search, (_b = this.debounce) !== null && _b !== void 0 ? _b : 0);
        // Track this emitter in two separate variables to maintain the `EventEmitter` typing for
        // `this.search`. This allows for correct generation of `CustomEvent` types.
        this.search = emitter;
        this.searchDisposable = emitter;
    }
    setupController() {
        var _a, _b;
        (_a = this.onStateChangeDisposable) === null || _a === void 0 ? void 0 : _a.dispose();
        this.onStateChangeDisposable = (_b = this.controller) === null || _b === void 0 ? void 0 : _b.onStateChange.on((state) => {
            // If a search was previously being performed, but has now finished,
            // emit the event that the search has completed.
            if (this.isSearching && !state.isSearching) {
                this.searchCompleted.emit(this.value);
            }
            this.isSearching = state.isSearching;
        });
    }
    emitCurrentValue() {
        this.lastEmittedValue = this.value;
        this.search.emit(this.value);
    }
    static get watchers() { return {
        "controller": [{
                "controllerChanged": 0
            }]
    }; }
};
SceneTreeSearch.style = sceneTreeSearchCss();

/**
 * Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
 */
/**
 * Lower case as a function.
 */
function lowerCase(str) {
    return str.toLowerCase();
}

// Support camel case ("camelCase" -> "camel Case" and "CAMELCase" -> "CAMEL Case").
var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
// Remove all non-word characters.
var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
/**
 * Normalize the string into something other libraries can manipulate easier.
 */
function noCase(input, options) {
    if (options === void 0) { options = {}; }
    var _a = options.splitRegexp, splitRegexp = _a === void 0 ? DEFAULT_SPLIT_REGEXP : _a, _b = options.stripRegexp, stripRegexp = _b === void 0 ? DEFAULT_STRIP_REGEXP : _b, _c = options.transform, transform = _c === void 0 ? lowerCase : _c, _d = options.delimiter, delimiter = _d === void 0 ? " " : _d;
    var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
    var start = 0;
    var end = result.length;
    // Trim the delimiter from around the output string.
    while (result.charAt(start) === "\0")
        start++;
    while (result.charAt(end - 1) === "\0")
        end--;
    // Transform each token independently.
    return result.slice(start, end).split("\0").map(transform).join(delimiter);
}
/**
 * Replace `re` in the input string with the replacement value.
 */
function replace(input, re, value) {
    if (re instanceof RegExp)
        return input.replace(re, value);
    return re.reduce(function (input, re) { return input.replace(re, value); }, input);
}

function pascalCaseTransform(input, index) {
    var firstChar = input.charAt(0);
    var lowerChars = input.substr(1).toLowerCase();
    if (index > 0 && firstChar >= "0" && firstChar <= "9") {
        return "_" + firstChar + lowerChars;
    }
    return "" + firstChar.toUpperCase() + lowerChars;
}
function pascalCase(input, options) {
    if (options === void 0) { options = {}; }
    return noCase(input, __assign({ delimiter: "", transform: pascalCaseTransform }, options));
}

function camelCaseTransform(input, index) {
    if (index === 0)
        return input.toLowerCase();
    return pascalCaseTransform(input, index);
}
function camelCase(input, options) {
    if (options === void 0) { options = {}; }
    return pascalCase(input, __assign({ transform: camelCaseTransform }, options));
}

const bindingRegEx = /{{(.+)}}/;
class CollectionBinding {
    constructor(bindings) {
        this.bindings = bindings;
    }
    bind(data) {
        this.bindings.forEach((binding) => binding.bind(data));
    }
}
class NodeBinding {
    constructor(node, expr) {
        this.node = node;
        this.expr = expr;
    }
}
class TextNodeBinding extends NodeBinding {
    constructor(node, expr) {
        super(node, expr);
    }
    bind(data) {
        const newContent = replaceBindingString(data, this.expr);
        if (newContent !== this.node.textContent) {
            this.node.textContent = newContent;
        }
    }
}
class AttributeBinding extends NodeBinding {
    constructor(node, expr, attr) {
        super(node, expr);
        this.attr = attr;
    }
    bind(data) {
        const newValue = replaceBindingString(data, this.expr);
        const oldValue = this.node.getAttribute(this.attr);
        if (oldValue !== newValue) {
            this.node.setAttribute(this.attr, newValue);
        }
    }
}
class PropertyBinding extends NodeBinding {
    constructor(node, expr, prop) {
        super(node, expr);
        this.prop = prop;
    }
    bind(data) {
        const newValue = replaceBinding(data, this.expr);
        /* eslint-disable @typescript-eslint/no-explicit-any */
        const oldValue = this.node[this.prop];
        if (oldValue !== newValue) {
            this.node[this.prop] = newValue;
        }
        /* eslint-enable @typescript-eslint/no-explicit-any */
    }
}
class EventHandlerBinding extends NodeBinding {
    constructor(node, expr, eventName) {
        super(node, expr);
        this.eventName = eventName;
    }
    bind(data) {
        var _a;
        const path = extractBindingPath(this.expr);
        if (path != null) {
            (_a = this.disposable) === null || _a === void 0 ? void 0 : _a.dispose();
            const listener = getBindableValue(data, path, true);
            this.node.addEventListener(this.eventName, listener);
            this.disposable = {
                dispose: () => {
                    this.node.removeEventListener(this.eventName, listener);
                },
            };
        }
    }
}
function generateBindings(node) {
    const bindings = [];
    if (node.nodeType === Node.ELEMENT_NODE) {
        const el = node;
        const bindableAttributes = getBindableAttributes(el);
        bindableAttributes.forEach((attr) => {
            if (attr.name.startsWith('event:')) {
                const eventName = camelCase(attr.name.replace('event:', ''));
                bindings.push(new EventHandlerBinding(el, attr.value, eventName));
            }
            else if (attr.name.startsWith('attr:')) {
                bindings.push(new AttributeBinding(el, attr.value, attr.name.replace('attr:', '')));
            }
            else if (attr.name.startsWith('prop:')) {
                const propName = camelCase(attr.name.replace('prop:', ''));
                bindings.push(new PropertyBinding(el, attr.value, propName));
            }
        });
    }
    else if (node.nodeType === Node.TEXT_NODE &&
        node.textContent != null &&
        bindingRegEx.test(node.textContent)) {
        bindings.push(new TextNodeBinding(node, node.textContent));
    }
    for (let i = 0; i < node.childNodes.length; i++) {
        bindings.push(...generateBindings(node.childNodes[i]));
    }
    return bindings;
}
function getBindableAttributes(element) {
    return Array.from(element.attributes).filter((attr) => bindingRegEx.test(attr.value));
}
function extractBindingPath(expr) {
    const result = bindingRegEx.exec(expr);
    return result != null ? result[1] : undefined;
}
function replaceBindingString(data, expr) {
    const path = extractBindingPath(expr);
    if (path != null) {
        const value = getBindableValue(data, path, true);
        return expr.replace(`{{${path}}}`, value === null || value === void 0 ? void 0 : value.toString());
    }
    else {
        return expr;
    }
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function replaceBinding(data, expr) {
    const path = extractBindingPath(expr);
    if (path != null) {
        const value = getBindableValue(data, path, true);
        return value;
    }
    else {
        return expr;
    }
}
function getBindableValue(data, path, isHead = false
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) {
    const [head, ...tail] = path.split('.');
    if (isHead && tail.length === 0) {
        return data;
    }
    else if (isHead && tail.length > 0) {
        return getBindableValue(data, tail.join('.'), false);
    }
    else {
        const value = data[head];
        if (tail.length > 0) {
            return getBindableValue(value, tail.join('.'), false);
        }
        else {
            return value;
        }
    }
}

class ElementPool {
    constructor(container, elementFactory) {
        this.container = container;
        this.elementFactory = elementFactory;
        this.instanceMap = new Map();
        this.elements = [];
    }
    swapHeadToTail(count) {
        const sliced = this.elements.splice(0, count);
        this.elements.splice(this.elements.length, 0, ...sliced);
        return this.elements.concat();
    }
    swapTailToHead(count) {
        const sliced = this.elements.splice(-count, count);
        this.elements.splice(0, 0, ...sliced);
        return this.elements.concat();
    }
    updateElements(count) {
        const diff = count - this.elements.length;
        if (diff > 0) {
            for (let i = 0; i < diff; i++) {
                this.createElement();
            }
        }
        else {
            for (let i = 0; i < -diff; i++) {
                this.deleteElement();
            }
        }
        return this.elements.concat();
    }
    updateData(f) {
        this.elements.forEach((el, i) => {
            const instance = this.instanceMap.get(el);
            const data = f(i);
            instance === null || instance === void 0 ? void 0 : instance.bindings.bind(data);
        });
    }
    updateElementFactory(elementFactory) {
        this.elementFactory = elementFactory;
        this.updateElements(0);
    }
    iterateElements(f) {
        this.elements.forEach((el, i) => {
            const instance = this.instanceMap.get(el);
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
            f(el, instance.bindings, i);
        });
    }
    createElement() {
        const instance = this.elementFactory();
        this.elements.push(instance.element);
        this.instanceMap.set(instance.element, instance);
        this.container.append(instance.element);
        return instance;
    }
    deleteElement() {
        const element = this.elements.pop();
        if (element != null) {
            this.instanceMap.delete(element);
            element.remove();
        }
    }
}
function generateInstanceFromTemplate(template) {
    const fragment = template.content.cloneNode(true);
    const element = fragment.firstElementChild;
    const bindings = new CollectionBinding(generateBindings(fragment));
    return { element, bindings };
}

function getSceneTreeTableOffsetTop(el) {
    var _a;
    return (_a = el.getBoundingClientRect().top) !== null && _a !== void 0 ? _a : 0;
}
function getSceneTreeTableViewportWidth(el) {
    return el.clientWidth;
}
function scrollToTop(el, top, options) {
    el.scrollTo({ top, ...options });
}

class SceneTreeCellHoverController {
    constructor() {
        this.onStateChange = new EventDispatcher();
    }
    setHovered(id) {
        this.onStateChange.emit(id);
    }
    stateChanged(listener) {
        return this.onStateChange.on(listener);
    }
}

function restartTimeout(fn, existingTimeout, delay = 200) {
    window.clearTimeout(existingTimeout);
    return window.setTimeout(fn, delay);
}

const sceneTreeTableLayoutCss = () => `:host{position:relative;display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden;font-size:0.825rem;--scene-tree-table-row-padding:2px 0px;--scene-tree-table-column-gap:0.5rem;--scene-tree-table-column-resize-cursor:col-resize}.header{position:relative;display:grid;width:100%;border-bottom:var(--scene-tree-toolbar-separator)}.table{position:relative;display:grid;width:100%;height:100%;overflow:auto}.resize-overlay{position:absolute;top:0;cursor:var(--scene-tree-table-column-resize-cursor);z-index:1000;width:100%;height:100%}.divider-overlay{position:absolute;top:0;display:grid;pointer-events:none;z-index:2000;width:100%;height:100%}`;

const SceneTreeTableLayout = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        this.layoutRendered = createEvent(this, "layoutRendered");
        this.columnsResized = createEvent(this, "columnsResized");
        /**
         * @internal
         */
        this.rows = [];
        /**
         * @internal
         */
        this.totalRows = 0;
        /**
         * @internal
         */
        this.rowHeight = 24;
        /**
         * The number of offscreen rows above and below the viewport to render. Having
         * a higher number reduces the chance of the browser not displaying a row
         * while scrolling.
         *
         * This prop will be automatically populated based on the `overScanCount` prop
         * specified in the parent `<vertex-scene-tree />` element.
         */
        this.overScanCount = 25;
        /**
         * @internal
         */
        this.layoutOffset = 0;
        /**
         * @internal
         */
        this.scrollOffset = 0;
        /**
         * @internal
         */
        this.viewportStartIndex = 0;
        /**
         * @internal
         */
        this.viewportEndIndex = 0;
        this.columnGridLayout = '1fr';
        this.columnGridFixedLayout = '';
        this.isComputingCellHeight = true;
        this.isScrolling = false;
        /**
         * This stores internal state that you want to preserve across live-reloads,
         * but shouldn't trigger a refresh if the data changes. Marking this with
         * @State to allow to preserve state across live-reloads.
         */
        this.stateMap = {
            viewportRows: [],
            columnWidths: [],
            columnWidthPercentages: [],
        };
        this.lastStartIndex = 0;
        this.columnElements = [];
        this.cellHoverController = new SceneTreeCellHoverController();
        this.layoutColumns = () => {
            const visibleRowCount = this.viewportEndIndex - this.viewportStartIndex + 1;
            const diff = this.viewportStartIndex - this.lastStartIndex;
            this.lastStartIndex = this.viewportStartIndex;
            this.iterateColumns((col, pool, colIndex) => {
                pool.updateElements(visibleRowCount);
                if (diff > 0) {
                    pool.swapHeadToTail(diff);
                }
                else {
                    pool.swapTailToHead(-diff);
                }
                col.style.minHeight = `${this.rowHeight * this.totalRows}px`;
                const cellPaddingLeft = colIndex === 0
                    ? (depth) => `calc(${depth} * 0.5rem)`
                    : () => `0`;
                pool.iterateElements((el, binding, rowIndex) => {
                    const row = this.stateMap.viewportRows[rowIndex];
                    if (isLoadedRow(row)) {
                        this.updateCell(row, el, binding, rowIndex, cellPaddingLeft);
                    }
                });
            });
        };
        this.updateCell = (row, cell, binding, rowIndex, cellPaddingLeft) => {
            cell.style.position = 'absolute';
            cell.style.top = `${(this.viewportStartIndex + rowIndex) * this.rowHeight}px`;
            cell.style.boxSizing = 'border-box';
            cell.style.height = `${this.rowHeight}px`;
            cell.style.width = '100%';
            cell.style.paddingLeft = cellPaddingLeft(row.node.depth);
            /* eslint-disable @typescript-eslint/no-explicit-any */
            cell.tree = this.tree;
            cell.node = row.node;
            cell.hoverController = this.cellHoverController;
            cell.isScrolling = this.isScrolling;
            /* eslint-enable @typescript-eslint/no-explicit-any */
            binding.bind(row);
        };
        this.updateLayoutPosition = () => {
            readDOM(() => {
                if (this.tableElement != null) {
                    this.layoutOffset = getSceneTreeTableOffsetTop(this.tableElement);
                }
            });
        };
        this.recomputeColumnWidths = () => {
            const layoutWidth = this.getLayoutWidth();
            if (layoutWidth != null &&
                this.stateMap.columnWidths.length ===
                    this.stateMap.columnWidthPercentages.length) {
                this.stateMap.columnWidths = this.stateMap.columnWidthPercentages.map((w) => w * layoutWidth);
                this.columnsResized.emit(this.stateMap.columnWidths);
            }
        };
        this.recomputeColumnPercentages = () => {
            const layoutWidth = this.getLayoutWidth();
            if (layoutWidth != null &&
                this.stateMap.columnWidths.length ===
                    this.stateMap.columnWidthPercentages.length) {
                this.stateMap.columnWidthPercentages = this.stateMap.columnWidths.map((w) => w / layoutWidth);
            }
        };
        this.computeInitialColumnWidths = () => {
            this.stateMap.columnWidths = this.columnElements.map((c) => { var _a; return (_a = c.initialWidth) !== null && _a !== void 0 ? _a : 100; });
            const layoutWidth = this.getLayoutWidth();
            if (layoutWidth != null) {
                const columnWidthSum = this.stateMap.columnWidths.reduce((result, w) => result + w, 0);
                const scaledColumnWidths = this.stateMap.columnWidths.map((w) => w * (layoutWidth / columnWidthSum));
                this.stateMap.columnWidthPercentages = scaledColumnWidths.map((w) => w / layoutWidth);
                this.stateMap.columnWidths = scaledColumnWidths;
            }
        };
        this.updateColumnElements = () => {
            this.columnElements = Array.from(this.hostEl.querySelectorAll('vertex-scene-tree-table-column'));
        };
        this.computeCellHeight = async () => {
            var _a;
            if (this.isComputingCellHeight && this.columnElements.length > 0) {
                const dummyData = {
                    index: 0,
                    node: {
                        id: { hex: '' },
                        name: 'Dummy row',
                        expanded: false,
                        selected: false,
                        visible: false,
                        partiallyVisible: false,
                        isLeaf: false,
                        depth: 0,
                        columnsList: [],
                        filterHit: false,
                        hasGeometry: false,
                        phantom: false,
                        endItem: false,
                    },
                    metadata: {},
                    data: {},
                };
                const { bindings, element } = this.createColumnCellInstance(this.columnElements[0]);
                bindings.bind(dummyData);
                element.style.visibility = 'hidden';
                (_a = this.columnElements[0]) === null || _a === void 0 ? void 0 : _a.appendChild(element);
                /* eslint-disable @typescript-eslint/no-explicit-any */
                if (typeof element.componentOnReady === 'function') {
                    await element.componentOnReady();
                }
                /* eslint-enable @typescript-eslint/no-explicit-any */
                let height = element.clientHeight;
                if (height === 0) {
                    height = await new Promise((resolve) => {
                        setTimeout(() => resolve(element.getBoundingClientRect().height), 5);
                    });
                }
                this.rowHeight = height !== null && height !== void 0 ? height : this.rowHeight;
                element.remove();
                this.isComputingCellHeight = this.rowHeight === 0;
            }
        };
        this.computeHeaderHeight = () => {
            var _a;
            if (this.stateMap.headerHeight == null) {
                this.stateMap.headerHeight =
                    (_a = this.headerElement) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().height;
                this.hostEl.style.setProperty('--header-height', `${this.stateMap.headerHeight}px`);
            }
        };
        this.computeColumnGridLayout = () => {
            if (this.stateMap.columnWidths.length === 0) {
                this.stateMap.columnWidths = this.columnElements.map((c) => { var _a; return (_a = c.initialWidth) !== null && _a !== void 0 ? _a : 100; });
            }
            const layoutWidth = this.getLayoutWidth();
            if (layoutWidth != null) {
                if (this.stateMap.columnWidthPercentages.length === 0) {
                    this.stateMap.columnWidthPercentages = this.columnElements.map((c) => { var _a; return ((_a = c.initialWidth) !== null && _a !== void 0 ? _a : 100) / layoutWidth; });
                }
            }
            /**
             * This layout uses `1fr` instead of the final column width to
             * allow the final column to shrink when a scrollbar appears.
             *
             * This flex behavior is not desired for the header and divider
             * elements since they are not scrollable, and `columnGridFixedLayout`
             * should be used instead.
             */
            this.columnGridLayout = `${this.stateMap.columnWidths
                .slice(0, -1)
                .reduce((res, w) => `${res} ${w}px`, '')} 1fr`;
            this.columnGridFixedLayout = `${this.stateMap.columnWidths.reduce((res, w) => `${res} ${w}px`, '')}`;
        };
        this.bindHeaderData = () => {
            if (this.stateMap.headerInstances == null) {
                this.stateMap.headerInstances = this.columnElements
                    .map((c, i) => {
                    var _a;
                    const instance = this.createHeaderInstance(c);
                    if (instance != null) {
                        instance.element.style.paddingRight =
                            i === this.columnElements.length - 1
                                ? `0`
                                : `var(--scene-tree-table-column-gap)`;
                        instance.element.slot = 'header';
                        instance.element.style.gridColumnStart = `${i + 1}`;
                        instance.element.style.gridColumnEnd = `${i + 2}`;
                        (_a = this.hostEl) === null || _a === void 0 ? void 0 : _a.appendChild(instance.element);
                    }
                    return instance;
                })
                    .filter((i) => i != null);
            }
            if (this.stateMap.headerDividerInstances == null) {
                this.stateMap.headerDividerInstances = this.columnElements
                    .slice(0, -1)
                    .map((_, i) => {
                    var _a;
                    const instance = this.createDividerInstance();
                    instance.element.slot = 'divider';
                    instance.element.style.position = 'absolute';
                    instance.element.style.right = '0';
                    instance.element.style.pointerEvents = 'auto';
                    instance.element.style.gridColumnStart = `${i + 1}`;
                    instance.element.style.gridColumnEnd = `${i + 2}`;
                    (_a = this.hostEl) === null || _a === void 0 ? void 0 : _a.appendChild(instance.element);
                    return instance;
                });
            }
        };
        this.rebindHeaderData = () => {
            var _a, _b;
            this.removeDividerDragListeners();
            (_a = this.stateMap.headerInstances) === null || _a === void 0 ? void 0 : _a.forEach((i) => i.element.remove());
            (_b = this.stateMap.headerDividerInstances) === null || _b === void 0 ? void 0 : _b.forEach((i) => i.element.remove());
            this.stateMap.headerInstances = undefined;
            this.stateMap.headerDividerInstances = undefined;
            this.bindHeaderData();
            this.addDividerDragListeners();
        };
        this.createDividerPointerDownHandler = (index) => {
            return (event) => {
                var _a, _b;
                event.preventDefault();
                event.stopPropagation();
                this.lastDividerPointerPosition = point.create(Math.floor(event.clientX), Math.floor(event.clientY));
                this.resizingColumnIndex = index;
                (_b = (_a = this.stateMap.headerDividerInstances) === null || _a === void 0 ? void 0 : _a[index]) === null || _b === void 0 ? void 0 : _b.element.classList.add('dragging');
                window.addEventListener('pointermove', this.handleDividerPointerMove);
                window.addEventListener('pointerup', this.handleDividerPointerUp);
            };
        };
        this.handleDividerPointerMove = (event) => {
            const current = point.create(Math.floor(event.clientX), Math.floor(event.clientY));
            if (this.lastDividerPointerPosition != null &&
                this.resizingColumnIndex != null) {
                const resizingIndex = this.resizingColumnIndex;
                const diff = point.subtract(this.lastDividerPointerPosition, current);
                if (Math.abs(diff.x) >= 1 && this.isValidResize(diff, resizingIndex)) {
                    this.stateMap.columnWidths = this.stateMap.columnWidths.map((w, i) => i === resizingIndex ? w - diff.x : w);
                    if (resizingIndex + 1 < this.stateMap.columnWidths.length) {
                        this.stateMap.columnWidths = this.stateMap.columnWidths.map((w, i) => i === resizingIndex + 1 ? w + diff.x : w);
                    }
                    this.lastDividerPointerPosition = current;
                    this.computeColumnGridLayout();
                }
            }
        };
        this.handleDividerPointerUp = () => {
            var _a, _b;
            if (this.resizingColumnIndex != null) {
                (_b = (_a = this.stateMap.headerDividerInstances) === null || _a === void 0 ? void 0 : _a[this.resizingColumnIndex]) === null || _b === void 0 ? void 0 : _b.element.classList.remove('dragging');
            }
            this.lastDividerPointerPosition = undefined;
            this.resizingColumnIndex = undefined;
            this.recomputeColumnPercentages();
            this.recomputeColumnWidths();
            window.removeEventListener('pointermove', this.handleDividerPointerMove);
            window.removeEventListener('pointerup', this.handleDividerPointerUp);
        };
        this.isValidResize = (diff, index) => {
            var _a, _b, _c, _d;
            const currentColumn = this.columnElements[index];
            const nextColumn = this.columnElements[index + 1];
            const currentWidth = this.stateMap.columnWidths[index];
            const nextWidth = this.stateMap.columnWidths[index + 1];
            const currentMinWidth = (_a = currentColumn.minWidth) !== null && _a !== void 0 ? _a : 0;
            const currentMaxWidth = (_b = currentColumn.maxWidth) !== null && _b !== void 0 ? _b : Number.MAX_SAFE_INTEGER;
            const nextMinWidth = (_c = nextColumn.minWidth) !== null && _c !== void 0 ? _c : 0;
            const nextMaxWidth = (_d = nextColumn.maxWidth) !== null && _d !== void 0 ? _d : Number.MAX_SAFE_INTEGER;
            const currentIsValid = currentWidth - diff.x > currentMinWidth &&
                currentWidth - diff.x < currentMaxWidth;
            const nextIsValid = nextColumn != null
                ? nextWidth + diff.x > nextMinWidth && nextWidth + diff.x < nextMaxWidth
                : true;
            return currentIsValid && nextIsValid;
        };
        this.handleScrollChanged = async (event) => {
            this.isScrolling = true;
            this.scrollTimer = restartTimeout(() => {
                this.isScrolling = false;
            }, this.scrollTimer);
            this.scrollOffset = event.target.scrollTop;
            await this.computeAndUpdateViewportRows();
        };
    }
    componentWillLoad() {
        this.updateColumnElements();
        this.createPools();
        this.headerResizeObserver = new ResizeObserver(() => {
            this.stateMap.headerHeight = undefined;
            this.computeHeaderHeight();
            this.updateLayoutPosition();
        });
        this.resizeObserver = new ResizeObserver(() => {
            this.updateLayoutPosition();
            this.clearLayoutHeight();
            this.clearLayoutWidth();
            this.recomputeColumnWidths();
            this.computeColumnGridLayout();
        });
    }
    async componentDidLoad() {
        var _a, _b, _c;
        this.computeInitialColumnWidths();
        this.computeColumnGridLayout();
        this.ensureDividerTemplateDefined();
        this.computeCellHeight();
        this.computeHeaderHeight();
        this.rebindHeaderData();
        (_a = this.tableElement) === null || _a === void 0 ? void 0 : _a.addEventListener('scroll', this.handleScrollChanged, {
            passive: true,
        });
        if (this.headerElement != null) {
            (_b = this.headerResizeObserver) === null || _b === void 0 ? void 0 : _b.observe(this.headerElement);
        }
        (_c = this.resizeObserver) === null || _c === void 0 ? void 0 : _c.observe(this.hostEl);
    }
    async componentWillRender() {
        await this.computeAndUpdateViewportRows();
    }
    componentDidRender() {
        this.layoutColumns();
        this.layoutRendered.emit();
    }
    async componentDidUpdate() {
        if (this.isComputingCellHeight) {
            await this.computeCellHeight();
        }
    }
    disconnectedCallback() {
        var _a, _b, _c;
        (_a = this.tableElement) === null || _a === void 0 ? void 0 : _a.removeEventListener('scroll', this.handleScrollChanged);
        this.removeDividerDragListeners();
        (_b = this.headerResizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
        (_c = this.resizeObserver) === null || _c === void 0 ? void 0 : _c.disconnect();
        this.stateMap.columnWidths = [];
        this.stateMap.columnWidthPercentages = [];
    }
    async handleViewportRowsPropsChanged() {
        await this.computeAndUpdateViewportRows();
    }
    /**
     * Scrolls the table to the provided top value.
     *
     * @param top The position to scroll to.
     * @param options A set of options to configure the scrolling behavior.
     */
    async scrollToPosition(top, options) {
        if (this.tableElement != null) {
            scrollToTop(this.tableElement, top, options);
        }
    }
    /**
     * Attempts to compute the height of templated cells. Used for internals
     * or testing.
     *
     * @internal
     * @ignore
     */
    async attemptComputeCellHeight() {
        this.computeCellHeight();
    }
    render() {
        return (h(Host, { key: 'b2968ba20c38a9e9ddda5b5af54c8ffef30d7682' }, h("div", { key: 'd17866ac3ac7f26ba76b46ff5682a0ec910faff5', class: "header", ref: (ref) => (this.headerElement = ref), style: {
                gridTemplateColumns: this.columnGridFixedLayout,
                display: this.columnElements.length <= 1 ? 'none' : 'grid',
            } }, h("slot", { key: '6bd84a11c21b399b848b8e18875117c9bf549278', name: "header" })), h("div", { key: '619f01616e0903d35d806116fb3f0f549ba9e388', class: "table", ref: (ref) => (this.tableElement = ref), style: {
                gridTemplateColumns: this.columnGridLayout,
            } }, h("slot", { key: 'b0de28b116b31023d2988d5dc13dbd0838b2317d', onSlotchange: () => {
                this.ensureDividerTemplateDefined();
                this.updateColumnElements();
                this.recreateColumnPools();
                this.computeInitialColumnWidths();
                this.rebindHeaderData();
                this.computeColumnGridLayout();
            } })), h("div", { key: '7260968b016ab69858dcd96ec2f053654772d432', class: "divider-overlay", style: {
                gridTemplateColumns: this.columnGridFixedLayout,
            } }, h("slot", { key: '9066d169f49953069710e0a20899f4dd5c9c69c9', name: "divider" })), this.resizingColumnIndex != null && h("div", { key: '54c202cc30717398d42eb80db613f9288334cd3a', class: "resize-overlay" })));
    }
    computeViewportRows() {
        const viewportHeight = this.getLayoutHeight();
        const canComputeIndices = viewportHeight != null &&
            viewportHeight > 0 &&
            !this.isComputingCellHeight;
        if (canComputeIndices) {
            const viewportCount = Math.ceil(viewportHeight / this.rowHeight);
            const viewportStartIndex = Math.floor(this.scrollOffset / this.rowHeight);
            const viewportEndIndex = viewportStartIndex + viewportCount;
            const startIndex = Math.max(0, viewportStartIndex - this.overScanCount);
            const endIndex = Math.min(this.totalRows - 1, viewportEndIndex + this.overScanCount);
            const rows = this.getViewportRows(startIndex, endIndex);
            this.viewportStartIndex = startIndex;
            this.viewportEndIndex = endIndex;
            this.stateMap.viewportRows = rows;
        }
    }
    async computeAndUpdateViewportRows() {
        var _a;
        this.computeViewportRows();
        if (((_a = this.controller) === null || _a === void 0 ? void 0 : _a.isConnected) && this.totalRows > 0) {
            await this.controller.updateActiveRowRange(this.viewportStartIndex, this.viewportEndIndex);
        }
    }
    createPools() {
        if (this.stateMap.columnElementPools == null) {
            this.stateMap.columnElementPools = this.columnElements.reduce((map, c) => map.set(c, new ElementPool(c, () => this.createColumnCellInstance(c))), new WeakMap());
        }
    }
    recreateColumnPools() {
        this.columnElements.forEach((c) => {
            var _a, _b, _c;
            if (((_a = this.stateMap.columnElementPools) === null || _a === void 0 ? void 0 : _a.get(c)) == null) {
                (_b = this.stateMap.columnElementPools) === null || _b === void 0 ? void 0 : _b.set(c, new ElementPool(c, () => this.createColumnCellInstance(c)));
            }
            else {
                (_c = this.stateMap.columnElementPools
                    .get(c)) === null || _c === void 0 ? void 0 : _c.updateElementFactory(() => this.createColumnCellInstance(c));
            }
        });
    }
    iterateColumns(f) {
        this.columnElements.forEach((column, i) => {
            var _a;
            const pool = (_a = this.stateMap.columnElementPools) === null || _a === void 0 ? void 0 : _a.get(column);
            if (pool != null) {
                f(column, pool, i);
            }
            else {
                throw new Error('Cannot find pool for column');
            }
        });
    }
    ensureDividerTemplateDefined() {
        const template = this.hostEl.querySelector('template[slot="divider"]');
        if (template == null) {
            const defaultDividerTemplate = document.createElement('template');
            defaultDividerTemplate.slot = 'divider';
            defaultDividerTemplate.innerHTML = `
        <vertex-scene-tree-table-resize-divider slot="divider">
        </vertex-scene-tree-table-resize-divider>
      `;
            this.hostEl.appendChild(defaultDividerTemplate);
        }
    }
    createHeaderInstance(column) {
        const template = column.querySelector('template[slot="header"]');
        if (template != null) {
            return generateInstanceFromTemplate(template);
        }
    }
    createDividerInstance() {
        const template = this.hostEl.querySelector('template[slot="divider"]');
        if (template != null) {
            return generateInstanceFromTemplate(template);
        }
        else {
            throw new Error('Table is missing divider template element');
        }
    }
    createColumnCellInstance(column) {
        const template = column.querySelector('template:not([slot="header"])');
        if (template != null) {
            return generateInstanceFromTemplate(template);
        }
        else {
            throw new Error('Column is missing cell template element');
        }
    }
    addDividerDragListeners() {
        var _a;
        this.stateMap.headerDividerListeners =
            (_a = this.stateMap.headerDividerInstances) === null || _a === void 0 ? void 0 : _a.map((d, i) => {
                const listener = this.createDividerPointerDownHandler(i);
                d.element.addEventListener('pointerdown', listener);
                return listener;
            });
    }
    removeDividerDragListeners() {
        var _a;
        if (this.stateMap.headerDividerListeners != null) {
            const listeners = this.stateMap.headerDividerListeners;
            (_a = this.stateMap.headerDividerInstances) === null || _a === void 0 ? void 0 : _a.forEach((d, i) => {
                const listener = listeners[i];
                if (listener != null) {
                    d.element.removeEventListener('pointerdown', listener);
                }
            });
            this.stateMap.headerDividerListeners = undefined;
        }
    }
    getViewportRows(startIndex, endIndex) {
        const rows = this.rows.slice(startIndex, endIndex + 1);
        return rows.map((row) => (row != null ? this.populateRowData(row) : row));
    }
    populateRowData(row) {
        var _a;
        if (this.rowData != null && row != null) {
            const data = ((_a = this.rowData) === null || _a === void 0 ? void 0 : _a.call(this, row)) || {};
            return { ...row, data };
        }
        else {
            return row;
        }
    }
    getLayoutHeight() {
        if (this.layoutHeight == null && this.tableElement != null) {
            this.layoutHeight = getSceneTreeViewportHeight(this.tableElement);
        }
        return this.layoutHeight;
    }
    getLayoutWidth() {
        if (this.layoutWidth == null) {
            const computedWidth = getSceneTreeTableViewportWidth(this.hostEl);
            if (computedWidth > 0) {
                this.layoutWidth = computedWidth;
            }
        }
        return this.layoutWidth;
    }
    clearLayoutHeight() {
        this.layoutHeight = undefined;
    }
    clearLayoutWidth() {
        this.layoutWidth = undefined;
    }
    get hostEl() { return getElement(this); }
    static get watchers() { return {
        "rows": [{
                "handleViewportRowsPropsChanged": 0
            }],
        "totalRows": [{
                "handleViewportRowsPropsChanged": 0
            }],
        "rowHeight": [{
                "handleViewportRowsPropsChanged": 0
            }]
    }; }
};
SceneTreeTableLayout.style = sceneTreeTableLayoutCss();

const sceneTreeToolbarCss = () => `:host{--scene-tree-toolbar-content-gap:8px;display:flex;padding:0.5rem}.content{display:flex;align-items:center}.content-primary{width:100%}::slotted(:not(:first-child)){margin-left:var(--scene-tree-toolbar-content-gap)}`;

const SceneTreeToolbar = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
    }
    render() {
        return (h(Host, { key: '7a3286d46171832c1fae126645568899b1004fa1' }, h("div", { key: 'ac81e6da67a1c41dbb30a23ec9658ddbac0cd9ea', class: "content" }, h("slot", { key: '1993b705fbeeca9f7fee213662981403d89ea4c2', name: "before" })), h("div", { key: 'ee8b5cf8eccb88a4b0b029c6f3a33c9c5f20ef09', class: "content content-primary" }, h("slot", { key: '2cb220546b02b8dd353aa0270bbfa7f51dc0ca95' })), h("div", { key: 'cd0c977e5f42f1dbacaad42306b1705a97b50ab9', class: "content" }, h("slot", { key: '0f3af32f24077fa6d0bda7cc1fce3b9921b49f70', name: "after" }))));
    }
};
SceneTreeToolbar.style = sceneTreeToolbarCss();

export { SceneTreeNotificationBanner as vertex_scene_tree_notification_banner, SceneTreeSearch as vertex_scene_tree_search, SceneTreeTableLayout as vertex_scene_tree_table_layout, SceneTreeToolbar as vertex_scene_tree_toolbar };
//# sourceMappingURL=vertex-scene-tree-notification-banner.vertex-scene-tree-search.vertex-scene-tree-table-layout.vertex-scene-tree-toolbar.entry.js.map

//# sourceMappingURL=vertex-scene-tree-notification-banner_4.entry.js.map