"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/index.ts
var src_exports = {};
__export(src_exports, {
  defineAsCustomElement: () => defineAsCustomElement,
  defineAsCustomElementWithPortal: () => defineAsCustomElement2,
  useCustomElement: () => useCustomElement,
  useMethodCallback: () => useMethodCallback
});
module.exports = __toCommonJS(src_exports);

// src/defineAsCustomElement.tsx
var import_react3 = __toESM(require("react"));
var import_react_dom = require("react-dom");

// src/hooks/CustomElementProvider.tsx
var import_react2 = __toESM(require("react"));

// src/hooks/private/CustomElementContext.ts
var import_react = require("react");
var CustomElementContext = (0, import_react.createContext)(
  new Proxy({}, {
    get() {
      throw new Error("This hook cannot be used outside of the custom element.");
    }
  })
);
var CustomElementContext_default = CustomElementContext;

// src/hooks/CustomElementProvider.tsx
var CustomElementProvider = ({
  componentType,
  customElement,
  props,
  setMethodCallback
}) => {
  const context = (0, import_react2.useMemo)(
    () => ({
      customElementState: Object.freeze([customElement]),
      setMethodCallback
    }),
    [customElement, setMethodCallback]
  );
  return /* @__PURE__ */ import_react2.default.createElement(CustomElementContext_default.Provider, { value: context }, (0, import_react2.createElement)(componentType, props));
};
CustomElementProvider.displayName = "CustomElementProvider";
var MemoizedCustomElementProvider = (0, import_react2.memo)(CustomElementProvider, (prevProps, nextProps) => {
  return Object.is(prevProps.componentType, nextProps.componentType) && Object.is(prevProps.customElement, nextProps.customElement) && Object.is(prevProps.setMethodCallback, nextProps.setMethodCallback) && Array.from(new Set(Object.keys(prevProps.props)).union(new Set(Object.keys(nextProps.props)))).every(
    (key) => Object.is(prevProps.props[key], nextProps.props[key])
  );
});
var CustomElementProvider_default = MemoizedCustomElementProvider;

// src/private/createReactCustomElement.ts
function createReactCustomElement(customElementConstructor) {
  const registry = new FinalizationRegistry((dispose) => dispose());
  return class ReactCustomElement extends (customElementConstructor || HTMLElement) {
    constructor(attributesMap, shadowRootInit, mountCallback, unmountCallback) {
      super();
      this.#attributesMap = attributesMap;
      this.#mountCallback = mountCallback;
      this.#unmountCallback = unmountCallback;
      this.#element = shadowRootInit ? this.attachShadow(shadowRootInit) : this;
      registry.register(new WeakRef(this), this[Symbol.dispose].bind(this));
    }
    #attributesMap;
    #connected = false;
    #element;
    #methodNonceMap = /* @__PURE__ */ new Map();
    #mountCallback;
    #propsMap = /* @__PURE__ */ new Map();
    #setMethodCallbackBound = this.#setMethodCallback.bind(this);
    #unmountCallback;
    #version = 0;
    [Symbol.dispose]() {
      this.#unmountCallback?.(this.#element);
      this.#unmountCallback = void 0;
    }
    #getProps() {
      return Object.freeze(Object.fromEntries(this.#propsMap.entries()));
    }
    #refresh() {
      if (this.#connected) {
        const version = ++this.#version;
        queueMicrotask(() => {
          if (version === this.#version) {
            const element = this.#element;
            element && this.#mountCallback(this.#getProps(), element, this.#setMethodCallbackBound);
          }
        });
      }
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    #setMethodCallback(name, nonce, fn) {
      const existingNonce = this.#methodNonceMap.get(name);
      if (typeof existingNonce === "number" && existingNonce !== nonce) {
        throw new Error(`useMethodCallback('${name}') is already registered to another function.`);
      }
      this.#methodNonceMap.set(name, nonce);
      if (fn) {
        this[name] = (...args) => {
          return fn(...args);
        };
      } else {
        delete this[name];
      }
    }
    attributeChangedCallback(name, _oldValue, newValue) {
      const propName = this.#attributesMap[name];
      if (propName) {
        this.#propsMap.set(propName, newValue);
        this.#refresh();
      }
    }
    connectedCallback() {
      this.#connected = true;
      this.#refresh();
    }
    disconnectedCallback() {
      this.#connected = false;
    }
  };
}

// src/defineAsCustomElement.tsx
function defineAsCustomElement(componentType, tagName, attributesMap, init) {
  const observedAttributes = Object.freeze(Object.keys(attributesMap));
  customElements.define(
    tagName,
    class extends createReactCustomElement(init?.builtInElement?.customElementConstructor) {
      static get observedAttributes() {
        return observedAttributes;
      }
      constructor() {
        super(
          attributesMap,
          init?.shadowRoot,
          (props, element, setMethodCallback) => (0, import_react_dom.render)(
            /* @__PURE__ */ import_react3.default.createElement(
              CustomElementProvider_default,
              {
                componentType,
                customElement: element,
                props,
                setMethodCallback
              }
            ),
            element
          ),
          (element) => (0, import_react_dom.unmountComponentAtNode)(element)
        );
      }
    },
    init?.builtInElement?.extends ? { extends: init?.builtInElement?.extends } : {}
  );
}

// src/defineAsCustomElementWithPortal.tsx
var import_math_random = __toESM(require("math-random"));
var import_react4 = __toESM(require("react"));
var import_react_dom2 = require("react-dom");

// src/signalingState.ts
function signalingState(initialState) {
  let resolvers = Promise.withResolvers();
  let state = initialState;
  return {
    getState() {
      return state;
    },
    async next() {
      return resolvers.promise;
    },
    patchState(next) {
      state = next(state);
      const resolve = resolvers.resolve.bind(resolvers);
      resolvers = Promise.withResolvers();
      resolve();
    }
  };
}

// src/defineAsCustomElementWithPortal.tsx
function defineAsCustomElement2(componentType, tagName, attributesMap, init) {
  const { getState, next, patchState } = signalingState(/* @__PURE__ */ new Map());
  const observedAttributes = Object.freeze(Object.keys(attributesMap));
  customElements.define(
    tagName,
    class extends createReactCustomElement(init?.builtInElement?.customElementConstructor) {
      static get observedAttributes() {
        return observedAttributes;
      }
      constructor() {
        super(
          attributesMap,
          init?.shadowRoot,
          (props, element, setMethodCallback) => patchState(
            (map) => Object.freeze(new Map(map).set(this.#key, Object.freeze([element, props, setMethodCallback])))
          ),
          () => patchState((map) => {
            const nextMap = new Map(map);
            nextMap.delete(this.#key);
            return Object.freeze(nextMap);
          })
        );
      }
      #key = (0, import_math_random.default)().toString(36).substring(2);
    },
    init?.builtInElement?.extends ? { extends: init?.builtInElement?.extends } : {}
  );
  let portalMounted = false;
  const CustomElementsWrapperPortal = (0, import_react4.memo)(() => {
    const [instances, setInstances] = (0, import_react4.useState)(/* @__PURE__ */ new Map());
    (0, import_react4.useEffect)(() => {
      if (portalMounted) {
        throw new Error("Portal already mounted.");
      }
      portalMounted = true;
      let unmounted = false;
      (async () => {
        while (!unmounted) {
          const state = getState();
          typeof state !== "undefined" && setInstances(state);
          await next();
        }
      })();
      return () => {
        unmounted = true;
        portalMounted = false;
      };
    }, [setInstances]);
    return /* @__PURE__ */ import_react4.default.createElement(import_react4.Fragment, null, Array.from(
      instances.entries().map(
        ([key, [element, props, setMethodCallback]]) => (0, import_react_dom2.createPortal)(
          /* @__PURE__ */ import_react4.default.createElement(
            CustomElementProvider_default,
            {
              componentType,
              customElement: element,
              props,
              setMethodCallback
            }
          ),
          element,
          key
        )
      )
    ));
  });
  CustomElementsWrapperPortal.displayName = "CustomElementsWrapperPortal";
  return { Portal: CustomElementsWrapperPortal };
}

// src/hooks/private/useCustomElementContext.ts
var import_react5 = require("react");
function useCustomElementContext() {
  return (0, import_react5.useContext)(CustomElementContext_default);
}

// src/hooks/useCustomElement.ts
function useCustomElement() {
  return useCustomElementContext().customElementState;
}

// src/hooks/useMethodCallback.ts
var import_math_random2 = __toESM(require("math-random"));
var import_react6 = require("react");
function useMethodCallback(name, fn) {
  const nonceRef = (0, import_react6.useRef)((0, import_math_random2.default)());
  useCustomElementContext().setMethodCallback(name, nonceRef.current, fn);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  defineAsCustomElement,
  defineAsCustomElementWithPortal,
  useCustomElement,
  useMethodCallback
});
//# sourceMappingURL=react-define-as-custom-element.js.map