var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { forceUpdate } from '@stencil/core';
import { MapToComponentField, MapToComponentMethod, VegaSlimmer } from 'vega-slimmer/core';
/**
 * Projects a light-DOM slot element into a container that lives inside a `vega-popover`'s `popover` slot.
 *
 * Why this slimmer exists:
 * `vega-popover` appends its `popover` slot content to a different shadow root (the appender), which breaks
 * normal slot projection for any extra slots declared inside that popover content. To support customization
 * via additional slots (e.g. a left-side panel), the host component must imperatively move the slot element
 * into the rendered container on every render, and observe DOM mutations to keep the projection in sync when
 * consumers add, replace, or remove the slot at runtime.
 *
 * Usage:
 * 1. Inject this slimmer into the component with the slot name and a getter returning the container ref.
 * 2. Call `hasSlot()` in the renderer to conditionally render the container wrapper.
 *
 * Lifecycle:
 * - `componentWillLoad`: capture the current slot element and set up observers.
 * - `componentDidRender`: append the slot element into the container when needed.
 * - `disconnectedCallback`: disconnect observers.
 */
export class PopoverNestedSlotProjectionSlimmer extends VegaSlimmer {
  constructor(slotName, getContainerRef) {
    super();
    this.slotElement = null;
    /**
     * Syncs the stored slot reference with dynamic light-DOM additions or replacements.
     */
    this.syncSlotElementFromHost = () => {
      var _a;
      const newSlotElement = this.host.querySelector(this.slotSelector());
      if (newSlotElement) {
        this.slotElement = newSlotElement;
        (_a = this.getContainerRef()) === null || _a === void 0 ? void 0 : _a.replaceChildren(newSlotElement);
        forceUpdate(this.host);
      }
    };
    /**
     * Syncs the stored slot reference when the appended slot element is removed from the container.
     */
    this.syncRemovedSlotElement = () => {
      if (this.slotElement && !this.slotElement.isConnected) {
        this.slotElement = null;
        forceUpdate(this.host);
      }
    };
    this.slotName = slotName;
    this.getContainerRef = getContainerRef;
  }
  /**
   * Returns whether the host currently has a matching slot element.
   *
   * @returns {boolean} True if a slot element is present.
   */
  hasSlot() {
    return !!this.slotElement;
  }
  /**
   * Captures the current slot element from the host's light DOM and initializes the mutation observers
   * that keep the projection in sync with runtime changes.
   */
  detectSlot() {
    this.slotElement = this.host.querySelector(this.slotSelector());
    this.hostMutationObserver = new MutationObserver(this.syncSlotElementFromHost);
    this.hostMutationObserver.observe(this.host, { childList: true });
    this.containerMutationObserver = new MutationObserver(this.syncRemovedSlotElement);
  }
  /**
   * Appends the slot element into the container after each render. The popover moves its `popover` slot
   * content into a different shadow root, so normal slot projection cannot keep the nested slot attached.
   */
  appendSlotContent() {
    const container = this.getContainerRef();
    if (container) {
      this.containerMutationObserver.observe(container, { childList: true });
    }
    if (this.slotElement && container && this.slotElement.parentElement !== container) {
      container.appendChild(this.slotElement);
    }
  }
  /**
   * Disconnects the mutation observers when the component is removed from the DOM.
   */
  cleanup() {
    if (this.hostMutationObserver) {
      this.hostMutationObserver.disconnect();
    }
    if (this.containerMutationObserver) {
      this.containerMutationObserver.disconnect();
    }
  }
  /**
   * Builds the CSS selector for the configured slot name.
   *
   * @returns {string} The attribute selector string.
   */
  slotSelector() {
    return `[slot="${this.slotName}"]`;
  }
}
__decorate([
  MapToComponentField()
], PopoverNestedSlotProjectionSlimmer.prototype, "host", void 0);
__decorate([
  MapToComponentMethod('componentWillLoad')
], PopoverNestedSlotProjectionSlimmer.prototype, "detectSlot", null);
__decorate([
  MapToComponentMethod('componentDidRender')
], PopoverNestedSlotProjectionSlimmer.prototype, "appendSlotContent", null);
__decorate([
  MapToComponentMethod('disconnectedCallback')
], PopoverNestedSlotProjectionSlimmer.prototype, "cleanup", null);
