"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.ZIndexLayer = ZIndexLayer;
var _react = require("react");
var _reactDom = require("react-dom");
var _hooks = require("../state/hooks");
var _zIndexSelectors = require("./zIndexSelectors");
var _zIndexSlice = require("../state/zIndexSlice");
var _chartLayoutContext = require("../context/chartLayoutContext");
var _PanoramaContext = require("../context/PanoramaContext");
/**
 * @since 3.4
 */

/**
 * A layer that renders its children into a portal corresponding to the given zIndex.
 * We can't use regular CSS `z-index` because SVG does not support it.
 * So instead, we create separate DOM nodes for each zIndex layer
 * and render the children into the corresponding DOM node using React portals.
 *
 * This component must be used inside a Chart component.
 *
 * @param zIndex numeric zIndex value, higher values are rendered on top of lower values
 * @param children the content to render inside this zIndex layer
 *
 * @since 3.4
 */
function ZIndexLayer(_ref) {
  var {
    zIndex,
    children
  } = _ref;
  /*
   * If we are outside of chart, then we can't rely on the zIndex portal state,
   * so we just render normally.
   */
  var isInChartContext = (0, _chartLayoutContext.useIsInChartContext)();
  /*
   * If zIndex is undefined then we render normally without portals.
   * Also, if zIndex is 0, we render normally without portals,
   * because 0 is the default layer that does not need a portal.
   */
  var shouldRenderInPortal = isInChartContext && zIndex !== undefined && zIndex !== 0;
  var isPanorama = (0, _PanoramaContext.useIsPanorama)();

  /**
   * When zIndex changes, the new portal element is not immediately available because
   * it requires a full render cycle through AllZIndexPortals → ZIndexSvgPortal.
   * During this transition we keep rendering into the previous portal element
   * to avoid an unmount/remount cycle that would cause children to briefly disappear.
   *
   * `registeredZIndexesRef` tracks every zIndex we have registered so that
   * we can defer unregistration of old values until the new portal is ready.
   * `lastPortalElementRef` caches the most recent valid portal DOM node.
   */
  var lastPortalElementRef = (0, _react.useRef)(undefined);
  var registeredZIndexesRef = (0, _react.useRef)(new Set());
  var dispatch = (0, _hooks.useAppDispatch)();
  var portalElement = (0, _hooks.useAppSelector)(state => (0, _zIndexSelectors.selectZIndexPortalElement)(state, zIndex, isPanorama));

  /*
   * Lifecycle effect — handles both registration and deferred cleanup.
   *
   * Registration: when zIndex changes we register the new value WITHOUT
   * immediately unregistering the old one. This keeps the old <g> element
   * alive in the DOM so `lastPortalElementRef` remains a valid render target.
   *
   * Deferred cleanup: once `portalElement` for the *new* zIndex becomes
   * available we unregister every stale zIndex that is no longer needed.
   */
  (0, _react.useLayoutEffect)(() => {
    if (!shouldRenderInPortal) {
      // Portal rendering was disabled — clean up any stale registrations
      var registered = registeredZIndexesRef.current;
      registered.forEach(z => {
        dispatch((0, _zIndexSlice.unregisterZIndexPortal)({
          zIndex: z
        }));
      });
      registered.clear();
      lastPortalElementRef.current = undefined;
      return;
    }

    /*
     * Because zIndexes are dynamic (meaning, we're not working with a predefined set of layers,
     * but we allow users to define any zIndex at any time), we need to register
     * the requested zIndex in the global store. This way, the ZIndexPortals component
     * can render the corresponding portals and only the requested ones.
     */
    // Register the current zIndex (idempotent — skips if already registered)
    if (!registeredZIndexesRef.current.has(zIndex)) {
      dispatch((0, _zIndexSlice.registerZIndexPortal)({
        zIndex
      }));
      registeredZIndexesRef.current.add(zIndex);
    }

    // When the new portal element is ready, retire old zIndex registrations
    if (portalElement) {
      lastPortalElementRef.current = portalElement;
      var _registered = registeredZIndexesRef.current;
      _registered.forEach(z => {
        if (z !== zIndex) {
          dispatch((0, _zIndexSlice.unregisterZIndexPortal)({
            zIndex: z
          }));
          _registered.delete(z);
        }
      });
    }
  }, [dispatch, zIndex, shouldRenderInPortal, portalElement]);

  // Unmount-only cleanup — unregister everything when the component is removed
  (0, _react.useLayoutEffect)(() => {
    var registered = registeredZIndexesRef.current;
    return () => {
      registered.forEach(z => {
        dispatch((0, _zIndexSlice.unregisterZIndexPortal)({
          zIndex: z
        }));
      });
      registered.clear();
    };
  }, [dispatch]);
  if (!shouldRenderInPortal) {
    return children;
  }

  // Prefer the current portal; fall back to the cached one during transitions
  var targetElement = portalElement !== null && portalElement !== void 0 ? portalElement : lastPortalElementRef.current;
  if (!targetElement) {
    // Very first render — no portal has ever been registered yet
    return null;
  }
  return /*#__PURE__*/(0, _reactDom.createPortal)(children, targetElement);
}