/* COPYRIGHT Esri - https://js.arcgis.com/5.1/LICENSE.txt */
import { makeGenericController } from "@arcgis/lumina/controllers";
import { createFocusTrap } from "focus-trap";
import { t as tabbableOptions, i as focusElement } from "./dom.js";
import { a as getConfig } from "./runtime.js";
function getEffectiveContainerElements(targetEl, { focusTrapOptions }, extraContainers) {
  if (!focusTrapOptions?.extraContainers && !extraContainers) {
    return targetEl;
  }
  return [targetEl, ...toContainerArray(focusTrapOptions?.extraContainers), ...toContainerArray(extraContainers)];
}
function toContainerArray(containers = []) {
  return Array.isArray(containers) ? containers : [containers];
}
const outsideClickDeactivated = /* @__PURE__ */ new WeakSet();
function defaultSetReturnFocus(hostEl, el) {
  const hasPreviousRelatedFocusedEl = el && el !== document.body && el !== document.documentElement;
  if (!outsideClickDeactivated.has(hostEl) && hasPreviousRelatedFocusedEl) {
    focusElement(el);
  }
  return false;
}
function createFocusTrapOptions(hostEl, options) {
  const fallbackFocus = options?.fallbackFocus || hostEl;
  const clickOutsideDeactivates = options?.clickOutsideDeactivates ?? true;
  let abortController;
  return {
    fallbackFocus,
    ...options,
    // the following options are not overridable
    document: hostEl.ownerDocument,
    tabbableOptions,
    trapStack: getConfig().focusTrapStack,
    clickOutsideDeactivates: (event) => {
      if (!outsideClickDeactivated.has(hostEl)) {
        outsideClickDeactivated.add(hostEl);
      }
      return typeof clickOutsideDeactivates === "function" ? clickOutsideDeactivates(event) : clickOutsideDeactivates;
    },
    onActivate: (params) => {
      if (options?.escapeDeactivates) {
        abortController = new AbortController();
        hostEl.addEventListener(
          "keydown",
          (event) => {
            if (event.key === "Escape") {
              const escapeDeactivates = options?.escapeDeactivates;
              const deactivate = typeof escapeDeactivates === "function" ? escapeDeactivates(event) : escapeDeactivates ?? true;
              if (deactivate) {
                params.trap.deactivate();
              }
            }
          },
          { signal: abortController.signal }
        );
      }
      options?.onActivate?.(params);
    },
    onDeactivate: (params) => {
      abortController?.abort();
      abortController = void 0;
      options?.onDeactivate?.(params);
    },
    onPostDeactivate: () => {
      outsideClickDeactivated.delete(hostEl);
    },
    setReturnFocus: (el) => {
      const returnFocusTarget = typeof options?.setReturnFocus === "function" ? options.setReturnFocus(el) : options?.setReturnFocus;
      return returnFocusTarget === void 0 ? defaultSetReturnFocus(hostEl, el) : returnFocusTarget;
    }
  };
}
const useFocusTrap = (options = {}) => {
  return makeGenericController((component, controller) => {
    let focusTrap;
    let focusTrapEl;
    let effectiveContainers;
    let requestedActive = false;
    const internalFocusTrapOptions = options.focusTrapOptions;
    const isTriggerActive = () => options.triggerProp ? Boolean(component[options.triggerProp]) : true;
    const shouldAutoActivate = () => options.triggerProp ? isTriggerActive() : requestedActive;
    const canActivateTrap = () => typeof component.focusTrapDisabledOverride === "function" ? !component.focusTrapDisabledOverride() : !component.focusTrapDisabled;
    const activateTrap = () => {
      const targetEl = focusTrapEl || component.el;
      if (!targetEl.isConnected) {
        return;
      }
      if (!focusTrap) {
        effectiveContainers ||= getEffectiveContainerElements(targetEl, component);
        focusTrap = createFocusTrap(
          effectiveContainers,
          createFocusTrapOptions(targetEl, {
            ...internalFocusTrapOptions,
            ...component.focusTrapOptions
          })
        );
      }
      if (canActivateTrap()) {
        focusTrap.activate();
      }
    };
    const deactivateTrap = () => {
      focusTrap?.deactivate();
    };
    controller.onConnected(() => {
      if (focusTrap && shouldAutoActivate()) {
        activateTrap();
      }
    });
    controller.onUpdate((changes) => {
      if (!component.hasUpdated || !changes.has("focusTrapDisabled")) {
        return;
      }
      if (component.focusTrapDisabled || !isTriggerActive()) {
        deactivateTrap();
        return;
      }
      if (shouldAutoActivate()) {
        activateTrap();
      }
    });
    controller.onDisconnected(() => deactivateTrap());
    const utils = {
      get _instance() {
        if (process.env.NODE_ENV === "test") {
          return focusTrap;
        }
        return void 0;
      },
      activate: () => {
        requestedActive = true;
        activateTrap();
      },
      deactivate: () => {
        requestedActive = false;
        deactivateTrap();
      },
      overrideFocusTrapEl: (el) => {
        if (focusTrap) {
          throw new Error("Focus trap already created");
        }
        focusTrapEl = el;
      },
      setExtraContainers: (extraContainers) => {
        const targetEl = focusTrapEl || component.el;
        effectiveContainers = getEffectiveContainerElements(targetEl, component, extraContainers);
      },
      updateContainerElements: () => {
        return focusTrap?.updateContainerElements(effectiveContainers);
      }
    };
    return utils;
  });
};
export {
  useFocusTrap as u
};
