var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __typeError = (msg) => {
  throw TypeError(msg);
};
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
var __async = (__this, __arguments, generator) => {
  return new Promise((resolve, reject) => {
    var fulfilled = (value) => {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    };
    var rejected = (value) => {
      try {
        step(generator.throw(value));
      } catch (e) {
        reject(e);
      }
    };
    var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
    step((generator = generator.apply(__this, __arguments)).next());
  });
};
var _PrimitiveNode_instances, onFirstConnection_fn, createWidget_fn, mergeWidgetConfig_fn, isValidConnection_fn, removeWidgets_fn, _convertedToProcess;
import { C as ComfyDialog, $ as $el, a as ComfyApp, b as app, L as LGraphCanvas, c as LiteGraph, d as applyTextReplacements, e as ComfyWidgets, f as addValueControlWidgets, D as DraggableList, g as api, u as useToastStore, h as LGraphGroup, i as LGraphNode } from "./index-CaD4RONs.js";
const _ClipspaceDialog = class _ClipspaceDialog extends ComfyDialog {
  static registerButton(name, contextPredicate, callback) {
    const item = $el("button", {
      type: "button",
      textContent: name,
      contextPredicate,
      onclick: callback
    });
    _ClipspaceDialog.items.push(item);
  }
  static invalidatePreview() {
    if (ComfyApp.clipspace && ComfyApp.clipspace.imgs && ComfyApp.clipspace.imgs.length > 0) {
      const img_preview = document.getElementById(
        "clipspace_preview"
      );
      if (img_preview) {
        img_preview.src = ComfyApp.clipspace.imgs[ComfyApp.clipspace["selectedIndex"]].src;
        img_preview.style.maxHeight = "100%";
        img_preview.style.maxWidth = "100%";
      }
    }
  }
  static invalidate() {
    if (_ClipspaceDialog.instance) {
      const self = _ClipspaceDialog.instance;
      const children = $el("div.comfy-modal-content", [
        self.createImgSettings(),
        ...self.createButtons()
      ]);
      if (self.element) {
        self.element.removeChild(self.element.firstChild);
        self.element.appendChild(children);
      } else {
        self.element = $el("div.comfy-modal", { parent: document.body }, [
          children
        ]);
      }
      if (self.element.children[0].children.length <= 1) {
        self.element.children[0].appendChild(
          $el("p", {}, [
            "Unable to find the features to edit content of a format stored in the current Clipspace."
          ])
        );
      }
      _ClipspaceDialog.invalidatePreview();
    }
  }
  constructor() {
    super();
  }
  createButtons() {
    const buttons = [];
    for (let idx in _ClipspaceDialog.items) {
      const item = _ClipspaceDialog.items[idx];
      if (!item.contextPredicate || item.contextPredicate())
        buttons.push(_ClipspaceDialog.items[idx]);
    }
    buttons.push(
      $el("button", {
        type: "button",
        textContent: "Close",
        onclick: /* @__PURE__ */ __name(() => {
          this.close();
        }, "onclick")
      })
    );
    return buttons;
  }
  createImgSettings() {
    if (ComfyApp.clipspace.imgs) {
      const combo_items = [];
      const imgs = ComfyApp.clipspace.imgs;
      for (let i = 0; i < imgs.length; i++) {
        combo_items.push($el("option", { value: i }, [`${i}`]));
      }
      const combo1 = $el(
        "select",
        {
          id: "clipspace_img_selector",
          onchange: /* @__PURE__ */ __name((event) => {
            ComfyApp.clipspace["selectedIndex"] = event.target.selectedIndex;
            _ClipspaceDialog.invalidatePreview();
          }, "onchange")
        },
        combo_items
      );
      const row1 = $el("tr", {}, [
        $el("td", {}, [$el("font", { color: "white" }, ["Select Image"])]),
        $el("td", {}, [combo1])
      ]);
      const combo2 = $el(
        "select",
        {
          id: "clipspace_img_paste_mode",
          onchange: /* @__PURE__ */ __name((event) => {
            ComfyApp.clipspace["img_paste_mode"] = event.target.value;
          }, "onchange")
        },
        [
          $el("option", { value: "selected" }, "selected"),
          $el("option", { value: "all" }, "all")
        ]
      );
      combo2.value = ComfyApp.clipspace["img_paste_mode"];
      const row2 = $el("tr", {}, [
        $el("td", {}, [$el("font", { color: "white" }, ["Paste Mode"])]),
        $el("td", {}, [combo2])
      ]);
      const td = $el(
        "td",
        { align: "center", width: "100px", height: "100px", colSpan: "2" },
        [$el("img", { id: "clipspace_preview", ondragstart: /* @__PURE__ */ __name(() => false, "ondragstart") }, [])]
      );
      const row3 = $el("tr", {}, [td]);
      return $el("table", {}, [row1, row2, row3]);
    } else {
      return [];
    }
  }
  createImgPreview() {
    if (ComfyApp.clipspace.imgs) {
      return $el("img", { id: "clipspace_preview", ondragstart: /* @__PURE__ */ __name(() => false, "ondragstart") });
    } else return [];
  }
  show() {
    const img_preview = document.getElementById("clipspace_preview");
    _ClipspaceDialog.invalidate();
    this.element.style.display = "block";
  }
};
__name(_ClipspaceDialog, "ClipspaceDialog");
__publicField(_ClipspaceDialog, "items", []);
__publicField(_ClipspaceDialog, "instance", null);
let ClipspaceDialog = _ClipspaceDialog;
app.registerExtension({
  name: "Comfy.Clipspace",
  init(app2) {
    app2.openClipspace = function() {
      if (!ClipspaceDialog.instance) {
        ClipspaceDialog.instance = new ClipspaceDialog();
        ComfyApp.clipspace_invalidate_handler = ClipspaceDialog.invalidate;
      }
      if (ComfyApp.clipspace) {
        ClipspaceDialog.instance.show();
      } else app2.ui.dialog.show("Clipspace is Empty!");
    };
  }
});
window.comfyAPI = window.comfyAPI || {};
window.comfyAPI.clipspace = window.comfyAPI.clipspace || {};
window.comfyAPI.clipspace.ClipspaceDialog = ClipspaceDialog;
const colorPalettes = {
  dark: {
    id: "dark",
    name: "Dark (Default)",
    colors: {
      node_slot: {
        CLIP: "#FFD500",
        // bright yellow
        CLIP_VISION: "#A8DADC",
        // light blue-gray
        CLIP_VISION_OUTPUT: "#ad7452",
        // rusty brown-orange
        CONDITIONING: "#FFA931",
        // vibrant orange-yellow
        CONTROL_NET: "#6EE7B7",
        // soft mint green
        IMAGE: "#64B5F6",
        // bright sky blue
        LATENT: "#FF9CF9",
        // light pink-purple
        MASK: "#81C784",
        // muted green
        MODEL: "#B39DDB",
        // light lavender-purple
        STYLE_MODEL: "#C2FFAE",
        // light green-yellow
        VAE: "#FF6E6E",
        // bright red
        NOISE: "#B0B0B0",
        // gray
        GUIDER: "#66FFFF",
        // cyan
        SAMPLER: "#ECB4B4",
        // very soft red
        SIGMAS: "#CDFFCD",
        // soft lime green
        TAESD: "#DCC274"
        // cheesecake
      },
      litegraph_base: {
        BACKGROUND_IMAGE: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=",
        CLEAR_BACKGROUND_COLOR: "#222",
        NODE_TITLE_COLOR: "#999",
        NODE_SELECTED_TITLE_COLOR: "#FFF",
        NODE_TEXT_SIZE: 14,
        NODE_TEXT_COLOR: "#AAA",
        NODE_SUBTEXT_SIZE: 12,
        NODE_DEFAULT_COLOR: "#333",
        NODE_DEFAULT_BGCOLOR: "#353535",
        NODE_DEFAULT_BOXCOLOR: "#666",
        NODE_DEFAULT_SHAPE: "box",
        NODE_BOX_OUTLINE_COLOR: "#FFF",
        DEFAULT_SHADOW_COLOR: "rgba(0,0,0,0.5)",
        DEFAULT_GROUP_FONT: 24,
        WIDGET_BGCOLOR: "#222",
        WIDGET_OUTLINE_COLOR: "#666",
        WIDGET_TEXT_COLOR: "#DDD",
        WIDGET_SECONDARY_TEXT_COLOR: "#999",
        LINK_COLOR: "#9A9",
        EVENT_LINK_COLOR: "#A86",
        CONNECTING_LINK_COLOR: "#AFA"
      },
      comfy_base: {
        "fg-color": "#fff",
        "bg-color": "#202020",
        "comfy-menu-bg": "#353535",
        "comfy-input-bg": "#222",
        "input-text": "#ddd",
        "descrip-text": "#999",
        "drag-text": "#ccc",
        "error-text": "#ff4444",
        "border-color": "#4e4e4e",
        "tr-even-bg-color": "#222",
        "tr-odd-bg-color": "#353535",
        "content-bg": "#4e4e4e",
        "content-fg": "#fff",
        "content-hover-bg": "#222",
        "content-hover-fg": "#fff"
      }
    }
  },
  light: {
    id: "light",
    name: "Light",
    colors: {
      node_slot: {
        CLIP: "#FFA726",
        // orange
        CLIP_VISION: "#5C6BC0",
        // indigo
        CLIP_VISION_OUTPUT: "#8D6E63",
        // brown
        CONDITIONING: "#EF5350",
        // red
        CONTROL_NET: "#66BB6A",
        // green
        IMAGE: "#42A5F5",
        // blue
        LATENT: "#AB47BC",
        // purple
        MASK: "#9CCC65",
        // light green
        MODEL: "#7E57C2",
        // deep purple
        STYLE_MODEL: "#D4E157",
        // lime
        VAE: "#FF7043"
        // deep orange
      },
      litegraph_base: {
        BACKGROUND_IMAGE: "data:image/gif;base64,R0lGODlhZABkALMAAAAAAP///+vr6+rq6ujo6Ofn5+bm5uXl5d3d3f///wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAABkAGQAAAT/UMhJq7046827HkcoHkYxjgZhnGG6si5LqnIM0/fL4qwwIMAg0CAsEovBIxKhRDaNy2GUOX0KfVFrssrNdpdaqTeKBX+dZ+jYvEaTf+y4W66mC8PUdrE879f9d2mBeoNLfH+IhYBbhIx2jkiHiomQlGKPl4uZe3CaeZifnnijgkESBqipqqusra6vsLGys62SlZO4t7qbuby7CLa+wqGWxL3Gv3jByMOkjc2lw8vOoNSi0czAncXW3Njdx9Pf48/Z4Kbbx+fQ5evZ4u3k1fKR6cn03vHlp7T9/v8A/8Gbp4+gwXoFryXMB2qgwoMMHyKEqA5fxX322FG8tzBcRnMW/zlulPbRncmQGidKjMjyYsOSKEF2FBlJQMCbOHP6c9iSZs+UnGYCdbnSo1CZI5F64kn0p1KnTH02nSoV3dGTV7FFHVqVq1dtWcMmVQZTbNGu72zqXMuW7danVL+6e4t1bEy6MeueBYLXrNO5Ze36jQtWsOG97wIj1vt3St/DjTEORss4nNq2mDP3e7w4r1bFkSET5hy6s2TRlD2/mSxXtSHQhCunXo26NevCpmvD/UU6tuullzULH76q92zdZG/Ltv1a+W+osI/nRmyc+fRi1Xdbh+68+0vv10dH3+77KD/i6IdnX669/frn5Zsjh4/2PXju8+8bzc9/6fj27LFnX11/+IUnXWl7BJfegm79FyB9JOl3oHgSklefgxAC+FmFGpqHIYcCfkhgfCohSKKJVo044YUMttggiBkmp6KFXw1oII24oYhjiDByaKOOHcp3Y5BD/njikSkO+eBREQAAOw==",
        CLEAR_BACKGROUND_COLOR: "lightgray",
        NODE_TITLE_COLOR: "#222",
        NODE_SELECTED_TITLE_COLOR: "#000",
        NODE_TEXT_SIZE: 14,
        NODE_TEXT_COLOR: "#444",
        NODE_SUBTEXT_SIZE: 12,
        NODE_DEFAULT_COLOR: "#F7F7F7",
        NODE_DEFAULT_BGCOLOR: "#F5F5F5",
        NODE_DEFAULT_BOXCOLOR: "#CCC",
        NODE_DEFAULT_SHAPE: "box",
        NODE_BOX_OUTLINE_COLOR: "#000",
        DEFAULT_SHADOW_COLOR: "rgba(0,0,0,0.1)",
        DEFAULT_GROUP_FONT: 24,
        WIDGET_BGCOLOR: "#D4D4D4",
        WIDGET_OUTLINE_COLOR: "#999",
        WIDGET_TEXT_COLOR: "#222",
        WIDGET_SECONDARY_TEXT_COLOR: "#555",
        LINK_COLOR: "#4CAF50",
        EVENT_LINK_COLOR: "#FF9800",
        CONNECTING_LINK_COLOR: "#2196F3"
      },
      comfy_base: {
        "fg-color": "#222",
        "bg-color": "#DDD",
        "comfy-menu-bg": "#F5F5F5",
        "comfy-input-bg": "#C9C9C9",
        "input-text": "#222",
        "descrip-text": "#444",
        "drag-text": "#555",
        "error-text": "#F44336",
        "border-color": "#888",
        "tr-even-bg-color": "#f9f9f9",
        "tr-odd-bg-color": "#fff",
        "content-bg": "#e0e0e0",
        "content-fg": "#222",
        "content-hover-bg": "#adadad",
        "content-hover-fg": "#222"
      }
    }
  },
  solarized: {
    id: "solarized",
    name: "Solarized",
    colors: {
      node_slot: {
        CLIP: "#2AB7CA",
        // light blue
        CLIP_VISION: "#6c71c4",
        // blue violet
        CLIP_VISION_OUTPUT: "#859900",
        // olive green
        CONDITIONING: "#d33682",
        // magenta
        CONTROL_NET: "#d1ffd7",
        // light mint green
        IMAGE: "#5940bb",
        // deep blue violet
        LATENT: "#268bd2",
        // blue
        MASK: "#CCC9E7",
        // light purple-gray
        MODEL: "#dc322f",
        // red
        STYLE_MODEL: "#1a998a",
        // teal
        UPSCALE_MODEL: "#054A29",
        // dark green
        VAE: "#facfad"
        // light pink-orange
      },
      litegraph_base: {
        NODE_TITLE_COLOR: "#fdf6e3",
        // Base3
        NODE_SELECTED_TITLE_COLOR: "#A9D400",
        NODE_TEXT_SIZE: 14,
        NODE_TEXT_COLOR: "#657b83",
        // Base00
        NODE_SUBTEXT_SIZE: 12,
        NODE_DEFAULT_COLOR: "#094656",
        NODE_DEFAULT_BGCOLOR: "#073642",
        // Base02
        NODE_DEFAULT_BOXCOLOR: "#839496",
        // Base0
        NODE_DEFAULT_SHAPE: "box",
        NODE_BOX_OUTLINE_COLOR: "#fdf6e3",
        // Base3
        DEFAULT_SHADOW_COLOR: "rgba(0,0,0,0.5)",
        DEFAULT_GROUP_FONT: 24,
        WIDGET_BGCOLOR: "#002b36",
        // Base03
        WIDGET_OUTLINE_COLOR: "#839496",
        // Base0
        WIDGET_TEXT_COLOR: "#fdf6e3",
        // Base3
        WIDGET_SECONDARY_TEXT_COLOR: "#93a1a1",
        // Base1
        LINK_COLOR: "#2aa198",
        // Solarized Cyan
        EVENT_LINK_COLOR: "#268bd2",
        // Solarized Blue
        CONNECTING_LINK_COLOR: "#859900"
        // Solarized Green
      },
      comfy_base: {
        "fg-color": "#fdf6e3",
        // Base3
        "bg-color": "#002b36",
        // Base03
        "comfy-menu-bg": "#073642",
        // Base02
        "comfy-input-bg": "#002b36",
        // Base03
        "input-text": "#93a1a1",
        // Base1
        "descrip-text": "#586e75",
        // Base01
        "drag-text": "#839496",
        // Base0
        "error-text": "#dc322f",
        // Solarized Red
        "border-color": "#657b83",
        // Base00
        "tr-even-bg-color": "#002b36",
        "tr-odd-bg-color": "#073642",
        "content-bg": "#657b83",
        "content-fg": "#fdf6e3",
        "content-hover-bg": "#002b36",
        "content-hover-fg": "#fdf6e3"
      }
    }
  },
  arc: {
    id: "arc",
    name: "Arc",
    colors: {
      node_slot: {
        BOOLEAN: "",
        CLIP: "#eacb8b",
        CLIP_VISION: "#A8DADC",
        CLIP_VISION_OUTPUT: "#ad7452",
        CONDITIONING: "#cf876f",
        CONTROL_NET: "#00d78d",
        CONTROL_NET_WEIGHTS: "",
        FLOAT: "",
        GLIGEN: "",
        IMAGE: "#80a1c0",
        IMAGEUPLOAD: "",
        INT: "",
        LATENT: "#b38ead",
        LATENT_KEYFRAME: "",
        MASK: "#a3bd8d",
        MODEL: "#8978a7",
        SAMPLER: "",
        SIGMAS: "",
        STRING: "",
        STYLE_MODEL: "#C2FFAE",
        T2I_ADAPTER_WEIGHTS: "",
        TAESD: "#DCC274",
        TIMESTEP_KEYFRAME: "",
        UPSCALE_MODEL: "",
        VAE: "#be616b"
      },
      litegraph_base: {
        BACKGROUND_IMAGE: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwEAmpwYAAABcklEQVR4nO3YMUoDARgF4RfxBqZI6/0vZqFn0MYtrLIQMFN8U6V4LAtD+Jm9XG/v30OGl2e/AP7yevz4+vx45nvgF/+QGITEICQGITEIiUFIjNNC3q43u3/YnRJyPOzeQ+0e220nhRzReC8e7R7bbdvl+Jal1Bs46jEIiUFIDEJiEBKDkBhKPbZT6qHdptRTu02p53DUYxASg5AYhMQgJAYhMZR6bKfUQ7tNqad2m1LP4ajHICQGITEIiUFIDEJiKPXYTqmHdptST+02pZ7DUY9BSAxCYhASg5AYhMRQ6rGdUg/tNqWe2m1KPYejHoOQGITEICQGITEIiaHUYzulHtptSj2125R6Dkc9BiExCIlBSAxCYhASQ6nHdko9tNuUemq3KfUcjnoMQmIQEoOQGITEICSGUo/tlHpotyn11G5T6jkc9RiExCAkBiExCIlBSAylHtsp9dBuU+qp3abUczjqMQiJQUgMQmIQEoOQGITE+AHFISNQrFTGuwAAAABJRU5ErkJggg==",
        CLEAR_BACKGROUND_COLOR: "#2b2f38",
        NODE_TITLE_COLOR: "#b2b7bd",
        NODE_SELECTED_TITLE_COLOR: "#FFF",
        NODE_TEXT_SIZE: 14,
        NODE_TEXT_COLOR: "#AAA",
        NODE_SUBTEXT_SIZE: 12,
        NODE_DEFAULT_COLOR: "#2b2f38",
        NODE_DEFAULT_BGCOLOR: "#242730",
        NODE_DEFAULT_BOXCOLOR: "#6e7581",
        NODE_DEFAULT_SHAPE: "box",
        NODE_BOX_OUTLINE_COLOR: "#FFF",
        DEFAULT_SHADOW_COLOR: "rgba(0,0,0,0.5)",
        DEFAULT_GROUP_FONT: 22,
        WIDGET_BGCOLOR: "#2b2f38",
        WIDGET_OUTLINE_COLOR: "#6e7581",
        WIDGET_TEXT_COLOR: "#DDD",
        WIDGET_SECONDARY_TEXT_COLOR: "#b2b7bd",
        LINK_COLOR: "#9A9",
        EVENT_LINK_COLOR: "#A86",
        CONNECTING_LINK_COLOR: "#AFA"
      },
      comfy_base: {
        "fg-color": "#fff",
        "bg-color": "#2b2f38",
        "comfy-menu-bg": "#242730",
        "comfy-input-bg": "#2b2f38",
        "input-text": "#ddd",
        "descrip-text": "#b2b7bd",
        "drag-text": "#ccc",
        "error-text": "#ff4444",
        "border-color": "#6e7581",
        "tr-even-bg-color": "#2b2f38",
        "tr-odd-bg-color": "#242730",
        "content-bg": "#6e7581",
        "content-fg": "#fff",
        "content-hover-bg": "#2b2f38",
        "content-hover-fg": "#fff"
      }
    }
  },
  nord: {
    id: "nord",
    name: "Nord",
    colors: {
      node_slot: {
        BOOLEAN: "",
        CLIP: "#eacb8b",
        CLIP_VISION: "#A8DADC",
        CLIP_VISION_OUTPUT: "#ad7452",
        CONDITIONING: "#cf876f",
        CONTROL_NET: "#00d78d",
        CONTROL_NET_WEIGHTS: "",
        FLOAT: "",
        GLIGEN: "",
        IMAGE: "#80a1c0",
        IMAGEUPLOAD: "",
        INT: "",
        LATENT: "#b38ead",
        LATENT_KEYFRAME: "",
        MASK: "#a3bd8d",
        MODEL: "#8978a7",
        SAMPLER: "",
        SIGMAS: "",
        STRING: "",
        STYLE_MODEL: "#C2FFAE",
        T2I_ADAPTER_WEIGHTS: "",
        TAESD: "#DCC274",
        TIMESTEP_KEYFRAME: "",
        UPSCALE_MODEL: "",
        VAE: "#be616b"
      },
      litegraph_base: {
        BACKGROUND_IMAGE: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFu2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4xLWMwMDEgNzkuMTQ2Mjg5OSwgMjAyMy8wNi8yNS0yMDowMTo1NSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDI1LjEgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyMy0xMS0xM1QwMDoxODowMiswMTowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjMtMTEtMTVUMDE6MjA6NDUrMDE6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjMtMTEtMTVUMDE6MjA6NDUrMDE6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjUwNDFhMmZjLTEzNzQtMTk0ZC1hZWY4LTYxMzM1MTVmNjUwMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoyMzFiMTBiMC1iNGZiLTAyNGUtYjEyZS0zMDUzMDNjZDA3YzgiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoyMzFiMTBiMC1iNGZiLTAyNGUtYjEyZS0zMDUzMDNjZDA3YzgiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjIzMWIxMGIwLWI0ZmItMDI0ZS1iMTJlLTMwNTMwM2NkMDdjOCIgc3RFdnQ6d2hlbj0iMjAyMy0xMS0xM1QwMDoxODowMiswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDI1LjEgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo1MDQxYTJmYy0xMzc0LTE5NGQtYWVmOC02MTMzNTE1ZjY1MDAiIHN0RXZ0OndoZW49IjIwMjMtMTEtMTVUMDE6MjA6NDUrMDE6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyNS4xIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz73jWg/AAAAyUlEQVR42u3WKwoAIBRFQRdiMb1idv9Lsxn9gEFw4Dbb8JCTojbbXEJwjJVL2HKwYMGCBQuWLbDmjr+9zrBGjHl1WVcvy2DBggULFizTWQpewSt4HzwsgwULFiwFr7MUvMtS8D54WLBgGSxYCl7BK3iXZbBgwYIFC5bpLAWv4BW8Dx6WwYIFC5aC11kK3mUpeB88LFiwDBYsBa/gFbzLMliwYMGCBct0loJX8AreBw/LYMGCBUvB6ywF77IUvA8eFixYBgsWrNfWAZPltufdad+1AAAAAElFTkSuQmCC",
        CLEAR_BACKGROUND_COLOR: "#212732",
        NODE_TITLE_COLOR: "#999",
        NODE_SELECTED_TITLE_COLOR: "#e5eaf0",
        NODE_TEXT_SIZE: 14,
        NODE_TEXT_COLOR: "#bcc2c8",
        NODE_SUBTEXT_SIZE: 12,
        NODE_DEFAULT_COLOR: "#2e3440",
        NODE_DEFAULT_BGCOLOR: "#161b22",
        NODE_DEFAULT_BOXCOLOR: "#545d70",
        NODE_DEFAULT_SHAPE: "box",
        NODE_BOX_OUTLINE_COLOR: "#e5eaf0",
        DEFAULT_SHADOW_COLOR: "rgba(0,0,0,0.5)",
        DEFAULT_GROUP_FONT: 24,
        WIDGET_BGCOLOR: "#2e3440",
        WIDGET_OUTLINE_COLOR: "#545d70",
        WIDGET_TEXT_COLOR: "#bcc2c8",
        WIDGET_SECONDARY_TEXT_COLOR: "#999",
        LINK_COLOR: "#9A9",
        EVENT_LINK_COLOR: "#A86",
        CONNECTING_LINK_COLOR: "#AFA"
      },
      comfy_base: {
        "fg-color": "#e5eaf0",
        "bg-color": "#2e3440",
        "comfy-menu-bg": "#161b22",
        "comfy-input-bg": "#2e3440",
        "input-text": "#bcc2c8",
        "descrip-text": "#999",
        "drag-text": "#ccc",
        "error-text": "#ff4444",
        "border-color": "#545d70",
        "tr-even-bg-color": "#2e3440",
        "tr-odd-bg-color": "#161b22",
        "content-bg": "#545d70",
        "content-fg": "#e5eaf0",
        "content-hover-bg": "#2e3440",
        "content-hover-fg": "#e5eaf0"
      }
    }
  },
  github: {
    id: "github",
    name: "Github",
    colors: {
      node_slot: {
        BOOLEAN: "",
        CLIP: "#eacb8b",
        CLIP_VISION: "#A8DADC",
        CLIP_VISION_OUTPUT: "#ad7452",
        CONDITIONING: "#cf876f",
        CONTROL_NET: "#00d78d",
        CONTROL_NET_WEIGHTS: "",
        FLOAT: "",
        GLIGEN: "",
        IMAGE: "#80a1c0",
        IMAGEUPLOAD: "",
        INT: "",
        LATENT: "#b38ead",
        LATENT_KEYFRAME: "",
        MASK: "#a3bd8d",
        MODEL: "#8978a7",
        SAMPLER: "",
        SIGMAS: "",
        STRING: "",
        STYLE_MODEL: "#C2FFAE",
        T2I_ADAPTER_WEIGHTS: "",
        TAESD: "#DCC274",
        TIMESTEP_KEYFRAME: "",
        UPSCALE_MODEL: "",
        VAE: "#be616b"
      },
      litegraph_base: {
        BACKGROUND_IMAGE: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGlmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4xLWMwMDEgNzkuMTQ2Mjg5OSwgMjAyMy8wNi8yNS0yMDowMTo1NSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDI1LjEgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyMy0xMS0xM1QwMDoxODowMiswMTowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjMtMTEtMTVUMDI6MDQ6NTkrMDE6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjMtMTEtMTVUMDI6MDQ6NTkrMDE6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmIyYzRhNjA5LWJmYTctYTg0MC1iOGFlLTk3MzE2ZjM1ZGIyNyIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjk0ZmNlZGU4LTE1MTctZmQ0MC04ZGU3LWYzOTgxM2E3ODk5ZiIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjIzMWIxMGIwLWI0ZmItMDI0ZS1iMTJlLTMwNTMwM2NkMDdjOCI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MjMxYjEwYjAtYjRmYi0wMjRlLWIxMmUtMzA1MzAzY2QwN2M4IiBzdEV2dDp3aGVuPSIyMDIzLTExLTEzVDAwOjE4OjAyKzAxOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjUuMSAoV2luZG93cykiLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjQ4OWY1NzlmLTJkNjUtZWQ0Zi04OTg0LTA4NGE2MGE1ZTMzNSIgc3RFdnQ6d2hlbj0iMjAyMy0xMS0xNVQwMjowNDo1OSswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDI1LjEgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpiMmM0YTYwOS1iZmE3LWE4NDAtYjhhZS05NzMxNmYzNWRiMjciIHN0RXZ0OndoZW49IjIwMjMtMTEtMTVUMDI6MDQ6NTkrMDE6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyNS4xIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4OTe6GAAAAx0lEQVR42u3WMQoAIQxFwRzJys77X8vSLiRgITif7bYbgrwYc/mKXyBoY4VVBgsWLFiwYFmOlTv+9jfDOjHmr8u6eVkGCxYsWLBgmc5S8ApewXvgYRksWLBgKXidpeBdloL3wMOCBctgwVLwCl7BuyyDBQsWLFiwTGcpeAWv4D3wsAwWLFiwFLzOUvAuS8F74GHBgmWwYCl4Ba/gXZbBggULFixYprMUvIJX8B54WAYLFixYCl5nKXiXpeA98LBgwTJYsGC9tg1o8f4TTtqzNQAAAABJRU5ErkJggg==",
        CLEAR_BACKGROUND_COLOR: "#040506",
        NODE_TITLE_COLOR: "#999",
        NODE_SELECTED_TITLE_COLOR: "#e5eaf0",
        NODE_TEXT_SIZE: 14,
        NODE_TEXT_COLOR: "#bcc2c8",
        NODE_SUBTEXT_SIZE: 12,
        NODE_DEFAULT_COLOR: "#161b22",
        NODE_DEFAULT_BGCOLOR: "#13171d",
        NODE_DEFAULT_BOXCOLOR: "#30363d",
        NODE_DEFAULT_SHAPE: "box",
        NODE_BOX_OUTLINE_COLOR: "#e5eaf0",
        DEFAULT_SHADOW_COLOR: "rgba(0,0,0,0.5)",
        DEFAULT_GROUP_FONT: 24,
        WIDGET_BGCOLOR: "#161b22",
        WIDGET_OUTLINE_COLOR: "#30363d",
        WIDGET_TEXT_COLOR: "#bcc2c8",
        WIDGET_SECONDARY_TEXT_COLOR: "#999",
        LINK_COLOR: "#9A9",
        EVENT_LINK_COLOR: "#A86",
        CONNECTING_LINK_COLOR: "#AFA"
      },
      comfy_base: {
        "fg-color": "#e5eaf0",
        "bg-color": "#161b22",
        "comfy-menu-bg": "#13171d",
        "comfy-input-bg": "#161b22",
        "input-text": "#bcc2c8",
        "descrip-text": "#999",
        "drag-text": "#ccc",
        "error-text": "#ff4444",
        "border-color": "#30363d",
        "tr-even-bg-color": "#161b22",
        "tr-odd-bg-color": "#13171d",
        "content-bg": "#30363d",
        "content-fg": "#e5eaf0",
        "content-hover-bg": "#161b22",
        "content-hover-fg": "#e5eaf0"
      }
    }
  }
};
const id$4 = "Comfy.ColorPalette";
const idCustomColorPalettes = "Comfy.CustomColorPalettes";
const defaultColorPaletteId = "dark";
const els = {
  select: null
};
app.registerExtension({
  name: id$4,
  init() {
    LGraphCanvas.prototype.updateBackground = function(image, clearBackgroundColor) {
      this._bg_img = new Image();
      this._bg_img.name = image;
      this._bg_img.src = image;
      this._bg_img.onload = () => {
        this.draw(true, true);
      };
      this.background_image = image;
      this.clear_background = true;
      this.clear_background_color = clearBackgroundColor;
      this._pattern = null;
    };
  },
  addCustomNodeDefs(node_defs) {
    const sortObjectKeys = /* @__PURE__ */ __name((unordered) => {
      return Object.keys(unordered).sort().reduce((obj, key) => {
        obj[key] = unordered[key];
        return obj;
      }, {});
    }, "sortObjectKeys");
    function getSlotTypes() {
      var types = [];
      const defs = node_defs;
      for (const nodeId in defs) {
        const nodeData = defs[nodeId];
        var inputs = nodeData["input"]["required"];
        if (nodeData["input"]["optional"] !== void 0) {
          inputs = Object.assign(
            {},
            nodeData["input"]["required"],
            nodeData["input"]["optional"]
          );
        }
        for (const inputName in inputs) {
          const inputData = inputs[inputName];
          const type = inputData[0];
          if (!Array.isArray(type)) {
            types.push(type);
          }
        }
        for (const o in nodeData["output"]) {
          const output = nodeData["output"][o];
          types.push(output);
        }
      }
      return types;
    }
    __name(getSlotTypes, "getSlotTypes");
    function completeColorPalette(colorPalette) {
      var types = getSlotTypes();
      for (const type of types) {
        if (!colorPalette.colors.node_slot[type]) {
          colorPalette.colors.node_slot[type] = "";
        }
      }
      colorPalette.colors.node_slot = sortObjectKeys(
        colorPalette.colors.node_slot
      );
      return colorPalette;
    }
    __name(completeColorPalette, "completeColorPalette");
    const getColorPaletteTemplate = /* @__PURE__ */ __name(() => __async(this, null, function* () {
      let colorPalette = {
        id: "my_color_palette_unique_id",
        name: "My Color Palette",
        colors: {
          node_slot: {},
          litegraph_base: {},
          comfy_base: {}
        }
      };
      const defaultColorPalette = colorPalettes[defaultColorPaletteId];
      for (const key in defaultColorPalette.colors.litegraph_base) {
        if (!colorPalette.colors.litegraph_base[key]) {
          colorPalette.colors.litegraph_base[key] = "";
        }
      }
      for (const key in defaultColorPalette.colors.comfy_base) {
        if (!colorPalette.colors.comfy_base[key]) {
          colorPalette.colors.comfy_base[key] = "";
        }
      }
      return completeColorPalette(colorPalette);
    }), "getColorPaletteTemplate");
    const getCustomColorPalettes = /* @__PURE__ */ __name(() => {
      return app.ui.settings.getSettingValue(idCustomColorPalettes, {});
    }, "getCustomColorPalettes");
    const setCustomColorPalettes = /* @__PURE__ */ __name((customColorPalettes) => {
      return app.ui.settings.setSettingValue(
        idCustomColorPalettes,
        customColorPalettes
      );
    }, "setCustomColorPalettes");
    const addCustomColorPalette = /* @__PURE__ */ __name((colorPalette) => __async(this, null, function* () {
      if (typeof colorPalette !== "object") {
        alert("Invalid color palette.");
        return;
      }
      if (!colorPalette.id) {
        alert("Color palette missing id.");
        return;
      }
      if (!colorPalette.name) {
        alert("Color palette missing name.");
        return;
      }
      if (!colorPalette.colors) {
        alert("Color palette missing colors.");
        return;
      }
      if (colorPalette.colors.node_slot && typeof colorPalette.colors.node_slot !== "object") {
        alert("Invalid color palette colors.node_slot.");
        return;
      }
      const customColorPalettes = getCustomColorPalettes();
      customColorPalettes[colorPalette.id] = colorPalette;
      setCustomColorPalettes(customColorPalettes);
      for (const option of els.select.childNodes) {
        if (option.value === "custom_" + colorPalette.id) {
          els.select.removeChild(option);
        }
      }
      els.select.append(
        $el("option", {
          textContent: colorPalette.name + " (custom)",
          value: "custom_" + colorPalette.id,
          selected: true
        })
      );
      setColorPalette("custom_" + colorPalette.id);
      yield loadColorPalette(colorPalette);
    }), "addCustomColorPalette");
    const deleteCustomColorPalette = /* @__PURE__ */ __name((colorPaletteId) => __async(this, null, function* () {
      const customColorPalettes = getCustomColorPalettes();
      delete customColorPalettes[colorPaletteId];
      setCustomColorPalettes(customColorPalettes);
      for (const opt of els.select.childNodes) {
        const option = opt;
        if (option.value === defaultColorPaletteId) {
          option.selected = true;
        }
        if (option.value === "custom_" + colorPaletteId) {
          els.select.removeChild(option);
        }
      }
      setColorPalette(defaultColorPaletteId);
      yield loadColorPalette(getColorPalette());
    }), "deleteCustomColorPalette");
    const loadColorPalette = /* @__PURE__ */ __name((colorPalette) => __async(this, null, function* () {
      colorPalette = yield completeColorPalette(colorPalette);
      if (colorPalette.colors) {
        if (colorPalette.colors.node_slot) {
          Object.assign(
            // @ts-expect-error
            app.canvas.default_connection_color_byType,
            colorPalette.colors.node_slot
          );
          Object.assign(
            LGraphCanvas.link_type_colors,
            colorPalette.colors.node_slot
          );
        }
        if (colorPalette.colors.litegraph_base) {
          app.canvas.node_title_color = colorPalette.colors.litegraph_base.NODE_TITLE_COLOR;
          app.canvas.default_link_color = colorPalette.colors.litegraph_base.LINK_COLOR;
          for (const key in colorPalette.colors.litegraph_base) {
            if (colorPalette.colors.litegraph_base.hasOwnProperty(key) && LiteGraph.hasOwnProperty(key)) {
              LiteGraph[key] = colorPalette.colors.litegraph_base[key];
            }
          }
        }
        if (colorPalette.colors.comfy_base) {
          const rootStyle = document.documentElement.style;
          for (const key in colorPalette.colors.comfy_base) {
            rootStyle.setProperty(
              "--" + key,
              colorPalette.colors.comfy_base[key]
            );
          }
        }
        app.canvas.draw(true, true);
      }
    }), "loadColorPalette");
    const getColorPalette = /* @__PURE__ */ __name((colorPaletteId) => {
      if (!colorPaletteId) {
        colorPaletteId = app.ui.settings.getSettingValue(
          id$4,
          defaultColorPaletteId
        );
      }
      if (colorPaletteId.startsWith("custom_")) {
        colorPaletteId = colorPaletteId.substr(7);
        let customColorPalettes = getCustomColorPalettes();
        if (customColorPalettes[colorPaletteId]) {
          return customColorPalettes[colorPaletteId];
        }
      }
      return colorPalettes[colorPaletteId];
    }, "getColorPalette");
    const setColorPalette = /* @__PURE__ */ __name((colorPaletteId) => {
      app.ui.settings.setSettingValue(id$4, colorPaletteId);
    }, "setColorPalette");
    const fileInput = $el("input", {
      type: "file",
      accept: ".json",
      style: { display: "none" },
      parent: document.body,
      onchange: /* @__PURE__ */ __name(() => {
        const file2 = fileInput.files[0];
        if (file2.type === "application/json" || file2.name.endsWith(".json")) {
          const reader = new FileReader();
          reader.onload = () => __async(this, null, function* () {
            yield addCustomColorPalette(JSON.parse(reader.result));
          });
          reader.readAsText(file2);
        }
      }, "onchange")
    });
    app.ui.settings.addSetting({
      id: id$4,
      category: ["Comfy", "ColorPalette"],
      name: "Color Palette",
      type: /* @__PURE__ */ __name((name, setter, value) => {
        const options = [
          ...Object.values(colorPalettes).map(
            (c) => $el("option", {
              textContent: c.name,
              value: c.id,
              selected: c.id === value
            })
          ),
          ...Object.values(getCustomColorPalettes()).map(
            (c) => $el("option", {
              textContent: `${c.name} (custom)`,
              value: `custom_${c.id}`,
              selected: `custom_${c.id}` === value
            })
          )
        ];
        els.select = $el(
          "select",
          {
            style: {
              marginBottom: "0.15rem",
              width: "100%"
            },
            onchange: /* @__PURE__ */ __name((e) => {
              setter(e.target.value);
            }, "onchange")
          },
          options
        );
        return $el("tr", [
          $el("td", [
            els.select,
            $el(
              "div",
              {
                style: {
                  display: "grid",
                  gap: "4px",
                  gridAutoFlow: "column"
                }
              },
              [
                $el("input", {
                  type: "button",
                  value: "Export",
                  onclick: /* @__PURE__ */ __name(() => __async(this, null, function* () {
                    const colorPaletteId = app.ui.settings.getSettingValue(
                      id$4,
                      defaultColorPaletteId
                    );
                    const colorPalette = yield completeColorPalette(
                      getColorPalette(colorPaletteId)
                    );
                    const json = JSON.stringify(colorPalette, null, 2);
                    const blob = new Blob([json], { type: "application/json" });
                    const url = URL.createObjectURL(blob);
                    const a = $el("a", {
                      href: url,
                      download: colorPaletteId + ".json",
                      style: { display: "none" },
                      parent: document.body
                    });
                    a.click();
                    setTimeout(function() {
                      a.remove();
                      window.URL.revokeObjectURL(url);
                    }, 0);
                  }), "onclick")
                }),
                $el("input", {
                  type: "button",
                  value: "Import",
                  onclick: /* @__PURE__ */ __name(() => {
                    fileInput.click();
                  }, "onclick")
                }),
                $el("input", {
                  type: "button",
                  value: "Template",
                  onclick: /* @__PURE__ */ __name(() => __async(this, null, function* () {
                    const colorPalette = yield getColorPaletteTemplate();
                    const json = JSON.stringify(colorPalette, null, 2);
                    const blob = new Blob([json], { type: "application/json" });
                    const url = URL.createObjectURL(blob);
                    const a = $el("a", {
                      href: url,
                      download: "color_palette.json",
                      style: { display: "none" },
                      parent: document.body
                    });
                    a.click();
                    setTimeout(function() {
                      a.remove();
                      window.URL.revokeObjectURL(url);
                    }, 0);
                  }), "onclick")
                }),
                $el("input", {
                  type: "button",
                  value: "Delete",
                  onclick: /* @__PURE__ */ __name(() => __async(this, null, function* () {
                    let colorPaletteId = app.ui.settings.getSettingValue(
                      id$4,
                      defaultColorPaletteId
                    );
                    if (colorPalettes[colorPaletteId]) {
                      alert("You cannot delete a built-in color palette.");
                      return;
                    }
                    if (colorPaletteId.startsWith("custom_")) {
                      colorPaletteId = colorPaletteId.substr(7);
                    }
                    yield deleteCustomColorPalette(colorPaletteId);
                  }), "onclick")
                })
              ]
            )
          ])
        ]);
      }, "type"),
      defaultValue: defaultColorPaletteId,
      onChange(value) {
        return __async(this, null, function* () {
          if (!value) {
            return;
          }
          let palette = colorPalettes[value];
          if (palette) {
            yield loadColorPalette(palette);
          } else if (value.startsWith("custom_")) {
            value = value.substr(7);
            let customColorPalettes = getCustomColorPalettes();
            if (customColorPalettes[value]) {
              palette = customColorPalettes[value];
              yield loadColorPalette(customColorPalettes[value]);
            }
          }
          let { BACKGROUND_IMAGE, CLEAR_BACKGROUND_COLOR } = palette.colors.litegraph_base;
          if (BACKGROUND_IMAGE === void 0 || CLEAR_BACKGROUND_COLOR === void 0) {
            const base = colorPalettes["dark"].colors.litegraph_base;
            BACKGROUND_IMAGE = base.BACKGROUND_IMAGE;
            CLEAR_BACKGROUND_COLOR = base.CLEAR_BACKGROUND_COLOR;
          }
          app.canvas.updateBackground(BACKGROUND_IMAGE, CLEAR_BACKGROUND_COLOR);
        });
      }
    });
  }
});
const ext$2 = {
  name: "Comfy.ContextMenuFilter",
  init() {
    const ctxMenu = LiteGraph.ContextMenu;
    LiteGraph.ContextMenu = function(values, options) {
      const ctx = ctxMenu.call(this, values, options);
      if ((options == null ? void 0 : options.className) === "dark" && (values == null ? void 0 : values.length) > 10) {
        const filter = document.createElement("input");
        filter.classList.add("comfy-context-menu-filter");
        filter.placeholder = "Filter list";
        this.root.prepend(filter);
        const items = Array.from(
          this.root.querySelectorAll(".litemenu-entry")
        );
        let displayedItems = [...items];
        let itemCount = displayedItems.length;
        requestAnimationFrame(() => {
          var _a, _b;
          const currentNode = LGraphCanvas.active_canvas.current_node;
          const clickedComboValue = (_b = (_a = currentNode.widgets) == null ? void 0 : _a.filter(
            (w) => w.type === "combo" && w.options.values.length === values.length
          ).find(
            (w) => w.options.values.every((v, i) => v === values[i])
          )) == null ? void 0 : _b.value;
          let selectedIndex = clickedComboValue ? values.findIndex((v) => v === clickedComboValue) : 0;
          if (selectedIndex < 0) {
            selectedIndex = 0;
          }
          let selectedItem = displayedItems[selectedIndex];
          updateSelected();
          function updateSelected() {
            selectedItem == null ? void 0 : selectedItem.style.setProperty("background-color", "");
            selectedItem == null ? void 0 : selectedItem.style.setProperty("color", "");
            selectedItem = displayedItems[selectedIndex];
            selectedItem == null ? void 0 : selectedItem.style.setProperty(
              "background-color",
              "#ccc",
              "important"
            );
            selectedItem == null ? void 0 : selectedItem.style.setProperty("color", "#000", "important");
          }
          __name(updateSelected, "updateSelected");
          const positionList = /* @__PURE__ */ __name(() => {
            const rect = this.root.getBoundingClientRect();
            if (rect.top < 0) {
              const scale = 1 - this.root.getBoundingClientRect().height / this.root.clientHeight;
              const shift = this.root.clientHeight * scale / 2;
              this.root.style.top = -shift + "px";
            }
          }, "positionList");
          filter.addEventListener("keydown", (event) => {
            switch (event.key) {
              case "ArrowUp":
                event.preventDefault();
                if (selectedIndex === 0) {
                  selectedIndex = itemCount - 1;
                } else {
                  selectedIndex--;
                }
                updateSelected();
                break;
              case "ArrowRight":
                event.preventDefault();
                selectedIndex = itemCount - 1;
                updateSelected();
                break;
              case "ArrowDown":
                event.preventDefault();
                if (selectedIndex === itemCount - 1) {
                  selectedIndex = 0;
                } else {
                  selectedIndex++;
                }
                updateSelected();
                break;
              case "ArrowLeft":
                event.preventDefault();
                selectedIndex = 0;
                updateSelected();
                break;
              case "Enter":
                selectedItem == null ? void 0 : selectedItem.click();
                break;
              case "Escape":
                this.close();
                break;
            }
          });
          filter.addEventListener("input", () => {
            const term = filter.value.toLocaleLowerCase();
            displayedItems = items.filter((item) => {
              const isVisible = !term || item.textContent.toLocaleLowerCase().includes(term);
              item.style.display = isVisible ? "block" : "none";
              return isVisible;
            });
            selectedIndex = 0;
            if (displayedItems.includes(selectedItem)) {
              selectedIndex = displayedItems.findIndex(
                (d) => d === selectedItem
              );
            }
            itemCount = displayedItems.length;
            updateSelected();
            if (options.event) {
              let top = options.event.clientY - 10;
              const bodyRect = document.body.getBoundingClientRect();
              const rootRect = this.root.getBoundingClientRect();
              if (bodyRect.height && top > bodyRect.height - rootRect.height - 10) {
                top = Math.max(0, bodyRect.height - rootRect.height - 10);
              }
              this.root.style.top = top + "px";
              positionList();
            }
          });
          requestAnimationFrame(() => {
            filter.focus();
            positionList();
          });
        });
      }
      return ctx;
    };
    LiteGraph.ContextMenu.prototype = ctxMenu.prototype;
  }
};
app.registerExtension(ext$2);
function stripComments(str) {
  return str.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, "");
}
__name(stripComments, "stripComments");
app.registerExtension({
  name: "Comfy.DynamicPrompts",
  nodeCreated(node) {
    if (node.widgets) {
      const widgets = node.widgets.filter((n) => n.dynamicPrompts);
      for (const widget of widgets) {
        widget.serializeValue = (workflowNode, widgetIndex) => {
          let prompt2 = stripComments(widget.value);
          while (prompt2.replace("\\{", "").includes("{") && prompt2.replace("\\}", "").includes("}")) {
            const startIndex = prompt2.replace("\\{", "00").indexOf("{");
            const endIndex = prompt2.replace("\\}", "00").indexOf("}");
            const optionsString = prompt2.substring(startIndex + 1, endIndex);
            const options = optionsString.split("|");
            const randomIndex = Math.floor(Math.random() * options.length);
            const randomOption = options[randomIndex];
            prompt2 = prompt2.substring(0, startIndex) + randomOption + prompt2.substring(endIndex + 1);
          }
          if (workflowNode == null ? void 0 : workflowNode.widgets_values)
            workflowNode.widgets_values[widgetIndex] = prompt2;
          return prompt2;
        };
      }
    }
  }
});
app.registerExtension({
  name: "Comfy.EditAttention",
  init() {
    const editAttentionDelta = app.ui.settings.addSetting({
      id: "Comfy.EditAttention.Delta",
      name: "Ctrl+up/down precision",
      type: "slider",
      attrs: {
        min: 0.01,
        max: 0.5,
        step: 0.01
      },
      defaultValue: 0.05
    });
    function incrementWeight(weight, delta) {
      const floatWeight = parseFloat(weight);
      if (isNaN(floatWeight)) return weight;
      const newWeight = floatWeight + delta;
      return String(Number(newWeight.toFixed(10)));
    }
    __name(incrementWeight, "incrementWeight");
    function findNearestEnclosure(text, cursorPos) {
      let start = cursorPos, end = cursorPos;
      let openCount = 0, closeCount = 0;
      while (start >= 0) {
        start--;
        if (text[start] === "(" && openCount === closeCount) break;
        if (text[start] === "(") openCount++;
        if (text[start] === ")") closeCount++;
      }
      if (start < 0) return false;
      openCount = 0;
      closeCount = 0;
      while (end < text.length) {
        if (text[end] === ")" && openCount === closeCount) break;
        if (text[end] === "(") openCount++;
        if (text[end] === ")") closeCount++;
        end++;
      }
      if (end === text.length) return false;
      return { start: start + 1, end };
    }
    __name(findNearestEnclosure, "findNearestEnclosure");
    function addWeightToParentheses(text) {
      const parenRegex = /^\((.*)\)$/;
      const parenMatch = text.match(parenRegex);
      const floatRegex = /:([+-]?(\d*\.)?\d+([eE][+-]?\d+)?)/;
      const floatMatch = text.match(floatRegex);
      if (parenMatch && !floatMatch) {
        return `(${parenMatch[1]}:1.0)`;
      } else {
        return text;
      }
    }
    __name(addWeightToParentheses, "addWeightToParentheses");
    function editAttention(event) {
      const inputField = event.composedPath()[0];
      const delta = parseFloat(editAttentionDelta.value);
      if (inputField.tagName !== "TEXTAREA") return;
      if (!(event.key === "ArrowUp" || event.key === "ArrowDown")) return;
      if (!event.ctrlKey && !event.metaKey) return;
      event.preventDefault();
      let start = inputField.selectionStart;
      let end = inputField.selectionEnd;
      let selectedText = inputField.value.substring(start, end);
      if (!selectedText) {
        const nearestEnclosure = findNearestEnclosure(inputField.value, start);
        if (nearestEnclosure) {
          start = nearestEnclosure.start;
          end = nearestEnclosure.end;
          selectedText = inputField.value.substring(start, end);
        } else {
          const delimiters = " .,\\/!?%^*;:{}=-_`~()\r\n	";
          while (!delimiters.includes(inputField.value[start - 1]) && start > 0) {
            start--;
          }
          while (!delimiters.includes(inputField.value[end]) && end < inputField.value.length) {
            end++;
          }
          selectedText = inputField.value.substring(start, end);
          if (!selectedText) return;
        }
      }
      if (selectedText[selectedText.length - 1] === " ") {
        selectedText = selectedText.substring(0, selectedText.length - 1);
        end -= 1;
      }
      if (inputField.value[start - 1] === "(" && inputField.value[end] === ")") {
        start -= 1;
        end += 1;
        selectedText = inputField.value.substring(start, end);
      }
      if (selectedText[0] !== "(" || selectedText[selectedText.length - 1] !== ")") {
        selectedText = `(${selectedText})`;
      }
      selectedText = addWeightToParentheses(selectedText);
      const weightDelta = event.key === "ArrowUp" ? delta : -delta;
      const updatedText = selectedText.replace(
        /\((.*):([+-]?\d+(?:\.\d+)?)\)/,
        (match, text, weight) => {
          weight = incrementWeight(weight, weightDelta);
          if (weight == 1) {
            return text;
          } else {
            return `(${text}:${weight})`;
          }
        }
      );
      inputField.setRangeText(updatedText, start, end, "select");
    }
    __name(editAttention, "editAttention");
    window.addEventListener("keydown", editAttention);
  }
});
const CONVERTED_TYPE = "converted-widget";
const VALID_TYPES = ["STRING", "combo", "number", "toggle", "BOOLEAN"];
const CONFIG = Symbol();
const GET_CONFIG = Symbol();
const TARGET = Symbol();
const replacePropertyName = "Run widget replace on values";
const _PrimitiveNode = class _PrimitiveNode {
  constructor() {
    __privateAdd(this, _PrimitiveNode_instances);
    __publicField(this, "controlValues");
    __publicField(this, "lastType");
    this.addOutput("connect to widget input", "*");
    this.serialize_widgets = true;
    this.isVirtualNode = true;
    if (!this.properties || !(replacePropertyName in this.properties)) {
      this.addProperty(replacePropertyName, false, "boolean");
    }
  }
  applyToGraph(extraLinks = []) {
    var _a, _b;
    if (!((_a = this.outputs[0].links) == null ? void 0 : _a.length)) return;
    function get_links(node) {
      let links2 = [];
      for (const l of node.outputs[0].links) {
        const linkInfo = app.graph.links[l];
        const n = node.graph.getNodeById(linkInfo.target_id);
        if (n.type == "Reroute") {
          links2 = links2.concat(get_links(n));
        } else {
          links2.push(l);
        }
      }
      return links2;
    }
    __name(get_links, "get_links");
    let links = [
      ...get_links(this).map((l) => app.graph.links[l]),
      ...extraLinks
    ];
    let v = (_b = this.widgets) == null ? void 0 : _b[0].value;
    if (v && this.properties[replacePropertyName]) {
      v = applyTextReplacements(app, v);
    }
    for (const linkInfo of links) {
      const node = this.graph.getNodeById(linkInfo.target_id);
      const input = node.inputs[linkInfo.target_slot];
      let widget;
      if (input.widget[TARGET]) {
        widget = input.widget[TARGET];
      } else {
        const widgetName = input.widget.name;
        if (widgetName) {
          widget = node.widgets.find((w) => w.name === widgetName);
        }
      }
      if (widget) {
        widget.value = v;
        if (widget.callback) {
          widget.callback(
            widget.value,
            app.canvas,
            node,
            app.canvas.graph_mouse,
            {}
          );
        }
      }
    }
  }
  refreshComboInNode() {
    var _a;
    const widget = (_a = this.widgets) == null ? void 0 : _a[0];
    if ((widget == null ? void 0 : widget.type) === "combo") {
      widget.options.values = this.outputs[0].widget[GET_CONFIG]()[0];
      if (!widget.options.values.includes(widget.value)) {
        widget.value = widget.options.values[0];
        widget.callback(widget.value);
      }
    }
  }
  onAfterGraphConfigured() {
    var _a, _b;
    if (((_a = this.outputs[0].links) == null ? void 0 : _a.length) && !((_b = this.widgets) == null ? void 0 : _b.length)) {
      if (!__privateMethod(this, _PrimitiveNode_instances, onFirstConnection_fn).call(this)) return;
      if (this.widgets) {
        for (let i = 0; i < this.widgets_values.length; i++) {
          const w = this.widgets[i];
          if (w) {
            w.value = this.widgets_values[i];
          }
        }
      }
      __privateMethod(this, _PrimitiveNode_instances, mergeWidgetConfig_fn).call(this);
    }
  }
  onConnectionsChange(_, index, connected) {
    var _a;
    if (app.configuringGraph) {
      return;
    }
    const links = this.outputs[0].links;
    if (connected) {
      if ((links == null ? void 0 : links.length) && !((_a = this.widgets) == null ? void 0 : _a.length)) {
        __privateMethod(this, _PrimitiveNode_instances, onFirstConnection_fn).call(this);
      }
    } else {
      __privateMethod(this, _PrimitiveNode_instances, mergeWidgetConfig_fn).call(this);
      if (!(links == null ? void 0 : links.length)) {
        this.onLastDisconnect();
      }
    }
  }
  onConnectOutput(slot, type, input, target_node, target_slot) {
    var _a;
    if (!input.widget) {
      if (!(input.type in ComfyWidgets)) return false;
    }
    if ((_a = this.outputs[slot].links) == null ? void 0 : _a.length) {
      const valid = __privateMethod(this, _PrimitiveNode_instances, isValidConnection_fn).call(this, input);
      if (valid) {
        this.applyToGraph([{ target_id: target_node.id, target_slot }]);
      }
      return valid;
    }
  }
  recreateWidget() {
    var _a, _b, _c;
    const values = (_a = this.widgets) == null ? void 0 : _a.map((w) => w.value);
    __privateMethod(this, _PrimitiveNode_instances, removeWidgets_fn).call(this);
    __privateMethod(this, _PrimitiveNode_instances, onFirstConnection_fn).call(this, true);
    if (values == null ? void 0 : values.length) {
      for (let i = 0; i < ((_b = this.widgets) == null ? void 0 : _b.length); i++)
        this.widgets[i].value = values[i];
    }
    return (_c = this.widgets) == null ? void 0 : _c[0];
  }
  onLastDisconnect() {
    this.outputs[0].type = "*";
    this.outputs[0].name = "connect to widget input";
    delete this.outputs[0].widget;
    __privateMethod(this, _PrimitiveNode_instances, removeWidgets_fn).call(this);
  }
};
_PrimitiveNode_instances = new WeakSet();
onFirstConnection_fn = /* @__PURE__ */ __name(function(recreating) {
  var _a, _b;
  if (!this.outputs[0].links) {
    this.onLastDisconnect();
    return;
  }
  const linkId = this.outputs[0].links[0];
  const link = this.graph.links[linkId];
  if (!link) return;
  const theirNode = this.graph.getNodeById(link.target_id);
  if (!theirNode || !theirNode.inputs) return;
  const input = theirNode.inputs[link.target_slot];
  if (!input) return;
  let widget;
  if (!input.widget) {
    if (!(input.type in ComfyWidgets)) return;
    widget = { name: input.name, [GET_CONFIG]: () => [input.type, {}] };
  } else {
    widget = input.widget;
  }
  const config = (_a = widget[GET_CONFIG]) == null ? void 0 : _a.call(widget);
  if (!config) return;
  const { type } = getWidgetType(config);
  this.outputs[0].type = type;
  this.outputs[0].name = type;
  this.outputs[0].widget = widget;
  __privateMethod(this, _PrimitiveNode_instances, createWidget_fn).call(this, (_b = widget[CONFIG]) != null ? _b : config, theirNode, widget.name, recreating, widget[TARGET]);
}, "#onFirstConnection");
createWidget_fn = /* @__PURE__ */ __name(function(inputData, node, widgetName, recreating, targetWidget) {
  var _a, _b, _c;
  let type = inputData[0];
  if (type instanceof Array) {
    type = "COMBO";
  }
  let widget;
  if (type in ComfyWidgets) {
    widget = (ComfyWidgets[type](this, "value", inputData, app) || {}).widget;
  } else {
    widget = this.addWidget(type, "value", null, () => {
    }, {});
  }
  if (targetWidget) {
    widget.value = targetWidget.value;
  } else if ((node == null ? void 0 : node.widgets) && widget) {
    const theirWidget = node.widgets.find((w) => w.name === widgetName);
    if (theirWidget) {
      widget.value = theirWidget.value;
    }
  }
  if (!((_a = inputData == null ? void 0 : inputData[1]) == null ? void 0 : _a.control_after_generate) && (widget.type === "number" || widget.type === "combo")) {
    let control_value = (_b = this.widgets_values) == null ? void 0 : _b[1];
    if (!control_value) {
      control_value = "fixed";
    }
    addValueControlWidgets(
      this,
      widget,
      control_value,
      void 0,
      inputData
    );
    let filter = (_c = this.widgets_values) == null ? void 0 : _c[2];
    if (filter && this.widgets.length === 3) {
      this.widgets[2].value = filter;
    }
  }
  const controlValues = this.controlValues;
  if (this.lastType === this.widgets[0].type && (controlValues == null ? void 0 : controlValues.length) === this.widgets.length - 1) {
    for (let i = 0; i < controlValues.length; i++) {
      this.widgets[i + 1].value = controlValues[i];
    }
  }
  const callback = widget.callback;
  const self = this;
  widget.callback = function() {
    const r = callback ? callback.apply(this, arguments) : void 0;
    self.applyToGraph();
    return r;
  };
  if (!recreating) {
    const sz = this.computeSize();
    if (this.size[0] < sz[0]) {
      this.size[0] = sz[0];
    }
    if (this.size[1] < sz[1]) {
      this.size[1] = sz[1];
    }
    requestAnimationFrame(() => {
      if (this.onResize) {
        this.onResize(this.size);
      }
    });
  }
}, "#createWidget");
mergeWidgetConfig_fn = /* @__PURE__ */ __name(function() {
  const output = this.outputs[0];
  const links = output.links;
  const hasConfig = !!output.widget[CONFIG];
  if (hasConfig) {
    delete output.widget[CONFIG];
  }
  if ((links == null ? void 0 : links.length) < 2 && hasConfig) {
    if (links.length) {
      this.recreateWidget();
    }
    return;
  }
  const config1 = output.widget[GET_CONFIG]();
  const isNumber = config1[0] === "INT" || config1[0] === "FLOAT";
  if (!isNumber) return;
  for (const linkId of links) {
    const link = app.graph.links[linkId];
    if (!link) continue;
    const theirNode = app.graph.getNodeById(link.target_id);
    const theirInput = theirNode.inputs[link.target_slot];
    __privateMethod(this, _PrimitiveNode_instances, isValidConnection_fn).call(this, theirInput, hasConfig);
  }
}, "#mergeWidgetConfig");
isValidConnection_fn = /* @__PURE__ */ __name(function(input, forceUpdate) {
  const output = this.outputs[0];
  const config2 = input.widget[GET_CONFIG]();
  return !!mergeIfValid.call(
    this,
    output,
    config2,
    forceUpdate,
    this.recreateWidget
  );
}, "#isValidConnection");
removeWidgets_fn = /* @__PURE__ */ __name(function() {
  var _a;
  if (this.widgets) {
    for (const w of this.widgets) {
      if (w.onRemove) {
        w.onRemove();
      }
    }
    this.controlValues = [];
    this.lastType = (_a = this.widgets[0]) == null ? void 0 : _a.type;
    for (let i = 1; i < this.widgets.length; i++) {
      this.controlValues.push(this.widgets[i].value);
    }
    setTimeout(() => {
      delete this.lastType;
      delete this.controlValues;
    }, 15);
    this.widgets.length = 0;
  }
}, "#removeWidgets");
__name(_PrimitiveNode, "PrimitiveNode");
__publicField(_PrimitiveNode, "category");
let PrimitiveNode = _PrimitiveNode;
function getWidgetConfig(slot) {
  var _a;
  return (_a = slot.widget[CONFIG]) != null ? _a : slot.widget[GET_CONFIG]();
}
__name(getWidgetConfig, "getWidgetConfig");
function getConfig(widgetName) {
  var _a, _b, _c, _d, _e;
  const { nodeData } = this.constructor;
  return (_e = (_b = (_a = nodeData == null ? void 0 : nodeData.input) == null ? void 0 : _a.required) == null ? void 0 : _b[widgetName]) != null ? _e : (_d = (_c = nodeData == null ? void 0 : nodeData.input) == null ? void 0 : _c.optional) == null ? void 0 : _d[widgetName];
}
__name(getConfig, "getConfig");
function isConvertibleWidget(widget, config) {
  var _a;
  return (VALID_TYPES.includes(widget.type) || VALID_TYPES.includes(config[0])) && !((_a = widget.options) == null ? void 0 : _a.forceInput);
}
__name(isConvertibleWidget, "isConvertibleWidget");
function hideWidget(node, widget, suffix = "") {
  var _a;
  if ((_a = widget.type) == null ? void 0 : _a.startsWith(CONVERTED_TYPE)) return;
  widget.origType = widget.type;
  widget.origComputeSize = widget.computeSize;
  widget.origSerializeValue = widget.serializeValue;
  widget.computeSize = () => [0, -4];
  widget.type = CONVERTED_TYPE + suffix;
  widget.serializeValue = () => {
    if (!node.inputs) {
      return void 0;
    }
    let node_input = node.inputs.find((i) => {
      var _a2;
      return ((_a2 = i.widget) == null ? void 0 : _a2.name) === widget.name;
    });
    if (!node_input || !node_input.link) {
      return void 0;
    }
    return widget.origSerializeValue ? widget.origSerializeValue() : widget.value;
  };
  if (widget.linkedWidgets) {
    for (const w of widget.linkedWidgets) {
      hideWidget(node, w, ":" + widget.name);
    }
  }
}
__name(hideWidget, "hideWidget");
function showWidget(widget) {
  widget.type = widget.origType;
  widget.computeSize = widget.origComputeSize;
  widget.serializeValue = widget.origSerializeValue;
  delete widget.origType;
  delete widget.origComputeSize;
  delete widget.origSerializeValue;
  if (widget.linkedWidgets) {
    for (const w of widget.linkedWidgets) {
      showWidget(w);
    }
  }
}
__name(showWidget, "showWidget");
function convertToInput(node, widget, config) {
  hideWidget(node, widget);
  const { type } = getWidgetType(config);
  const sz = node.size;
  node.addInput(widget.name, type, {
    widget: { name: widget.name, [GET_CONFIG]: () => config }
  });
  for (const widget2 of node.widgets) {
    widget2.last_y += LiteGraph.NODE_SLOT_HEIGHT;
  }
  node.setSize([Math.max(sz[0], node.size[0]), Math.max(sz[1], node.size[1])]);
}
__name(convertToInput, "convertToInput");
function convertToWidget(node, widget) {
  showWidget(widget);
  const sz = node.size;
  node.removeInput(node.inputs.findIndex((i) => {
    var _a;
    return ((_a = i.widget) == null ? void 0 : _a.name) === widget.name;
  }));
  for (const widget2 of node.widgets) {
    widget2.last_y -= LiteGraph.NODE_SLOT_HEIGHT;
  }
  node.setSize([Math.max(sz[0], node.size[0]), Math.max(sz[1], node.size[1])]);
}
__name(convertToWidget, "convertToWidget");
function getWidgetType(config) {
  let type = config[0];
  if (type instanceof Array) {
    type = "COMBO";
  }
  return { type };
}
__name(getWidgetType, "getWidgetType");
function isValidCombo(combo, obj) {
  if (!(obj instanceof Array)) {
    console.log(`connection rejected: tried to connect combo to ${obj}`);
    return false;
  }
  if (combo.length !== obj.length) {
    console.log(`connection rejected: combo lists dont match`);
    return false;
  }
  if (combo.find((v, i) => obj[i] !== v)) {
    console.log(`connection rejected: combo lists dont match`);
    return false;
  }
  return true;
}
__name(isValidCombo, "isValidCombo");
function isPrimitiveNode(node) {
  return node.type === "PrimitiveNode";
}
__name(isPrimitiveNode, "isPrimitiveNode");
function setWidgetConfig(slot, config, target) {
  if (!slot.widget) return;
  if (config) {
    slot.widget[GET_CONFIG] = () => config;
    slot.widget[TARGET] = target;
  } else {
    delete slot.widget;
  }
  if (slot.link) {
    const link = app.graph.links[slot.link];
    if (link) {
      const originNode = app.graph.getNodeById(link.origin_id);
      if (isPrimitiveNode(originNode)) {
        if (config) {
          originNode.recreateWidget();
        } else if (!app.configuringGraph) {
          originNode.disconnectOutput(0);
          originNode.onLastDisconnect();
        }
      }
    }
  }
}
__name(setWidgetConfig, "setWidgetConfig");
function mergeIfValid(output, config2, forceUpdate, recreateWidget, config1) {
  var _a, _b, _c, _d, _e, _f;
  if (!config1) {
    config1 = (_a = output.widget[CONFIG]) != null ? _a : output.widget[GET_CONFIG]();
  }
  if (config1[0] instanceof Array) {
    if (!isValidCombo(config1[0], config2[0])) return;
  } else if (config1[0] !== config2[0]) {
    console.log(`connection rejected: types dont match`, config1[0], config2[0]);
    return;
  }
  const keys = /* @__PURE__ */ new Set([
    ...Object.keys((_b = config1[1]) != null ? _b : {}),
    ...Object.keys((_c = config2[1]) != null ? _c : {})
  ]);
  let customConfig;
  const getCustomConfig = /* @__PURE__ */ __name(() => {
    var _a2, _b2;
    if (!customConfig) {
      if (typeof structuredClone === "undefined") {
        customConfig = JSON.parse(JSON.stringify((_a2 = config1[1]) != null ? _a2 : {}));
      } else {
        customConfig = structuredClone((_b2 = config1[1]) != null ? _b2 : {});
      }
    }
    return customConfig;
  }, "getCustomConfig");
  const isNumber = config1[0] === "INT" || config1[0] === "FLOAT";
  for (const k of keys.values()) {
    if (k !== "default" && k !== "forceInput" && k !== "defaultInput" && k !== "control_after_generate" && k !== "multiline" && k !== "tooltip") {
      let v1 = config1[1][k];
      let v2 = (_d = config2[1]) == null ? void 0 : _d[k];
      if (v1 === v2 || !v1 && !v2) continue;
      if (isNumber) {
        if (k === "min") {
          const theirMax = (_e = config2[1]) == null ? void 0 : _e["max"];
          if (theirMax != null && v1 > theirMax) {
            console.log("connection rejected: min > max", v1, theirMax);
            return;
          }
          getCustomConfig()[k] = v1 == null ? v2 : v2 == null ? v1 : Math.max(v1, v2);
          continue;
        } else if (k === "max") {
          const theirMin = (_f = config2[1]) == null ? void 0 : _f["min"];
          if (theirMin != null && v1 < theirMin) {
            console.log("connection rejected: max < min", v1, theirMin);
            return;
          }
          getCustomConfig()[k] = v1 == null ? v2 : v2 == null ? v1 : Math.min(v1, v2);
          continue;
        } else if (k === "step") {
          let step;
          if (v1 == null) {
            step = v2;
          } else if (v2 == null) {
            step = v1;
          } else {
            if (v1 < v2) {
              const a = v2;
              v2 = v1;
              v1 = a;
            }
            if (v1 % v2) {
              console.log(
                "connection rejected: steps not divisible",
                "current:",
                v1,
                "new:",
                v2
              );
              return;
            }
            step = v1;
          }
          getCustomConfig()[k] = step;
          continue;
        }
      }
      console.log(`connection rejected: config ${k} values dont match`, v1, v2);
      return;
    }
  }
  if (customConfig || forceUpdate) {
    if (customConfig) {
      output.widget[CONFIG] = [config1[0], customConfig];
    }
    const widget = recreateWidget == null ? void 0 : recreateWidget.call(this);
    if (widget) {
      const min = widget.options.min;
      const max = widget.options.max;
      if (min != null && widget.value < min) widget.value = min;
      if (max != null && widget.value > max) widget.value = max;
      widget.callback(widget.value);
    }
  }
  return { customConfig };
}
__name(mergeIfValid, "mergeIfValid");
let useConversionSubmenusSetting;
app.registerExtension({
  name: "Comfy.WidgetInputs",
  init() {
    useConversionSubmenusSetting = app.ui.settings.addSetting({
      id: "Comfy.NodeInputConversionSubmenus",
      name: "In the node context menu, place the entries that convert between input/widget in sub-menus.",
      type: "boolean",
      defaultValue: true
    });
  },
  beforeRegisterNodeDef(nodeType, nodeData, app2) {
    return __async(this, null, function* () {
      const origGetExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
      nodeType.prototype.convertWidgetToInput = function(widget) {
        var _a;
        const config = (_a = getConfig.call(this, widget.name)) != null ? _a : [
          widget.type,
          widget.options || {}
        ];
        if (!isConvertibleWidget(widget, config)) return false;
        convertToInput(this, widget, config);
        return true;
      };
      nodeType.prototype.getExtraMenuOptions = function(_, options) {
        var _a, _b;
        const r = origGetExtraMenuOptions ? origGetExtraMenuOptions.apply(this, arguments) : void 0;
        if (this.widgets) {
          let toInput = [];
          let toWidget = [];
          for (const w of this.widgets) {
            if ((_a = w.options) == null ? void 0 : _a.forceInput) {
              continue;
            }
            if (w.type === CONVERTED_TYPE) {
              toWidget.push({
                content: `Convert ${w.name} to widget`,
                callback: /* @__PURE__ */ __name(() => convertToWidget(this, w), "callback")
              });
            } else {
              const config = (_b = getConfig.call(this, w.name)) != null ? _b : [
                w.type,
                w.options || {}
              ];
              if (isConvertibleWidget(w, config)) {
                toInput.push({
                  content: `Convert ${w.name} to input`,
                  callback: /* @__PURE__ */ __name(() => convertToInput(this, w, config), "callback")
                });
              }
            }
          }
          if (toInput.length) {
            if (useConversionSubmenusSetting.value) {
              options.push({
                content: "Convert Widget to Input",
                submenu: {
                  options: toInput
                }
              });
            } else {
              options.push(...toInput, null);
            }
          }
          if (toWidget.length) {
            if (useConversionSubmenusSetting.value) {
              options.push({
                content: "Convert Input to Widget",
                submenu: {
                  options: toWidget
                }
              });
            } else {
              options.push(...toWidget, null);
            }
          }
        }
        return r;
      };
      nodeType.prototype.onGraphConfigured = function() {
        if (!this.inputs) return;
        for (const input of this.inputs) {
          if (input.widget) {
            if (!input.widget[GET_CONFIG]) {
              input.widget[GET_CONFIG] = () => getConfig.call(this, input.widget.name);
            }
            if (input.widget.config) {
              if (input.widget.config[0] instanceof Array) {
                input.type = "COMBO";
                const link = app2.graph.links[input.link];
                if (link) {
                  link.type = input.type;
                }
              }
              delete input.widget.config;
            }
            const w = this.widgets.find((w2) => w2.name === input.widget.name);
            if (w) {
              hideWidget(this, w);
            } else {
              convertToWidget(this, input);
            }
          }
        }
      };
      const origOnNodeCreated = nodeType.prototype.onNodeCreated;
      nodeType.prototype.onNodeCreated = function() {
        var _a, _b, _c;
        const r = origOnNodeCreated ? origOnNodeCreated.apply(this) : void 0;
        if (!app2.configuringGraph && this.widgets) {
          for (const w of this.widgets) {
            if (((_a = w == null ? void 0 : w.options) == null ? void 0 : _a.forceInput) || ((_b = w == null ? void 0 : w.options) == null ? void 0 : _b.defaultInput)) {
              const config = (_c = getConfig.call(this, w.name)) != null ? _c : [
                w.type,
                w.options || {}
              ];
              convertToInput(this, w, config);
            }
          }
        }
        return r;
      };
      const origOnConfigure = nodeType.prototype.onConfigure;
      nodeType.prototype.onConfigure = function() {
        const r = origOnConfigure ? origOnConfigure.apply(this, arguments) : void 0;
        if (!app2.configuringGraph && this.inputs) {
          for (const input of this.inputs) {
            if (input.widget && !input.widget[GET_CONFIG]) {
              input.widget[GET_CONFIG] = () => getConfig.call(this, input.widget.name);
              const w = this.widgets.find((w2) => w2.name === input.widget.name);
              if (w) {
                hideWidget(this, w);
              }
            }
          }
        }
        return r;
      };
      function isNodeAtPos(pos) {
        for (const n of app2.graph._nodes) {
          if (n.pos[0] === pos[0] && n.pos[1] === pos[1]) {
            return true;
          }
        }
        return false;
      }
      __name(isNodeAtPos, "isNodeAtPos");
      const origOnInputDblClick = nodeType.prototype.onInputDblClick;
      const ignoreDblClick = Symbol();
      nodeType.prototype.onInputDblClick = function(slot) {
        var _a, _b, _c;
        const r = origOnInputDblClick ? origOnInputDblClick.apply(this, arguments) : void 0;
        const input = this.inputs[slot];
        if (!input.widget || !input[ignoreDblClick]) {
          if (!(input.type in ComfyWidgets) && !(((_c = (_b = (_a = input.widget)[GET_CONFIG]) == null ? void 0 : _b.call(_a)) == null ? void 0 : _c[0]) instanceof Array)) {
            return r;
          }
        }
        const node = LiteGraph.createNode("PrimitiveNode");
        app2.graph.add(node);
        const pos = [
          this.pos[0] - node.size[0] - 30,
          this.pos[1]
        ];
        while (isNodeAtPos(pos)) {
          pos[1] += LiteGraph.NODE_TITLE_HEIGHT;
        }
        node.pos = pos;
        node.connect(0, this, slot);
        node.title = input.name;
        input[ignoreDblClick] = true;
        setTimeout(() => {
          delete input[ignoreDblClick];
        }, 300);
        return r;
      };
      const onConnectInput = nodeType.prototype.onConnectInput;
      nodeType.prototype.onConnectInput = function(targetSlot, type, output, originNode, originSlot) {
        var _a, _b, _c, _d, _e, _f;
        const v = onConnectInput == null ? void 0 : onConnectInput(this, arguments);
        if (type !== "COMBO") return v;
        if (originNode.outputs[originSlot].widget) return v;
        const targetCombo = (_c = (_b = (_a = this.inputs[targetSlot].widget) == null ? void 0 : _a[GET_CONFIG]) == null ? void 0 : _b.call(_a)) == null ? void 0 : _c[0];
        if (!targetCombo || !(targetCombo instanceof Array)) return v;
        const originConfig = (_f = (_e = (_d = originNode.constructor) == null ? void 0 : _d.nodeData) == null ? void 0 : _e.output) == null ? void 0 : _f[originSlot];
        if (!originConfig || !isValidCombo(targetCombo, originConfig)) {
          return false;
        }
        return v;
      };
    });
  },
  registerCustomNodes() {
    LiteGraph.registerNodeType(
      "PrimitiveNode",
      Object.assign(PrimitiveNode, {
        title: "Primitive"
      })
    );
    PrimitiveNode.category = "utils";
  }
});
window.comfyAPI = window.comfyAPI || {};
window.comfyAPI.widgetInputs = window.comfyAPI.widgetInputs || {};
window.comfyAPI.widgetInputs.getWidgetConfig = getWidgetConfig;
window.comfyAPI.widgetInputs.setWidgetConfig = setWidgetConfig;
window.comfyAPI.widgetInputs.mergeIfValid = mergeIfValid;
const ORDER = Symbol();
function merge(target, source) {
  if (typeof target === "object" && typeof source === "object") {
    for (const key in source) {
      const sv = source[key];
      if (typeof sv === "object") {
        let tv = target[key];
        if (!tv) tv = target[key] = {};
        merge(tv, source[key]);
      } else {
        target[key] = sv;
      }
    }
  }
  return target;
}
__name(merge, "merge");
const _ManageGroupDialog = class _ManageGroupDialog extends ComfyDialog {
  constructor(app2) {
    super();
    __publicField(this, "tabs");
    __publicField(this, "selectedNodeIndex");
    __publicField(this, "selectedTab", "Inputs");
    __publicField(this, "selectedGroup");
    __publicField(this, "modifications", {});
    __publicField(this, "nodeItems");
    __publicField(this, "app");
    __publicField(this, "groupNodeType");
    __publicField(this, "groupNodeDef");
    __publicField(this, "groupData");
    __publicField(this, "innerNodesList");
    __publicField(this, "widgetsPage");
    __publicField(this, "inputsPage");
    __publicField(this, "outputsPage");
    __publicField(this, "draggable");
    this.app = app2;
    this.element = $el("dialog.comfy-group-manage", {
      parent: document.body
    });
  }
  get selectedNodeInnerIndex() {
    return +this.nodeItems[this.selectedNodeIndex].dataset.nodeindex;
  }
  changeTab(tab) {
    this.tabs[this.selectedTab].tab.classList.remove("active");
    this.tabs[this.selectedTab].page.classList.remove("active");
    this.tabs[tab].tab.classList.add("active");
    this.tabs[tab].page.classList.add("active");
    this.selectedTab = tab;
  }
  changeNode(index, force) {
    if (!force && this.selectedNodeIndex === index) return;
    if (this.selectedNodeIndex != null) {
      this.nodeItems[this.selectedNodeIndex].classList.remove("selected");
    }
    this.nodeItems[index].classList.add("selected");
    this.selectedNodeIndex = index;
    if (!this.buildInputsPage() && this.selectedTab === "Inputs") {
      this.changeTab("Widgets");
    }
    if (!this.buildWidgetsPage() && this.selectedTab === "Widgets") {
      this.changeTab("Outputs");
    }
    if (!this.buildOutputsPage() && this.selectedTab === "Outputs") {
      this.changeTab("Inputs");
    }
    this.changeTab(this.selectedTab);
  }
  getGroupData() {
    this.groupNodeType = LiteGraph.registered_node_types["workflow/" + this.selectedGroup];
    this.groupNodeDef = this.groupNodeType.nodeData;
    this.groupData = GroupNodeHandler.getGroupData(this.groupNodeType);
  }
  changeGroup(group, reset = true) {
    var _a;
    this.selectedGroup = group;
    this.getGroupData();
    const nodes = this.groupData.nodeData.nodes;
    this.nodeItems = nodes.map(
      (n, i) => {
        var _a2;
        return $el(
          "li.draggable-item",
          {
            dataset: {
              nodeindex: n.index + ""
            },
            onclick: /* @__PURE__ */ __name(() => {
              this.changeNode(i);
            }, "onclick")
          },
          [
            $el("span.drag-handle"),
            $el(
              "div",
              {
                textContent: (_a2 = n.title) != null ? _a2 : n.type
              },
              n.title ? $el("span", {
                textContent: n.type
              }) : []
            )
          ]
        );
      }
    );
    this.innerNodesList.replaceChildren(...this.nodeItems);
    if (reset) {
      this.selectedNodeIndex = null;
      this.changeNode(0);
    } else {
      const items = this.draggable.getAllItems();
      let index = items.findIndex((item) => item.classList.contains("selected"));
      if (index === -1) index = this.selectedNodeIndex;
      this.changeNode(index, true);
    }
    const ordered = [...nodes];
    (_a = this.draggable) == null ? void 0 : _a.dispose();
    this.draggable = new DraggableList(this.innerNodesList, "li");
    this.draggable.addEventListener(
      "dragend",
      ({ detail: { oldPosition, newPosition } }) => {
        if (oldPosition === newPosition) return;
        ordered.splice(newPosition, 0, ordered.splice(oldPosition, 1)[0]);
        for (let i = 0; i < ordered.length; i++) {
          this.storeModification({
            nodeIndex: ordered[i].index,
            section: ORDER,
            prop: "order",
            value: i
          });
        }
      }
    );
  }
  storeModification(props) {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    const { nodeIndex, section, prop, value } = props;
    const groupMod = (_c = (_a = this.modifications)[_b = this.selectedGroup]) != null ? _c : _a[_b] = {};
    const nodesMod = (_d = groupMod.nodes) != null ? _d : groupMod.nodes = {};
    const nodeMod = (_f = nodesMod[_e = nodeIndex != null ? nodeIndex : this.selectedNodeInnerIndex]) != null ? _f : nodesMod[_e] = {};
    const typeMod = (_g = nodeMod[section]) != null ? _g : nodeMod[section] = {};
    if (typeof value === "object") {
      const objMod = (_h = typeMod[prop]) != null ? _h : typeMod[prop] = {};
      Object.assign(objMod, value);
    } else {
      typeMod[prop] = value;
    }
  }
  getEditElement(section, prop, value, placeholder, checked, checkable = true) {
    var _a, _b, _c, _d;
    if (value === placeholder) value = "";
    const mods = (_d = (_c = (_b = (_a = this.modifications[this.selectedGroup]) == null ? void 0 : _a.nodes) == null ? void 0 : _b[this.selectedNodeInnerIndex]) == null ? void 0 : _c[section]) == null ? void 0 : _d[prop];
    if (mods) {
      if (mods.name != null) {
        value = mods.name;
      }
      if (mods.visible != null) {
        checked = mods.visible;
      }
    }
    return $el("div", [
      $el("input", {
        value,
        placeholder,
        type: "text",
        onchange: /* @__PURE__ */ __name((e) => {
          this.storeModification({
            section,
            prop,
            value: { name: e.target.value }
          });
        }, "onchange")
      }),
      $el("label", { textContent: "Visible" }, [
        $el("input", {
          type: "checkbox",
          checked,
          disabled: !checkable,
          onchange: /* @__PURE__ */ __name((e) => {
            this.storeModification({
              section,
              prop,
              value: { visible: !!e.target.checked }
            });
          }, "onchange")
        })
      ])
    ]);
  }
  buildWidgetsPage() {
    var _a, _b;
    const widgets = this.groupData.oldToNewWidgetMap[this.selectedNodeInnerIndex];
    const items = Object.keys(widgets != null ? widgets : {});
    const type = app.graph.extra.groupNodes[this.selectedGroup];
    const config = (_b = (_a = type.config) == null ? void 0 : _a[this.selectedNodeInnerIndex]) == null ? void 0 : _b.input;
    this.widgetsPage.replaceChildren(
      ...items.map((oldName) => {
        var _a2;
        return this.getEditElement(
          "input",
          oldName,
          widgets[oldName],
          oldName,
          ((_a2 = config == null ? void 0 : config[oldName]) == null ? void 0 : _a2.visible) !== false
        );
      })
    );
    return !!items.length;
  }
  buildInputsPage() {
    var _a, _b;
    const inputs = this.groupData.nodeInputs[this.selectedNodeInnerIndex];
    const items = Object.keys(inputs != null ? inputs : {});
    const type = app.graph.extra.groupNodes[this.selectedGroup];
    const config = (_b = (_a = type.config) == null ? void 0 : _a[this.selectedNodeInnerIndex]) == null ? void 0 : _b.input;
    this.inputsPage.replaceChildren(
      ...items.map((oldName) => {
        var _a2;
        let value = inputs[oldName];
        if (!value) {
          return;
        }
        return this.getEditElement(
          "input",
          oldName,
          value,
          oldName,
          ((_a2 = config == null ? void 0 : config[oldName]) == null ? void 0 : _a2.visible) !== false
        );
      }).filter(Boolean)
    );
    return !!items.length;
  }
  buildOutputsPage() {
    var _a, _b, _c;
    const nodes = this.groupData.nodeData.nodes;
    const innerNodeDef = this.groupData.getNodeDef(
      nodes[this.selectedNodeInnerIndex]
    );
    const outputs = (_a = innerNodeDef == null ? void 0 : innerNodeDef.output) != null ? _a : [];
    const groupOutputs = this.groupData.oldToNewOutputMap[this.selectedNodeInnerIndex];
    const type = app.graph.extra.groupNodes[this.selectedGroup];
    const config = (_c = (_b = type.config) == null ? void 0 : _b[this.selectedNodeInnerIndex]) == null ? void 0 : _c.output;
    const node = this.groupData.nodeData.nodes[this.selectedNodeInnerIndex];
    const checkable = node.type !== "PrimitiveNode";
    this.outputsPage.replaceChildren(
      ...outputs.map((type2, slot) => {
        var _a2, _b2, _c2, _d;
        const groupOutputIndex = groupOutputs == null ? void 0 : groupOutputs[slot];
        const oldName = (_b2 = (_a2 = innerNodeDef.output_name) == null ? void 0 : _a2[slot]) != null ? _b2 : type2;
        let value = (_c2 = config == null ? void 0 : config[slot]) == null ? void 0 : _c2.name;
        const visible = ((_d = config == null ? void 0 : config[slot]) == null ? void 0 : _d.visible) || groupOutputIndex != null;
        if (!value || value === oldName) {
          value = "";
        }
        return this.getEditElement(
          "output",
          slot,
          value,
          oldName,
          visible,
          checkable
        );
      }).filter(Boolean)
    );
    return !!outputs.length;
  }
  show(type) {
    var _a, _b;
    const groupNodes = Object.keys((_b = (_a = app.graph.extra) == null ? void 0 : _a.groupNodes) != null ? _b : {}).sort(
      (a, b) => a.localeCompare(b)
    );
    this.innerNodesList = $el(
      "ul.comfy-group-manage-list-items"
    );
    this.widgetsPage = $el("section.comfy-group-manage-node-page");
    this.inputsPage = $el("section.comfy-group-manage-node-page");
    this.outputsPage = $el("section.comfy-group-manage-node-page");
    const pages = $el("div", [
      this.widgetsPage,
      this.inputsPage,
      this.outputsPage
    ]);
    this.tabs = [
      ["Inputs", this.inputsPage],
      ["Widgets", this.widgetsPage],
      ["Outputs", this.outputsPage]
    ].reduce((p, [name, page]) => {
      p[name] = {
        tab: $el("a", {
          onclick: /* @__PURE__ */ __name(() => {
            this.changeTab(name);
          }, "onclick"),
          textContent: name
        }),
        page
      };
      return p;
    }, {});
    const outer = $el("div.comfy-group-manage-outer", [
      $el("header", [
        $el("h2", "Group Nodes"),
        $el(
          "select",
          {
            onchange: /* @__PURE__ */ __name((e) => {
              this.changeGroup(e.target.value);
            }, "onchange")
          },
          groupNodes.map(
            (g) => $el("option", {
              textContent: g,
              selected: "workflow/" + g === type,
              value: g
            })
          )
        )
      ]),
      $el("main", [
        $el("section.comfy-group-manage-list", this.innerNodesList),
        $el("section.comfy-group-manage-node", [
          $el(
            "header",
            Object.values(this.tabs).map((t) => t.tab)
          ),
          pages
        ])
      ]),
      $el("footer", [
        $el(
          "button.comfy-btn",
          {
            onclick: /* @__PURE__ */ __name((e) => {
              const node = app.graph._nodes.find(
                (n) => n.type === "workflow/" + this.selectedGroup
              );
              if (node) {
                alert(
                  "This group node is in use in the current workflow, please first remove these."
                );
                return;
              }
              if (confirm(
                `Are you sure you want to remove the node: "${this.selectedGroup}"`
              )) {
                delete app.graph.extra.groupNodes[this.selectedGroup];
                LiteGraph.unregisterNodeType("workflow/" + this.selectedGroup);
              }
              this.show();
            }, "onclick")
          },
          "Delete Group Node"
        ),
        $el(
          "button.comfy-btn",
          {
            onclick: /* @__PURE__ */ __name(() => __async(this, null, function* () {
              var _a2, _b2;
              let nodesByType;
              let recreateNodes = [];
              const types = {};
              for (const g in this.modifications) {
                const type2 = app.graph.extra.groupNodes[g];
                let config = (_a2 = type2.config) != null ? _a2 : type2.config = {};
                let nodeMods = (_b2 = this.modifications[g]) == null ? void 0 : _b2.nodes;
                if (nodeMods) {
                  const keys = Object.keys(nodeMods);
                  if (nodeMods[keys[0]][ORDER]) {
                    const orderedNodes = [];
                    const orderedMods = {};
                    const orderedConfig = {};
                    for (const n of keys) {
                      const order = nodeMods[n][ORDER].order;
                      orderedNodes[order] = type2.nodes[+n];
                      orderedMods[order] = nodeMods[n];
                      orderedNodes[order].index = order;
                    }
                    for (const l of type2.links) {
                      if (l[0] != null) l[0] = type2.nodes[l[0]].index;
                      if (l[2] != null) l[2] = type2.nodes[l[2]].index;
                    }
                    if (type2.external) {
                      for (const ext2 of type2.external) {
                        ext2[0] = type2.nodes[ext2[0]];
                      }
                    }
                    for (const id2 of keys) {
                      if (config[id2]) {
                        orderedConfig[type2.nodes[id2].index] = config[id2];
                      }
                      delete config[id2];
                    }
                    type2.nodes = orderedNodes;
                    nodeMods = orderedMods;
                    type2.config = config = orderedConfig;
                  }
                  merge(config, nodeMods);
                }
                types[g] = type2;
                if (!nodesByType) {
                  nodesByType = app.graph._nodes.reduce((p, n) => {
                    var _a3, _b3;
                    (_b3 = p[_a3 = n.type]) != null ? _b3 : p[_a3] = [];
                    p[n.type].push(n);
                    return p;
                  }, {});
                }
                const nodes = nodesByType["workflow/" + g];
                if (nodes) recreateNodes.push(...nodes);
              }
              yield GroupNodeConfig.registerFromWorkflow(types, {});
              for (const node of recreateNodes) {
                node.recreate();
              }
              this.modifications = {};
              this.app.graph.setDirtyCanvas(true, true);
              this.changeGroup(this.selectedGroup, false);
            }), "onclick")
          },
          "Save"
        ),
        $el(
          "button.comfy-btn",
          { onclick: /* @__PURE__ */ __name(() => this.element.close(), "onclick") },
          "Close"
        )
      ])
    ]);
    this.element.replaceChildren(outer);
    this.changeGroup(
      type ? groupNodes.find((g) => "workflow/" + g === type) : groupNodes[0]
    );
    this.element.showModal();
    this.element.addEventListener("close", () => {
      var _a2;
      (_a2 = this.draggable) == null ? void 0 : _a2.dispose();
    });
  }
};
__name(_ManageGroupDialog, "ManageGroupDialog");
let ManageGroupDialog = _ManageGroupDialog;
window.comfyAPI = window.comfyAPI || {};
window.comfyAPI.groupNodeManage = window.comfyAPI.groupNodeManage || {};
window.comfyAPI.groupNodeManage.ManageGroupDialog = ManageGroupDialog;
const GROUP = Symbol();
const Workflow = {
  InUse: {
    Free: 0,
    Registered: 1,
    InWorkflow: 2
  },
  isInUseGroupNode(name) {
    var _a, _b;
    const id2 = `workflow/${name}`;
    if ((_b = (_a = app.graph.extra) == null ? void 0 : _a.groupNodes) == null ? void 0 : _b[name]) {
      if (app.graph._nodes.find((n) => n.type === id2)) {
        return Workflow.InUse.InWorkflow;
      } else {
        return Workflow.InUse.Registered;
      }
    }
    return Workflow.InUse.Free;
  },
  storeGroupNode(name, data) {
    let extra = app.graph.extra;
    if (!extra) app.graph.extra = extra = {};
    let groupNodes = extra.groupNodes;
    if (!groupNodes) extra.groupNodes = groupNodes = {};
    groupNodes[name] = data;
  }
};
const _GroupNodeBuilder = class _GroupNodeBuilder {
  constructor(nodes) {
    __publicField(this, "nodes");
    __publicField(this, "nodeData");
    this.nodes = nodes;
  }
  build() {
    const name = this.getName();
    if (!name) return;
    this.sortNodes();
    this.nodeData = this.getNodeData();
    Workflow.storeGroupNode(name, this.nodeData);
    return { name, nodeData: this.nodeData };
  }
  getName() {
    const name = prompt("Enter group name");
    if (!name) return;
    const used = Workflow.isInUseGroupNode(name);
    switch (used) {
      case Workflow.InUse.InWorkflow:
        alert(
          "An in use group node with this name already exists embedded in this workflow, please remove any instances or use a new name."
        );
        return;
      case Workflow.InUse.Registered:
        if (!confirm(
          "A group node with this name already exists embedded in this workflow, are you sure you want to overwrite it?"
        )) {
          return;
        }
        break;
    }
    return name;
  }
  sortNodes() {
    const nodesInOrder = app.graph.computeExecutionOrder(false);
    this.nodes = this.nodes.map((node) => ({ index: nodesInOrder.indexOf(node), node })).sort((a, b) => a.index - b.index || a.node.id - b.node.id).map(({ node }) => node);
  }
  getNodeData() {
    const storeLinkTypes = /* @__PURE__ */ __name((config) => {
      for (const link of config.links) {
        const origin = app.graph.getNodeById(link[4]);
        const type = origin.outputs[link[1]].type;
        link.push(type);
      }
    }, "storeLinkTypes");
    const storeExternalLinks = /* @__PURE__ */ __name((config) => {
      var _a, _b;
      config.external = [];
      for (let i = 0; i < this.nodes.length; i++) {
        const node = this.nodes[i];
        if (!((_a = node.outputs) == null ? void 0 : _a.length)) continue;
        for (let slot = 0; slot < node.outputs.length; slot++) {
          let hasExternal = false;
          const output = node.outputs[slot];
          let type = output.type;
          if (!((_b = output.links) == null ? void 0 : _b.length)) continue;
          for (const l of output.links) {
            const link = app.graph.links[l];
            if (!link) continue;
            if (type === "*") type = link.type;
            if (!app.canvas.selected_nodes[link.target_id]) {
              hasExternal = true;
              break;
            }
          }
          if (hasExternal) {
            config.external.push([i, slot, type]);
          }
        }
      }
    }, "storeExternalLinks");
    const backup = localStorage.getItem("litegrapheditor_clipboard");
    try {
      app.canvas.copyToClipboard(this.nodes);
      const config = JSON.parse(
        localStorage.getItem("litegrapheditor_clipboard")
      );
      storeLinkTypes(config);
      storeExternalLinks(config);
      return config;
    } finally {
      localStorage.setItem("litegrapheditor_clipboard", backup);
    }
  }
};
__name(_GroupNodeBuilder, "GroupNodeBuilder");
let GroupNodeBuilder = _GroupNodeBuilder;
const _GroupNodeConfig = class _GroupNodeConfig {
  constructor(name, nodeData) {
    __publicField(this, "name");
    __publicField(this, "nodeData");
    __publicField(this, "inputCount");
    __publicField(this, "oldToNewOutputMap");
    __publicField(this, "newToOldOutputMap");
    __publicField(this, "oldToNewInputMap");
    __publicField(this, "oldToNewWidgetMap");
    __publicField(this, "newToOldWidgetMap");
    __publicField(this, "primitiveDefs");
    __publicField(this, "widgetToPrimitive");
    __publicField(this, "primitiveToWidget");
    __publicField(this, "nodeInputs");
    __publicField(this, "outputVisibility");
    __publicField(this, "nodeDef");
    __publicField(this, "inputs");
    __publicField(this, "linksFrom");
    __publicField(this, "linksTo");
    __publicField(this, "externalFrom");
    __privateAdd(this, _convertedToProcess, []);
    this.name = name;
    this.nodeData = nodeData;
    this.getLinks();
    this.inputCount = 0;
    this.oldToNewOutputMap = {};
    this.newToOldOutputMap = {};
    this.oldToNewInputMap = {};
    this.oldToNewWidgetMap = {};
    this.newToOldWidgetMap = {};
    this.primitiveDefs = {};
    this.widgetToPrimitive = {};
    this.primitiveToWidget = {};
    this.nodeInputs = {};
    this.outputVisibility = [];
  }
  registerType(source = "workflow") {
    return __async(this, null, function* () {
      this.nodeDef = {
        output: [],
        output_name: [],
        output_is_list: [],
        output_is_hidden: [],
        name: source + "/" + this.name,
        display_name: this.name,
        category: "group nodes" + ("/" + source),
        input: { required: {} },
        [GROUP]: this
      };
      this.inputs = [];
      const seenInputs = {};
      const seenOutputs = {};
      for (let i = 0; i < this.nodeData.nodes.length; i++) {
        const node = this.nodeData.nodes[i];
        node.index = i;
        this.processNode(node, seenInputs, seenOutputs);
      }
      for (const p of __privateGet(this, _convertedToProcess)) {
        p();
      }
      __privateSet(this, _convertedToProcess, null);
      yield app.registerNodeDef("workflow/" + this.name, this.nodeDef);
    });
  }
  getLinks() {
    this.linksFrom = {};
    this.linksTo = {};
    this.externalFrom = {};
    for (const l of this.nodeData.links) {
      const [sourceNodeId, sourceNodeSlot, targetNodeId, targetNodeSlot] = l;
      if (sourceNodeId == null) continue;
      if (!this.linksFrom[sourceNodeId]) {
        this.linksFrom[sourceNodeId] = {};
      }
      if (!this.linksFrom[sourceNodeId][sourceNodeSlot]) {
        this.linksFrom[sourceNodeId][sourceNodeSlot] = [];
      }
      this.linksFrom[sourceNodeId][sourceNodeSlot].push(l);
      if (!this.linksTo[targetNodeId]) {
        this.linksTo[targetNodeId] = {};
      }
      this.linksTo[targetNodeId][targetNodeSlot] = l;
    }
    if (this.nodeData.external) {
      for (const ext2 of this.nodeData.external) {
        if (!this.externalFrom[ext2[0]]) {
          this.externalFrom[ext2[0]] = { [ext2[1]]: ext2[2] };
        } else {
          this.externalFrom[ext2[0]][ext2[1]] = ext2[2];
        }
      }
    }
  }
  processNode(node, seenInputs, seenOutputs) {
    var _a, _b, _c;
    const def = this.getNodeDef(node);
    if (!def) return;
    const inputs = __spreadValues(__spreadValues({}, (_a = def.input) == null ? void 0 : _a.required), (_b = def.input) == null ? void 0 : _b.optional);
    this.inputs.push(this.processNodeInputs(node, seenInputs, inputs));
    if ((_c = def.output) == null ? void 0 : _c.length) this.processNodeOutputs(node, seenOutputs, def);
  }
  getNodeDef(node) {
    var _a, _b, _c, _d, _e;
    const def = globalDefs[node.type];
    if (def) return def;
    const linksFrom = this.linksFrom[node.index];
    if (node.type === "PrimitiveNode") {
      if (!linksFrom) return;
      let type = linksFrom["0"][0][5];
      if (type === "COMBO") {
        const source = node.outputs[0].widget.name;
        const fromTypeName = this.nodeData.nodes[linksFrom["0"][0][2]].type;
        const fromType = globalDefs[fromTypeName];
        const input = (_a = fromType.input.required[source]) != null ? _a : fromType.input.optional[source];
        type = input[0];
      }
      const def2 = this.primitiveDefs[node.index] = {
        input: {
          required: {
            value: [type, {}]
          }
        },
        output: [type],
        output_name: [],
        output_is_list: []
      };
      return def2;
    } else if (node.type === "Reroute") {
      const linksTo = this.linksTo[node.index];
      if (linksTo && linksFrom && !((_b = this.externalFrom[node.index]) == null ? void 0 : _b[0])) {
        return null;
      }
      let config = {};
      let rerouteType = "*";
      if (linksFrom) {
        for (const [, , id2, slot] of linksFrom["0"]) {
          const node2 = this.nodeData.nodes[id2];
          const input = node2.inputs[slot];
          if (rerouteType === "*") {
            rerouteType = input.type;
          }
          if (input.widget) {
            const targetDef = globalDefs[node2.type];
            const targetWidget = (_c = targetDef.input.required[input.widget.name]) != null ? _c : targetDef.input.optional[input.widget.name];
            const widget = [targetWidget[0], config];
            const res = mergeIfValid(
              {
                widget
              },
              targetWidget,
              false,
              null,
              widget
            );
            config = (_d = res == null ? void 0 : res.customConfig) != null ? _d : config;
          }
        }
      } else if (linksTo) {
        const [id2, slot] = linksTo["0"];
        rerouteType = this.nodeData.nodes[id2].outputs[slot].type;
      } else {
        for (const l of this.nodeData.links) {
          if (l[2] === node.index) {
            rerouteType = l[5];
            break;
          }
        }
        if (rerouteType === "*") {
          const t = (_e = this.externalFrom[node.index]) == null ? void 0 : _e[0];
          if (t) {
            rerouteType = t;
          }
        }
      }
      config.forceInput = true;
      return {
        input: {
          required: {
            [rerouteType]: [rerouteType, config]
          }
        },
        output: [rerouteType],
        output_name: [],
        output_is_list: []
      };
    }
    console.warn(
      "Skipping virtual node " + node.type + " when building group node " + this.name
    );
  }
  getInputConfig(node, inputName, seenInputs, config, extra) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
    const customConfig = (_c = (_b = (_a = this.nodeData.config) == null ? void 0 : _a[node.index]) == null ? void 0 : _b.input) == null ? void 0 : _c[inputName];
    let name = (_g = (_f = customConfig == null ? void 0 : customConfig.name) != null ? _f : (_e = (_d = node.inputs) == null ? void 0 : _d.find((inp) => inp.name === inputName)) == null ? void 0 : _e.label) != null ? _g : inputName;
    let key = name;
    let prefix = "";
    if (node.type === "PrimitiveNode" && node.title || name in seenInputs) {
      prefix = `${(_h = node.title) != null ? _h : node.type} `;
      key = name = `${prefix}${inputName}`;
      if (name in seenInputs) {
        name = `${prefix}${seenInputs[name]} ${inputName}`;
      }
    }
    seenInputs[key] = ((_i = seenInputs[key]) != null ? _i : 1) + 1;
    if (inputName === "seed" || inputName === "noise_seed") {
      if (!extra) extra = {};
      extra.control_after_generate = `${prefix}control_after_generate`;
    }
    if (config[0] === "IMAGEUPLOAD") {
      if (!extra) extra = {};
      extra.widget = (_m = (_l = this.oldToNewWidgetMap[node.index]) == null ? void 0 : _l[(_k = (_j = config[1]) == null ? void 0 : _j.widget) != null ? _k : "image"]) != null ? _m : "image";
    }
    if (extra) {
      config = [config[0], __spreadValues(__spreadValues({}, config[1]), extra)];
    }
    return { name, config, customConfig };
  }
  processWidgetInputs(inputs, node, inputNames, seenInputs) {
    var _a;
    const slots = [];
    const converted = /* @__PURE__ */ new Map();
    const widgetMap = this.oldToNewWidgetMap[node.index] = {};
    for (const inputName of inputNames) {
      let widgetType = app.getWidgetType(inputs[inputName], inputName);
      if (widgetType) {
        const convertedIndex = (_a = node.inputs) == null ? void 0 : _a.findIndex(
          (inp) => {
            var _a2;
            return inp.name === inputName && ((_a2 = inp.widget) == null ? void 0 : _a2.name) === inputName;
          }
        );
        if (convertedIndex > -1) {
          converted.set(convertedIndex, inputName);
          widgetMap[inputName] = null;
        } else {
          const { name, config } = this.getInputConfig(
            node,
            inputName,
            seenInputs,
            inputs[inputName]
          );
          this.nodeDef.input.required[name] = config;
          widgetMap[inputName] = name;
          this.newToOldWidgetMap[name] = { node, inputName };
        }
      } else {
        slots.push(inputName);
      }
    }
    return { converted, slots };
  }
  checkPrimitiveConnection(link, inputName, inputs) {
    var _a;
    const sourceNode = this.nodeData.nodes[link[0]];
    if (sourceNode.type === "PrimitiveNode") {
      const [sourceNodeId, _, targetNodeId, __] = link;
      const primitiveDef = this.primitiveDefs[sourceNodeId];
      const targetWidget = inputs[inputName];
      const primitiveConfig = primitiveDef.input.required.value;
      const output = { widget: primitiveConfig };
      const config = mergeIfValid(
        output,
        targetWidget,
        false,
        null,
        primitiveConfig
      );
      primitiveConfig[1] = ((_a = config == null ? void 0 : config.customConfig) != null ? _a : inputs[inputName][1]) ? __spreadValues({}, inputs[inputName][1]) : {};
      let name = this.oldToNewWidgetMap[sourceNodeId]["value"];
      name = name.substr(0, name.length - 6);
      primitiveConfig[1].control_after_generate = true;
      primitiveConfig[1].control_prefix = name;
      let toPrimitive = this.widgetToPrimitive[targetNodeId];
      if (!toPrimitive) {
        toPrimitive = this.widgetToPrimitive[targetNodeId] = {};
      }
      if (toPrimitive[inputName]) {
        toPrimitive[inputName].push(sourceNodeId);
      }
      toPrimitive[inputName] = sourceNodeId;
      let toWidget = this.primitiveToWidget[sourceNodeId];
      if (!toWidget) {
        toWidget = this.primitiveToWidget[sourceNodeId] = [];
      }
      toWidget.push({ nodeId: targetNodeId, inputName });
    }
  }
  processInputSlots(inputs, node, slots, linksTo, inputMap, seenInputs) {
    this.nodeInputs[node.index] = {};
    for (let i = 0; i < slots.length; i++) {
      const inputName = slots[i];
      if (linksTo[i]) {
        this.checkPrimitiveConnection(linksTo[i], inputName, inputs);
        continue;
      }
      const { name, config, customConfig } = this.getInputConfig(
        node,
        inputName,
        seenInputs,
        inputs[inputName]
      );
      this.nodeInputs[node.index][inputName] = name;
      if ((customConfig == null ? void 0 : customConfig.visible) === false) continue;
      this.nodeDef.input.required[name] = config;
      inputMap[i] = this.inputCount++;
    }
  }
  processConvertedWidgets(inputs, node, slots, converted, linksTo, inputMap, seenInputs) {
    const convertedSlots = [...converted.keys()].sort().map((k) => converted.get(k));
    for (let i = 0; i < convertedSlots.length; i++) {
      const inputName = convertedSlots[i];
      if (linksTo[slots.length + i]) {
        this.checkPrimitiveConnection(
          linksTo[slots.length + i],
          inputName,
          inputs
        );
        continue;
      }
      const { name, config } = this.getInputConfig(
        node,
        inputName,
        seenInputs,
        inputs[inputName],
        {
          defaultInput: true
        }
      );
      this.nodeDef.input.required[name] = config;
      this.newToOldWidgetMap[name] = { node, inputName };
      if (!this.oldToNewWidgetMap[node.index]) {
        this.oldToNewWidgetMap[node.index] = {};
      }
      this.oldToNewWidgetMap[node.index][inputName] = name;
      inputMap[slots.length + i] = this.inputCount++;
    }
  }
  processNodeInputs(node, seenInputs, inputs) {
    var _a;
    const inputMapping = [];
    const inputNames = Object.keys(inputs);
    if (!inputNames.length) return;
    const { converted, slots } = this.processWidgetInputs(
      inputs,
      node,
      inputNames,
      seenInputs
    );
    const linksTo = (_a = this.linksTo[node.index]) != null ? _a : {};
    const inputMap = this.oldToNewInputMap[node.index] = {};
    this.processInputSlots(inputs, node, slots, linksTo, inputMap, seenInputs);
    __privateGet(this, _convertedToProcess).push(
      () => this.processConvertedWidgets(
        inputs,
        node,
        slots,
        converted,
        linksTo,
        inputMap,
        seenInputs
      )
    );
    return inputMapping;
  }
  processNodeOutputs(node, seenOutputs, def) {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    const oldToNew = this.oldToNewOutputMap[node.index] = {};
    for (let outputId = 0; outputId < def.output.length; outputId++) {
      const linksFrom = this.linksFrom[node.index];
      const hasLink = (linksFrom == null ? void 0 : linksFrom[outputId]) && !((_a = this.externalFrom[node.index]) == null ? void 0 : _a[outputId]);
      const customConfig = (_d = (_c = (_b = this.nodeData.config) == null ? void 0 : _b[node.index]) == null ? void 0 : _c.output) == null ? void 0 : _d[outputId];
      const visible = (_e = customConfig == null ? void 0 : customConfig.visible) != null ? _e : !hasLink;
      this.outputVisibility.push(visible);
      if (!visible) {
        continue;
      }
      oldToNew[outputId] = this.nodeDef.output.length;
      this.newToOldOutputMap[this.nodeDef.output.length] = {
        node,
        slot: outputId
      };
      this.nodeDef.output.push(def.output[outputId]);
      this.nodeDef.output_is_list.push(def.output_is_list[outputId]);
      let label = customConfig == null ? void 0 : customConfig.name;
      if (!label) {
        label = (_g = (_f = def.output_name) == null ? void 0 : _f[outputId]) != null ? _g : def.output[outputId];
        const output = node.outputs.find((o) => o.name === label);
        if (output == null ? void 0 : output.label) {
          label = output.label;
        }
      }
      let name = label;
      if (name in seenOutputs) {
        const prefix = `${(_h = node.title) != null ? _h : node.type} `;
        name = `${prefix}${label}`;
        if (name in seenOutputs) {
          name = `${prefix}${node.index} ${label}`;
        }
      }
      seenOutputs[name] = 1;
      this.nodeDef.output_name.push(name);
    }
  }
  static registerFromWorkflow(groupNodes, missingNodeTypes) {
    return __async(this, null, function* () {
      const clean = app.clean;
      app.clean = function() {
        for (const g in groupNodes) {
          try {
            LiteGraph.unregisterNodeType("workflow/" + g);
          } catch (error) {
          }
        }
        app.clean = clean;
      };
      for (const g in groupNodes) {
        const groupData = groupNodes[g];
        let hasMissing = false;
        for (const n of groupData.nodes) {
          if (!(n.type in LiteGraph.registered_node_types)) {
            missingNodeTypes.push({
              type: n.type,
              hint: ` (In group node 'workflow/${g}')`
            });
            missingNodeTypes.push({
              type: "workflow/" + g,
              action: {
                text: "Remove from workflow",
                callback: /* @__PURE__ */ __name((e) => {
                  delete groupNodes[g];
                  e.target.textContent = "Removed";
                  e.target.style.pointerEvents = "none";
                  e.target.style.opacity = 0.7;
                }, "callback")
              }
            });
            hasMissing = true;
          }
        }
        if (hasMissing) continue;
        const config = new _GroupNodeConfig(g, groupData);
        yield config.registerType();
      }
    });
  }
};
_convertedToProcess = new WeakMap();
__name(_GroupNodeConfig, "GroupNodeConfig");
let GroupNodeConfig = _GroupNodeConfig;
const _GroupNodeHandler = class _GroupNodeHandler {
  constructor(node) {
    __publicField(this, "node");
    __publicField(this, "groupData");
    __publicField(this, "innerNodes");
    var _a, _b;
    this.node = node;
    this.groupData = (_b = (_a = node.constructor) == null ? void 0 : _a.nodeData) == null ? void 0 : _b[GROUP];
    this.node.setInnerNodes = (innerNodes) => {
      var _a2;
      this.innerNodes = innerNodes;
      for (let innerNodeIndex = 0; innerNodeIndex < this.innerNodes.length; innerNodeIndex++) {
        const innerNode = this.innerNodes[innerNodeIndex];
        for (const w of (_a2 = innerNode.widgets) != null ? _a2 : []) {
          if (w.type === "converted-widget") {
            w.serializeValue = w.origSerializeValue;
          }
        }
        innerNode.index = innerNodeIndex;
        innerNode.getInputNode = (slot) => {
          var _a3, _b2;
          const externalSlot = (_a3 = this.groupData.oldToNewInputMap[innerNode.index]) == null ? void 0 : _a3[slot];
          if (externalSlot != null) {
            return this.node.getInputNode(externalSlot);
          }
          const innerLink = (_b2 = this.groupData.linksTo[innerNode.index]) == null ? void 0 : _b2[slot];
          if (!innerLink) return null;
          const inputNode = innerNodes[innerLink[0]];
          if (inputNode.type === "PrimitiveNode") return null;
          return inputNode;
        };
        innerNode.getInputLink = (slot) => {
          var _a3, _b2;
          const externalSlot = (_a3 = this.groupData.oldToNewInputMap[innerNode.index]) == null ? void 0 : _a3[slot];
          if (externalSlot != null) {
            const linkId = this.node.inputs[externalSlot].link;
            let link2 = app.graph.links[linkId];
            link2 = __spreadProps(__spreadValues({}, link2), {
              target_id: innerNode.id,
              target_slot: +slot
            });
            return link2;
          }
          let link = (_b2 = this.groupData.linksTo[innerNode.index]) == null ? void 0 : _b2[slot];
          if (!link) return null;
          link = {
            origin_id: innerNodes[link[0]].id,
            origin_slot: link[1],
            target_id: innerNode.id,
            target_slot: +slot
          };
          return link;
        };
      }
    };
    this.node.updateLink = (link) => {
      var _a2;
      link = __spreadValues({}, link);
      const output = this.groupData.newToOldOutputMap[link.origin_slot];
      let innerNode = this.innerNodes[output.node.index];
      let l;
      while ((innerNode == null ? void 0 : innerNode.type) === "Reroute") {
        l = innerNode.getInputLink(0);
        innerNode = innerNode.getInputNode(0);
      }
      if (!innerNode) {
        return null;
      }
      if (l && _GroupNodeHandler.isGroupNode(innerNode)) {
        return innerNode.updateLink(l);
      }
      link.origin_id = innerNode.id;
      link.origin_slot = (_a2 = l == null ? void 0 : l.origin_slot) != null ? _a2 : output.slot;
      return link;
    };
    this.node.getInnerNodes = () => {
      if (!this.innerNodes) {
        this.node.setInnerNodes(
          this.groupData.nodeData.nodes.map((n, i) => {
            const innerNode = LiteGraph.createNode(n.type);
            innerNode.configure(n);
            innerNode.id = `${this.node.id}:${i}`;
            return innerNode;
          })
        );
      }
      this.updateInnerWidgets();
      return this.innerNodes;
    };
    this.node.recreate = () => __async(this, null, function* () {
      const id2 = this.node.id;
      const sz = this.node.size;
      const nodes = this.node.convertToNodes();
      const groupNode = LiteGraph.createNode(this.node.type);
      groupNode.id = id2;
      groupNode.setInnerNodes(nodes);
      groupNode[GROUP].populateWidgets();
      app.graph.add(groupNode);
      groupNode.size = [
        Math.max(groupNode.size[0], sz[0]),
        Math.max(groupNode.size[1], sz[1])
      ];
      groupNode[GROUP].replaceNodes(nodes);
      return groupNode;
    });
    this.node.convertToNodes = () => {
      const addInnerNodes = /* @__PURE__ */ __name(() => {
        var _a2, _b2;
        const backup = localStorage.getItem("litegrapheditor_clipboard");
        const c = __spreadValues({}, this.groupData.nodeData);
        c.nodes = [...c.nodes];
        const innerNodes = this.node.getInnerNodes();
        let ids = [];
        for (let i = 0; i < c.nodes.length; i++) {
          let id2 = (_a2 = innerNodes == null ? void 0 : innerNodes[i]) == null ? void 0 : _a2.id;
          if (id2 == null || isNaN(id2)) {
            id2 = void 0;
          } else {
            ids.push(id2);
          }
          c.nodes[i] = __spreadProps(__spreadValues({}, c.nodes[i]), { id: id2 });
        }
        localStorage.setItem("litegrapheditor_clipboard", JSON.stringify(c));
        app.canvas.pasteFromClipboard();
        localStorage.setItem("litegrapheditor_clipboard", backup);
        const [x, y] = this.node.pos;
        let top;
        let left;
        const selectedIds2 = ids.length ? ids : Object.keys(app.canvas.selected_nodes);
        const newNodes2 = [];
        for (let i = 0; i < selectedIds2.length; i++) {
          const id2 = selectedIds2[i];
          const newNode = app.graph.getNodeById(id2);
          const innerNode = innerNodes[i];
          newNodes2.push(newNode);
          if (left == null || newNode.pos[0] < left) {
            left = newNode.pos[0];
          }
          if (top == null || newNode.pos[1] < top) {
            top = newNode.pos[1];
          }
          if (!newNode.widgets) continue;
          const map = this.groupData.oldToNewWidgetMap[innerNode.index];
          if (map) {
            const widgets = Object.keys(map);
            for (const oldName of widgets) {
              const newName = map[oldName];
              if (!newName) continue;
              const widgetIndex = this.node.widgets.findIndex(
                (w) => w.name === newName
              );
              if (widgetIndex === -1) continue;
              if (innerNode.type === "PrimitiveNode") {
                for (let i2 = 0; i2 < newNode.widgets.length; i2++) {
                  newNode.widgets[i2].value = this.node.widgets[widgetIndex + i2].value;
                }
              } else {
                const outerWidget = this.node.widgets[widgetIndex];
                const newWidget = newNode.widgets.find(
                  (w) => w.name === oldName
                );
                if (!newWidget) continue;
                newWidget.value = outerWidget.value;
                for (let w = 0; w < ((_b2 = outerWidget.linkedWidgets) == null ? void 0 : _b2.length); w++) {
                  newWidget.linkedWidgets[w].value = outerWidget.linkedWidgets[w].value;
                }
              }
            }
          }
        }
        for (const newNode of newNodes2) {
          newNode.pos = [
            newNode.pos[0] - (left - x),
            newNode.pos[1] - (top - y)
          ];
        }
        return { newNodes: newNodes2, selectedIds: selectedIds2 };
      }, "addInnerNodes");
      const reconnectInputs = /* @__PURE__ */ __name((selectedIds2) => {
        for (const innerNodeIndex in this.groupData.oldToNewInputMap) {
          const id2 = selectedIds2[innerNodeIndex];
          const newNode = app.graph.getNodeById(id2);
          const map = this.groupData.oldToNewInputMap[innerNodeIndex];
          for (const innerInputId in map) {
            const groupSlotId = map[innerInputId];
            if (groupSlotId == null) continue;
            const slot = node.inputs[groupSlotId];
            if (slot.link == null) continue;
            const link = app.graph.links[slot.link];
            if (!link) continue;
            const originNode = app.graph.getNodeById(link.origin_id);
            originNode.connect(link.origin_slot, newNode, +innerInputId);
          }
        }
      }, "reconnectInputs");
      const reconnectOutputs = /* @__PURE__ */ __name((selectedIds2) => {
        var _a2;
        for (let groupOutputId = 0; groupOutputId < ((_a2 = node.outputs) == null ? void 0 : _a2.length); groupOutputId++) {
          const output = node.outputs[groupOutputId];
          if (!output.links) continue;
          const links = [...output.links];
          for (const l of links) {
            const slot = this.groupData.newToOldOutputMap[groupOutputId];
            const link = app.graph.links[l];
            const targetNode = app.graph.getNodeById(link.target_id);
            const newNode = app.graph.getNodeById(selectedIds2[slot.node.index]);
            newNode.connect(slot.slot, targetNode, link.target_slot);
          }
        }
      }, "reconnectOutputs");
      const { newNodes, selectedIds } = addInnerNodes();
      reconnectInputs(selectedIds);
      reconnectOutputs(selectedIds);
      app.graph.remove(this.node);
      return newNodes;
    };
    const getExtraMenuOptions = this.node.getExtraMenuOptions;
    this.node.getExtraMenuOptions = function(_, options) {
      getExtraMenuOptions == null ? void 0 : getExtraMenuOptions.apply(this, arguments);
      let optionIndex = options.findIndex((o) => o.content === "Outputs");
      if (optionIndex === -1) optionIndex = options.length;
      else optionIndex++;
      options.splice(
        optionIndex,
        0,
        null,
        {
          content: "Convert to nodes",
          callback: /* @__PURE__ */ __name(() => {
            return this.convertToNodes();
          }, "callback")
        },
        {
          content: "Manage Group Node",
          callback: /* @__PURE__ */ __name(() => {
            new ManageGroupDialog(app).show(this.type);
          }, "callback")
        }
      );
    };
    const onDrawTitleBox = this.node.onDrawTitleBox;
    this.node.onDrawTitleBox = function(ctx, height, size, scale) {
      onDrawTitleBox == null ? void 0 : onDrawTitleBox.apply(this, arguments);
      const fill = ctx.fillStyle;
      ctx.beginPath();
      ctx.rect(11, -height + 11, 2, 2);
      ctx.rect(14, -height + 11, 2, 2);
      ctx.rect(17, -height + 11, 2, 2);
      ctx.rect(11, -height + 14, 2, 2);
      ctx.rect(14, -height + 14, 2, 2);
      ctx.rect(17, -height + 14, 2, 2);
      ctx.rect(11, -height + 17, 2, 2);
      ctx.rect(14, -height + 17, 2, 2);
      ctx.rect(17, -height + 17, 2, 2);
      ctx.fillStyle = this.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
      ctx.fill();
      ctx.fillStyle = fill;
    };
    const onDrawForeground = node.onDrawForeground;
    const groupData = this.groupData.nodeData;
    node.onDrawForeground = function(ctx) {
      var _a2;
      const r = (_a2 = onDrawForeground == null ? void 0 : onDrawForeground.apply) == null ? void 0 : _a2.call(onDrawForeground, this, arguments);
      if (+app.runningNodeId === this.id && this.runningInternalNodeId !== null) {
        const n = groupData.nodes[this.runningInternalNodeId];
        if (!n) return;
        const message = `Running ${n.title || n.type} (${this.runningInternalNodeId}/${groupData.nodes.length})`;
        ctx.save();
        ctx.font = "12px sans-serif";
        const sz = ctx.measureText(message);
        ctx.fillStyle = node.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
        ctx.beginPath();
        ctx.roundRect(
          0,
          -LiteGraph.NODE_TITLE_HEIGHT - 20,
          sz.width + 12,
          20,
          5
        );
        ctx.fill();
        ctx.fillStyle = "#fff";
        ctx.fillText(message, 6, -LiteGraph.NODE_TITLE_HEIGHT - 6);
        ctx.restore();
      }
    };
    const onExecutionStart = this.node.onExecutionStart;
    this.node.onExecutionStart = function() {
      this.resetExecution = true;
      return onExecutionStart == null ? void 0 : onExecutionStart.apply(this, arguments);
    };
    const self = this;
    const onNodeCreated = this.node.onNodeCreated;
    this.node.onNodeCreated = function() {
      var _a2;
      if (!this.widgets) {
        return;
      }
      const config = self.groupData.nodeData.config;
      if (config) {
        for (const n in config) {
          const inputs = (_a2 = config[n]) == null ? void 0 : _a2.input;
          for (const w in inputs) {
            if (inputs[w].visible !== false) continue;
            const widgetName = self.groupData.oldToNewWidgetMap[n][w];
            const widget = this.widgets.find((w2) => w2.name === widgetName);
            if (widget) {
              widget.type = "hidden";
              widget.computeSize = () => [0, -4];
            }
          }
        }
      }
      return onNodeCreated == null ? void 0 : onNodeCreated.apply(this, arguments);
    };
    function handleEvent(type, getId, getEvent) {
      const handler = /* @__PURE__ */ __name(({ detail }) => {
        var _a2;
        const id2 = getId(detail);
        if (!id2) return;
        const node2 = app.graph.getNodeById(id2);
        if (node2) return;
        const innerNodeIndex = (_a2 = this.innerNodes) == null ? void 0 : _a2.findIndex((n) => n.id == id2);
        if (innerNodeIndex > -1) {
          this.node.runningInternalNodeId = innerNodeIndex;
          api.dispatchEvent(
            new CustomEvent(type, {
              detail: getEvent(detail, this.node.id + "", this.node)
            })
          );
        }
      }, "handler");
      api.addEventListener(type, handler);
      return handler;
    }
    __name(handleEvent, "handleEvent");
    const executing = handleEvent.call(
      this,
      "executing",
      (d) => d,
      (d, id2, node2) => id2
    );
    const executed = handleEvent.call(
      this,
      "executed",
      (d) => (d == null ? void 0 : d.display_node) || (d == null ? void 0 : d.node),
      (d, id2, node2) => __spreadProps(__spreadValues({}, d), {
        node: id2,
        display_node: id2,
        merge: !node2.resetExecution
      })
    );
    const onRemoved = node.onRemoved;
    this.node.onRemoved = function() {
      onRemoved == null ? void 0 : onRemoved.apply(this, arguments);
      api.removeEventListener("executing", executing);
      api.removeEventListener("executed", executed);
    };
    this.node.refreshComboInNode = (defs) => {
      var _a2, _b2, _c, _d, _e;
      for (const widgetName in this.groupData.newToOldWidgetMap) {
        const widget = this.node.widgets.find((w) => w.name === widgetName);
        if ((widget == null ? void 0 : widget.type) === "combo") {
          const old = this.groupData.newToOldWidgetMap[widgetName];
          const def = defs[old.node.type];
          const input = (_e = (_b2 = (_a2 = def == null ? void 0 : def.input) == null ? void 0 : _a2.required) == null ? void 0 : _b2[old.inputName]) != null ? _e : (_d = (_c = def == null ? void 0 : def.input) == null ? void 0 : _c.optional) == null ? void 0 : _d[old.inputName];
          if (!input) continue;
          widget.options.values = input[0];
          if (old.inputName !== "image" && !widget.options.values.includes(widget.value)) {
            widget.value = widget.options.values[0];
            widget.callback(widget.value);
          }
        }
      }
    };
  }
  updateInnerWidgets() {
    var _a, _b;
    for (const newWidgetName in this.groupData.newToOldWidgetMap) {
      const newWidget = this.node.widgets.find((w) => w.name === newWidgetName);
      if (!newWidget) continue;
      const newValue = newWidget.value;
      const old = this.groupData.newToOldWidgetMap[newWidgetName];
      let innerNode = this.innerNodes[old.node.index];
      if (innerNode.type === "PrimitiveNode") {
        innerNode.primitiveValue = newValue;
        const primitiveLinked = this.groupData.primitiveToWidget[old.node.index];
        for (const linked of primitiveLinked != null ? primitiveLinked : []) {
          const node = this.innerNodes[linked.nodeId];
          const widget2 = node.widgets.find((w) => w.name === linked.inputName);
          if (widget2) {
            widget2.value = newValue;
          }
        }
        continue;
      } else if (innerNode.type === "Reroute") {
        const rerouteLinks = this.groupData.linksFrom[old.node.index];
        if (rerouteLinks) {
          for (const [_, , targetNodeId, targetSlot] of rerouteLinks["0"]) {
            const node = this.innerNodes[targetNodeId];
            const input = node.inputs[targetSlot];
            if (input.widget) {
              const widget2 = (_a = node.widgets) == null ? void 0 : _a.find(
                (w) => w.name === input.widget.name
              );
              if (widget2) {
                widget2.value = newValue;
              }
            }
          }
        }
      }
      const widget = (_b = innerNode.widgets) == null ? void 0 : _b.find((w) => w.name === old.inputName);
      if (widget) {
        widget.value = newValue;
      }
    }
  }
  populatePrimitive(node, nodeId, oldName, i, linkedShift) {
    var _a, _b;
    const primitiveId = (_a = this.groupData.widgetToPrimitive[nodeId]) == null ? void 0 : _a[oldName];
    if (primitiveId == null) return;
    const targetWidgetName = this.groupData.oldToNewWidgetMap[primitiveId]["value"];
    const targetWidgetIndex = this.node.widgets.findIndex(
      (w) => w.name === targetWidgetName
    );
    if (targetWidgetIndex > -1) {
      const primitiveNode = this.innerNodes[primitiveId];
      let len = primitiveNode.widgets.length;
      if (len - 1 !== ((_b = this.node.widgets[targetWidgetIndex].linkedWidgets) == null ? void 0 : _b.length)) {
        len = 1;
      }
      for (let i2 = 0; i2 < len; i2++) {
        this.node.widgets[targetWidgetIndex + i2].value = primitiveNode.widgets[i2].value;
      }
    }
    return true;
  }
  populateReroute(node, nodeId, map) {
    var _a, _b, _c, _d, _e, _f;
    if (node.type !== "Reroute") return;
    const link = (_b = (_a = this.groupData.linksFrom[nodeId]) == null ? void 0 : _a[0]) == null ? void 0 : _b[0];
    if (!link) return;
    const [, , targetNodeId, targetNodeSlot] = link;
    const targetNode = this.groupData.nodeData.nodes[targetNodeId];
    const inputs = targetNode.inputs;
    const targetWidget = (_c = inputs == null ? void 0 : inputs[targetNodeSlot]) == null ? void 0 : _c.widget;
    if (!targetWidget) return;
    const offset = inputs.length - ((_e = (_d = targetNode.widgets_values) == null ? void 0 : _d.length) != null ? _e : 0);
    const v = (_f = targetNode.widgets_values) == null ? void 0 : _f[targetNodeSlot - offset];
    if (v == null) return;
    const widgetName = Object.values(map)[0];
    const widget = this.node.widgets.find((w) => w.name === widgetName);
    if (widget) {
      widget.value = v;
    }
  }
  populateWidgets() {
    var _a, _b, _c, _d, _e, _f;
    if (!this.node.widgets) return;
    for (let nodeId = 0; nodeId < this.groupData.nodeData.nodes.length; nodeId++) {
      const node = this.groupData.nodeData.nodes[nodeId];
      const map = (_a = this.groupData.oldToNewWidgetMap[nodeId]) != null ? _a : {};
      const widgets = Object.keys(map);
      if (!((_b = node.widgets_values) == null ? void 0 : _b.length)) {
        this.populateReroute(node, nodeId, map);
        continue;
      }
      let linkedShift = 0;
      for (let i = 0; i < widgets.length; i++) {
        const oldName = widgets[i];
        const newName = map[oldName];
        const widgetIndex = this.node.widgets.findIndex(
          (w) => w.name === newName
        );
        const mainWidget = this.node.widgets[widgetIndex];
        if (this.populatePrimitive(node, nodeId, oldName, i, linkedShift) || widgetIndex === -1) {
          const innerWidget = (_c = this.innerNodes[nodeId].widgets) == null ? void 0 : _c.find(
            (w) => w.name === oldName
          );
          linkedShift += (_e = (_d = innerWidget == null ? void 0 : innerWidget.linkedWidgets) == null ? void 0 : _d.length) != null ? _e : 0;
        }
        if (widgetIndex === -1) {
          continue;
        }
        mainWidget.value = node.widgets_values[i + linkedShift];
        for (let w = 0; w < ((_f = mainWidget.linkedWidgets) == null ? void 0 : _f.length); w++) {
          this.node.widgets[widgetIndex + w + 1].value = node.widgets_values[i + ++linkedShift];
        }
      }
    }
  }
  replaceNodes(nodes) {
    let top;
    let left;
    for (let i = 0; i < nodes.length; i++) {
      const node = nodes[i];
      if (left == null || node.pos[0] < left) {
        left = node.pos[0];
      }
      if (top == null || node.pos[1] < top) {
        top = node.pos[1];
      }
      this.linkOutputs(node, i);
      app.graph.remove(node);
    }
    this.linkInputs();
    this.node.pos = [left, top];
  }
  linkOutputs(originalNode, nodeId) {
    var _a;
    if (!originalNode.outputs) return;
    for (const output of originalNode.outputs) {
      if (!output.links) continue;
      const links = [...output.links];
      for (const l of links) {
        const link = app.graph.links[l];
        if (!link) continue;
        const targetNode = app.graph.getNodeById(link.target_id);
        const newSlot = (_a = this.groupData.oldToNewOutputMap[nodeId]) == null ? void 0 : _a[link.origin_slot];
        if (newSlot != null) {
          this.node.connect(newSlot, targetNode, link.target_slot);
        }
      }
    }
  }
  linkInputs() {
    var _a;
    for (const link of (_a = this.groupData.nodeData.links) != null ? _a : []) {
      const [, originSlot, targetId, targetSlot, actualOriginId] = link;
      const originNode = app.graph.getNodeById(actualOriginId);
      if (!originNode) continue;
      originNode.connect(
        originSlot,
        this.node.id,
        this.groupData.oldToNewInputMap[targetId][targetSlot]
      );
    }
  }
  static getGroupData(node) {
    var _a, _b, _c;
    return (_c = (_b = node.nodeData) != null ? _b : (_a = node.constructor) == null ? void 0 : _a.nodeData) == null ? void 0 : _c[GROUP];
  }
  static isGroupNode(node) {
    var _a, _b;
    return !!((_b = (_a = node.constructor) == null ? void 0 : _a.nodeData) == null ? void 0 : _b[GROUP]);
  }
  static fromNodes(nodes) {
    return __async(this, null, function* () {
      const builder = new GroupNodeBuilder(nodes);
      const res = builder.build();
      if (!res) return;
      const { name, nodeData } = res;
      const config = new GroupNodeConfig(name, nodeData);
      yield config.registerType();
      const groupNode = LiteGraph.createNode(`workflow/${name}`);
      groupNode.setInnerNodes(builder.nodes);
      groupNode[GROUP].populateWidgets();
      app.graph.add(groupNode);
      groupNode[GROUP].replaceNodes(builder.nodes);
      return groupNode;
    });
  }
};
__name(_GroupNodeHandler, "GroupNodeHandler");
let GroupNodeHandler = _GroupNodeHandler;
function addConvertToGroupOptions() {
  function addConvertOption(options, index) {
    var _a;
    const selected = Object.values((_a = app.canvas.selected_nodes) != null ? _a : {});
    const disabled = selected.length < 2 || selected.find((n) => GroupNodeHandler.isGroupNode(n));
    options.splice(index + 1, null, {
      content: `Convert to Group Node`,
      disabled,
      callback: /* @__PURE__ */ __name(() => __async(this, null, function* () {
        return yield GroupNodeHandler.fromNodes(selected);
      }), "callback")
    });
  }
  __name(addConvertOption, "addConvertOption");
  function addManageOption(options, index) {
    var _a;
    const groups = (_a = app.graph.extra) == null ? void 0 : _a.groupNodes;
    const disabled = !groups || !Object.keys(groups).length;
    options.splice(index + 1, null, {
      content: `Manage Group Nodes`,
      disabled,
      callback: /* @__PURE__ */ __name(() => {
        new ManageGroupDialog(app).show();
      }, "callback")
    });
  }
  __name(addManageOption, "addManageOption");
  const getCanvasMenuOptions = LGraphCanvas.prototype.getCanvasMenuOptions;
  LGraphCanvas.prototype.getCanvasMenuOptions = function() {
    const options = getCanvasMenuOptions.apply(this, arguments);
    const index = options.findIndex((o) => (o == null ? void 0 : o.content) === "Add Group") + 1 || options.length;
    addConvertOption(options, index);
    addManageOption(options, index + 1);
    return options;
  };
  const getNodeMenuOptions = LGraphCanvas.prototype.getNodeMenuOptions;
  LGraphCanvas.prototype.getNodeMenuOptions = function(node) {
    const options = getNodeMenuOptions.apply(this, arguments);
    if (!GroupNodeHandler.isGroupNode(node)) {
      const index = options.findIndex((o) => (o == null ? void 0 : o.content) === "Outputs") + 1 || options.length - 1;
      addConvertOption(options, index);
    }
    return options;
  };
}
__name(addConvertToGroupOptions, "addConvertToGroupOptions");
const id$3 = "Comfy.GroupNode";
let globalDefs;
const ext$1 = {
  name: id$3,
  setup() {
    addConvertToGroupOptions();
  },
  beforeConfigureGraph(graphData, missingNodeTypes) {
    return __async(this, null, function* () {
      var _a;
      const nodes = (_a = graphData == null ? void 0 : graphData.extra) == null ? void 0 : _a.groupNodes;
      if (nodes) {
        yield GroupNodeConfig.registerFromWorkflow(nodes, missingNodeTypes);
      }
    });
  },
  addCustomNodeDefs(defs) {
    globalDefs = defs;
  },
  nodeCreated(node) {
    if (GroupNodeHandler.isGroupNode(node)) {
      node[GROUP] = new GroupNodeHandler(node);
    }
  },
  refreshComboInNodes(defs) {
    return __async(this, null, function* () {
      var _a;
      Object.assign(globalDefs, defs);
      const nodes = (_a = app.graph.extra) == null ? void 0 : _a.groupNodes;
      if (nodes) {
        yield GroupNodeConfig.registerFromWorkflow(nodes, {});
      }
    });
  }
};
app.registerExtension(ext$1);
window.comfyAPI = window.comfyAPI || {};
window.comfyAPI.groupNode = window.comfyAPI.groupNode || {};
window.comfyAPI.groupNode.GroupNodeConfig = GroupNodeConfig;
window.comfyAPI.groupNode.GroupNodeHandler = GroupNodeHandler;
function setNodeMode(node, mode) {
  node.mode = mode;
  node.graph.change();
}
__name(setNodeMode, "setNodeMode");
function addNodesToGroup(group, nodes = []) {
  var _a;
  var x1, y1, x2, y2;
  var nx1, ny1, nx2, ny2;
  var node;
  x1 = y1 = x2 = y2 = -1;
  nx1 = ny1 = nx2 = ny2 = -1;
  for (var n of [group._nodes, nodes]) {
    for (var i in n) {
      node = n[i];
      nx1 = node.pos[0];
      ny1 = node.pos[1];
      nx2 = node.pos[0] + node.size[0];
      ny2 = node.pos[1] + node.size[1];
      if (node.type != "Reroute") {
        ny1 -= LiteGraph.NODE_TITLE_HEIGHT;
      }
      if ((_a = node.flags) == null ? void 0 : _a.collapsed) {
        ny2 = ny1 + LiteGraph.NODE_TITLE_HEIGHT;
        if (node == null ? void 0 : node._collapsed_width) {
          nx2 = nx1 + Math.round(node._collapsed_width);
        }
      }
      if (x1 == -1 || nx1 < x1) {
        x1 = nx1;
      }
      if (y1 == -1 || ny1 < y1) {
        y1 = ny1;
      }
      if (x2 == -1 || nx2 > x2) {
        x2 = nx2;
      }
      if (y2 == -1 || ny2 > y2) {
        y2 = ny2;
      }
    }
  }
  var padding = 10;
  y1 = y1 - Math.round(group.font_size * 1.4);
  group.pos = [x1 - padding, y1 - padding];
  group.size = [x2 - x1 + padding * 2, y2 - y1 + padding * 2];
}
__name(addNodesToGroup, "addNodesToGroup");
app.registerExtension({
  name: "Comfy.GroupOptions",
  setup() {
    const orig = LGraphCanvas.prototype.getCanvasMenuOptions;
    LGraphCanvas.prototype.getCanvasMenuOptions = function() {
      const options = orig.apply(this, arguments);
      const group = this.graph.getGroupOnPos(
        this.graph_mouse[0],
        this.graph_mouse[1]
      );
      if (!group) {
        options.push({
          content: "Add Group For Selected Nodes",
          disabled: !Object.keys(app.canvas.selected_nodes || {}).length,
          callback: /* @__PURE__ */ __name(() => {
            var group2 = new LiteGraph.LGraphGroup();
            addNodesToGroup(group2, this.selected_nodes);
            app.canvas.graph.add(group2);
            this.graph.change();
          }, "callback")
        });
        return options;
      }
      group.recomputeInsideNodes();
      const nodesInGroup = group._nodes;
      options.push({
        content: "Add Selected Nodes To Group",
        disabled: !Object.keys(app.canvas.selected_nodes || {}).length,
        callback: /* @__PURE__ */ __name(() => {
          addNodesToGroup(group, this.selected_nodes);
          this.graph.change();
        }, "callback")
      });
      if (nodesInGroup.length === 0) {
        return options;
      } else {
        options.push(null);
      }
      let allNodesAreSameMode = true;
      for (let i = 1; i < nodesInGroup.length; i++) {
        if (nodesInGroup[i].mode !== nodesInGroup[0].mode) {
          allNodesAreSameMode = false;
          break;
        }
      }
      options.push({
        content: "Fit Group To Nodes",
        callback: /* @__PURE__ */ __name(() => {
          addNodesToGroup(group);
          this.graph.change();
        }, "callback")
      });
      options.push({
        content: "Select Nodes",
        callback: /* @__PURE__ */ __name(() => {
          this.selectNodes(nodesInGroup);
          this.graph.change();
          this.canvas.focus();
        }, "callback")
      });
      if (allNodesAreSameMode) {
        const mode = nodesInGroup[0].mode;
        switch (mode) {
          case 0:
            options.push({
              content: "Set Group Nodes to Never",
              callback: /* @__PURE__ */ __name(() => {
                for (const node of nodesInGroup) {
                  setNodeMode(node, 2);
                }
              }, "callback")
            });
            options.push({
              content: "Bypass Group Nodes",
              callback: /* @__PURE__ */ __name(() => {
                for (const node of nodesInGroup) {
                  setNodeMode(node, 4);
                }
              }, "callback")
            });
            break;
          case 2:
            options.push({
              content: "Set Group Nodes to Always",
              callback: /* @__PURE__ */ __name(() => {
                for (const node of nodesInGroup) {
                  setNodeMode(node, 0);
                }
              }, "callback")
            });
            options.push({
              content: "Bypass Group Nodes",
              callback: /* @__PURE__ */ __name(() => {
                for (const node of nodesInGroup) {
                  setNodeMode(node, 4);
                }
              }, "callback")
            });
            break;
          case 4:
            options.push({
              content: "Set Group Nodes to Always",
              callback: /* @__PURE__ */ __name(() => {
                for (const node of nodesInGroup) {
                  setNodeMode(node, 0);
                }
              }, "callback")
            });
            options.push({
              content: "Set Group Nodes to Never",
              callback: /* @__PURE__ */ __name(() => {
                for (const node of nodesInGroup) {
                  setNodeMode(node, 2);
                }
              }, "callback")
            });
            break;
          default:
            options.push({
              content: "Set Group Nodes to Always",
              callback: /* @__PURE__ */ __name(() => {
                for (const node of nodesInGroup) {
                  setNodeMode(node, 0);
                }
              }, "callback")
            });
            options.push({
              content: "Set Group Nodes to Never",
              callback: /* @__PURE__ */ __name(() => {
                for (const node of nodesInGroup) {
                  setNodeMode(node, 2);
                }
              }, "callback")
            });
            options.push({
              content: "Bypass Group Nodes",
              callback: /* @__PURE__ */ __name(() => {
                for (const node of nodesInGroup) {
                  setNodeMode(node, 4);
                }
              }, "callback")
            });
            break;
        }
      } else {
        options.push({
          content: "Set Group Nodes to Always",
          callback: /* @__PURE__ */ __name(() => {
            for (const node of nodesInGroup) {
              setNodeMode(node, 0);
            }
          }, "callback")
        });
        options.push({
          content: "Set Group Nodes to Never",
          callback: /* @__PURE__ */ __name(() => {
            for (const node of nodesInGroup) {
              setNodeMode(node, 2);
            }
          }, "callback")
        });
        options.push({
          content: "Bypass Group Nodes",
          callback: /* @__PURE__ */ __name(() => {
            for (const node of nodesInGroup) {
              setNodeMode(node, 4);
            }
          }, "callback")
        });
      }
      return options;
    };
  }
});
const id$2 = "Comfy.InvertMenuScrolling";
app.registerExtension({
  name: id$2,
  init() {
    const ctxMenu = LiteGraph.ContextMenu;
    const replace = /* @__PURE__ */ __name(() => {
      LiteGraph.ContextMenu = function(values, options) {
        options = options || {};
        if (options.scroll_speed) {
          options.scroll_speed *= -1;
        } else {
          options.scroll_speed = -0.1;
        }
        return ctxMenu.call(this, values, options);
      };
      LiteGraph.ContextMenu.prototype = ctxMenu.prototype;
    }, "replace");
    app.ui.settings.addSetting({
      id: id$2,
      category: ["Comfy", "Graph", "InvertMenuScrolling"],
      name: "Invert Context Menu Scrolling",
      type: "boolean",
      defaultValue: false,
      onChange(value) {
        if (value) {
          replace();
        } else {
          LiteGraph.ContextMenu = ctxMenu;
        }
      }
    });
  }
});
app.registerExtension({
  name: "Comfy.Keybinds",
  init() {
    const keybindListener = /* @__PURE__ */ __name(function(event) {
      return __async(this, null, function* () {
        const modifierPressed = event.ctrlKey || event.metaKey;
        if (modifierPressed && event.key === "Enter") {
          if (event.altKey) {
            yield api.interrupt();
            useToastStore().add({
              severity: "info",
              summary: "Interrupted",
              detail: "Execution has been interrupted",
              life: 1e3
            });
            return;
          }
          app.queuePrompt(event.shiftKey ? -1 : 0).then();
          return;
        }
        const target = event.composedPath()[0];
        if (["INPUT", "TEXTAREA"].includes(target.tagName)) {
          return;
        }
        const modifierKeyIdMap = {
          s: "#comfy-save-button",
          o: "#comfy-file-input",
          Backspace: "#comfy-clear-button",
          d: "#comfy-load-default-button"
        };
        const modifierKeybindId = modifierKeyIdMap[event.key];
        if (modifierPressed && modifierKeybindId) {
          event.preventDefault();
          const elem = document.querySelector(modifierKeybindId);
          elem.click();
          return;
        }
        if (event.ctrlKey || event.altKey || event.metaKey) {
          return;
        }
        if (event.key === "Escape") {
          const modals = document.querySelectorAll(".comfy-modal");
          const modal = Array.from(modals).find(
            (modal2) => window.getComputedStyle(modal2).getPropertyValue("display") !== "none"
          );
          if (modal) {
            modal.style.display = "none";
          }
          ;
          [...document.querySelectorAll("dialog")].forEach((d) => {
            d.close();
          });
        }
        const keyIdMap = {
          q: ".queue-tab-button.side-bar-button",
          h: ".queue-tab-button.side-bar-button",
          r: "#comfy-refresh-button"
        };
        const buttonId = keyIdMap[event.key];
        if (buttonId) {
          const button = document.querySelector(buttonId);
          button.click();
        }
      });
    }, "keybindListener");
    window.addEventListener("keydown", keybindListener, true);
  }
});
const id$1 = "Comfy.LinkRenderMode";
const ext = {
  name: id$1,
  setup(app2) {
    return __async(this, null, function* () {
      app2.ui.settings.addSetting({
        id: id$1,
        category: ["Comfy", "Graph", "LinkRenderMode"],
        name: "Link Render Mode",
        defaultValue: 2,
        type: "combo",
        // @ts-expect-error
        options: [...LiteGraph.LINK_RENDER_MODES, "Hidden"].map((m, i) => ({
          value: i,
          text: m,
          selected: i == app2.canvas.links_render_mode
        })),
        onChange(value) {
          app2.canvas.links_render_mode = +value;
          app2.graph.setDirtyCanvas(true);
        }
      });
    });
  }
};
app.registerExtension(ext);
function dataURLToBlob(dataURL) {
  const parts = dataURL.split(";base64,");
  const contentType = parts[0].split(":")[1];
  const byteString = atob(parts[1]);
  const arrayBuffer = new ArrayBuffer(byteString.length);
  const uint8Array = new Uint8Array(arrayBuffer);
  for (let i = 0; i < byteString.length; i++) {
    uint8Array[i] = byteString.charCodeAt(i);
  }
  return new Blob([arrayBuffer], { type: contentType });
}
__name(dataURLToBlob, "dataURLToBlob");
function loadedImageToBlob(image) {
  const canvas = document.createElement("canvas");
  canvas.width = image.width;
  canvas.height = image.height;
  const ctx = canvas.getContext("2d");
  ctx.drawImage(image, 0, 0);
  const dataURL = canvas.toDataURL("image/png", 1);
  const blob = dataURLToBlob(dataURL);
  return blob;
}
__name(loadedImageToBlob, "loadedImageToBlob");
function loadImage(imagePath) {
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.onload = function() {
      resolve(image);
    };
    image.src = imagePath;
  });
}
__name(loadImage, "loadImage");
function uploadMask(filepath, formData) {
  return __async(this, null, function* () {
    yield api.fetchApi("/upload/mask", {
      method: "POST",
      body: formData
    }).then((response) => {
    }).catch((error) => {
      console.error("Error:", error);
    });
    ComfyApp.clipspace.imgs[ComfyApp.clipspace["selectedIndex"]] = new Image();
    ComfyApp.clipspace.imgs[ComfyApp.clipspace["selectedIndex"]].src = api.apiURL(
      "/view?" + new URLSearchParams(filepath).toString() + app.getPreviewFormatParam() + app.getRandParam()
    );
    if (ComfyApp.clipspace.images)
      ComfyApp.clipspace.images[ComfyApp.clipspace["selectedIndex"]] = filepath;
    ClipspaceDialog.invalidatePreview();
  });
}
__name(uploadMask, "uploadMask");
function prepare_mask(image, maskCanvas, maskCtx, maskColor) {
  maskCtx.drawImage(image, 0, 0, maskCanvas.width, maskCanvas.height);
  const maskData = maskCtx.getImageData(
    0,
    0,
    maskCanvas.width,
    maskCanvas.height
  );
  for (let i = 0; i < maskData.data.length; i += 4) {
    if (maskData.data[i + 3] == 255) maskData.data[i + 3] = 0;
    else maskData.data[i + 3] = 255;
    maskData.data[i] = maskColor.r;
    maskData.data[i + 1] = maskColor.g;
    maskData.data[i + 2] = maskColor.b;
  }
  maskCtx.globalCompositeOperation = "source-over";
  maskCtx.putImageData(maskData, 0, 0);
}
__name(prepare_mask, "prepare_mask");
const _MaskEditorDialog = class _MaskEditorDialog extends ComfyDialog {
  constructor() {
    super();
    __publicField(this, "brush");
    __publicField(this, "maskCtx");
    __publicField(this, "maskCanvas");
    __publicField(this, "brush_size_slider");
    __publicField(this, "brush_opacity_slider");
    __publicField(this, "colorButton");
    __publicField(this, "saveButton");
    __publicField(this, "zoom_ratio");
    __publicField(this, "pan_x");
    __publicField(this, "pan_y");
    __publicField(this, "imgCanvas");
    __publicField(this, "last_display_style");
    __publicField(this, "is_visible");
    __publicField(this, "image");
    __publicField(this, "handler_registered");
    __publicField(this, "brush_slider_input");
    __publicField(this, "cursorX");
    __publicField(this, "cursorY");
    __publicField(this, "mousedown_pan_x");
    __publicField(this, "mousedown_pan_y");
    __publicField(this, "last_pressure");
    __publicField(this, "is_layout_created", false);
    __publicField(this, "brush_opacity", 0.7);
    __publicField(this, "brush_size", 10);
    __publicField(this, "brush_color_mode", "black");
    __publicField(this, "drawing_mode", false);
    __publicField(this, "lastx", -1);
    __publicField(this, "lasty", -1);
    __publicField(this, "lasttime", 0);
    this.element = $el("div.comfy-modal", { parent: document.body }, [
      $el("div.comfy-modal-content", [...this.createButtons()])
    ]);
  }
  static getInstance() {
    if (!_MaskEditorDialog.instance) {
      _MaskEditorDialog.instance = new _MaskEditorDialog();
    }
    return _MaskEditorDialog.instance;
  }
  createButtons() {
    return [];
  }
  createButton(name, callback) {
    var button = document.createElement("button");
    button.style.pointerEvents = "auto";
    button.innerText = name;
    button.addEventListener("click", callback);
    return button;
  }
  createLeftButton(name, callback) {
    var button = this.createButton(name, callback);
    button.style.cssFloat = "left";
    button.style.marginRight = "4px";
    return button;
  }
  createRightButton(name, callback) {
    var button = this.createButton(name, callback);
    button.style.cssFloat = "right";
    button.style.marginLeft = "4px";
    return button;
  }
  createLeftSlider(self, name, callback) {
    const divElement = document.createElement("div");
    divElement.id = "maskeditor-slider";
    divElement.style.cssFloat = "left";
    divElement.style.fontFamily = "sans-serif";
    divElement.style.marginRight = "4px";
    divElement.style.color = "var(--input-text)";
    divElement.style.backgroundColor = "var(--comfy-input-bg)";
    divElement.style.borderRadius = "8px";
    divElement.style.borderColor = "var(--border-color)";
    divElement.style.borderStyle = "solid";
    divElement.style.fontSize = "15px";
    divElement.style.height = "21px";
    divElement.style.padding = "1px 6px";
    divElement.style.display = "flex";
    divElement.style.position = "relative";
    divElement.style.top = "2px";
    divElement.style.pointerEvents = "auto";
    self.brush_slider_input = document.createElement("input");
    self.brush_slider_input.setAttribute("type", "range");
    self.brush_slider_input.setAttribute("min", "1");
    self.brush_slider_input.setAttribute("max", "100");
    self.brush_slider_input.setAttribute("value", "10");
    const labelElement = document.createElement("label");
    labelElement.textContent = name;
    divElement.appendChild(labelElement);
    divElement.appendChild(self.brush_slider_input);
    self.brush_slider_input.addEventListener("change", callback);
    return divElement;
  }
  createOpacitySlider(self, name, callback) {
    const divElement = document.createElement("div");
    divElement.id = "maskeditor-opacity-slider";
    divElement.style.cssFloat = "left";
    divElement.style.fontFamily = "sans-serif";
    divElement.style.marginRight = "4px";
    divElement.style.color = "var(--input-text)";
    divElement.style.backgroundColor = "var(--comfy-input-bg)";
    divElement.style.borderRadius = "8px";
    divElement.style.borderColor = "var(--border-color)";
    divElement.style.borderStyle = "solid";
    divElement.style.fontSize = "15px";
    divElement.style.height = "21px";
    divElement.style.padding = "1px 6px";
    divElement.style.display = "flex";
    divElement.style.position = "relative";
    divElement.style.top = "2px";
    divElement.style.pointerEvents = "auto";
    self.opacity_slider_input = document.createElement("input");
    self.opacity_slider_input.setAttribute("type", "range");
    self.opacity_slider_input.setAttribute("min", "0.1");
    self.opacity_slider_input.setAttribute("max", "1.0");
    self.opacity_slider_input.setAttribute("step", "0.01");
    self.opacity_slider_input.setAttribute("value", "0.7");
    const labelElement = document.createElement("label");
    labelElement.textContent = name;
    divElement.appendChild(labelElement);
    divElement.appendChild(self.opacity_slider_input);
    self.opacity_slider_input.addEventListener("input", callback);
    return divElement;
  }
  setlayout(imgCanvas, maskCanvas) {
    const self = this;
    var bottom_panel = document.createElement("div");
    bottom_panel.style.position = "absolute";
    bottom_panel.style.bottom = "0px";
    bottom_panel.style.left = "20px";
    bottom_panel.style.right = "20px";
    bottom_panel.style.height = "50px";
    bottom_panel.style.pointerEvents = "none";
    var brush = document.createElement("div");
    brush.id = "brush";
    brush.style.backgroundColor = "transparent";
    brush.style.outline = "1px dashed black";
    brush.style.boxShadow = "0 0 0 1px white";
    brush.style.borderRadius = "50%";
    brush.style.MozBorderRadius = "50%";
    brush.style.WebkitBorderRadius = "50%";
    brush.style.position = "absolute";
    brush.style.zIndex = "8889";
    brush.style.pointerEvents = "none";
    this.brush = brush;
    this.element.appendChild(imgCanvas);
    this.element.appendChild(maskCanvas);
    this.element.appendChild(bottom_panel);
    document.body.appendChild(brush);
    var clearButton = this.createLeftButton("Clear", () => {
      self.maskCtx.clearRect(
        0,
        0,
        self.maskCanvas.width,
        self.maskCanvas.height
      );
    });
    this.brush_size_slider = this.createLeftSlider(
      self,
      "Thickness",
      (event) => {
        self.brush_size = event.target.value;
        self.updateBrushPreview(self);
      }
    );
    this.brush_opacity_slider = this.createOpacitySlider(
      self,
      "Opacity",
      (event) => {
        self.brush_opacity = event.target.value;
        if (self.brush_color_mode !== "negative") {
          self.maskCanvas.style.opacity = self.brush_opacity.toString();
        }
      }
    );
    this.colorButton = this.createLeftButton(this.getColorButtonText(), () => {
      if (self.brush_color_mode === "black") {
        self.brush_color_mode = "white";
      } else if (self.brush_color_mode === "white") {
        self.brush_color_mode = "negative";
      } else {
        self.brush_color_mode = "black";
      }
      self.updateWhenBrushColorModeChanged();
    });
    var cancelButton = this.createRightButton("Cancel", () => {
      document.removeEventListener("keydown", _MaskEditorDialog.handleKeyDown);
      self.close();
    });
    this.saveButton = this.createRightButton("Save", () => {
      document.removeEventListener("keydown", _MaskEditorDialog.handleKeyDown);
      self.save();
    });
    this.element.appendChild(imgCanvas);
    this.element.appendChild(maskCanvas);
    this.element.appendChild(bottom_panel);
    bottom_panel.appendChild(clearButton);
    bottom_panel.appendChild(this.saveButton);
    bottom_panel.appendChild(cancelButton);
    bottom_panel.appendChild(this.brush_size_slider);
    bottom_panel.appendChild(this.brush_opacity_slider);
    bottom_panel.appendChild(this.colorButton);
    imgCanvas.style.position = "absolute";
    maskCanvas.style.position = "absolute";
    imgCanvas.style.top = "200";
    imgCanvas.style.left = "0";
    maskCanvas.style.top = imgCanvas.style.top;
    maskCanvas.style.left = imgCanvas.style.left;
    const maskCanvasStyle = this.getMaskCanvasStyle();
    maskCanvas.style.mixBlendMode = maskCanvasStyle.mixBlendMode;
    maskCanvas.style.opacity = maskCanvasStyle.opacity.toString();
  }
  show() {
    return __async(this, null, function* () {
      this.zoom_ratio = 1;
      this.pan_x = 0;
      this.pan_y = 0;
      if (!this.is_layout_created) {
        const imgCanvas = document.createElement("canvas");
        const maskCanvas = document.createElement("canvas");
        imgCanvas.id = "imageCanvas";
        maskCanvas.id = "maskCanvas";
        this.setlayout(imgCanvas, maskCanvas);
        this.imgCanvas = imgCanvas;
        this.maskCanvas = maskCanvas;
        this.maskCtx = maskCanvas.getContext("2d", { willReadFrequently: true });
        this.setEventHandler(maskCanvas);
        this.is_layout_created = true;
        const self = this;
        const observer = new MutationObserver(function(mutations) {
          mutations.forEach(function(mutation) {
            if (mutation.type === "attributes" && mutation.attributeName === "style") {
              if (self.last_display_style && self.last_display_style != "none" && self.element.style.display == "none") {
                self.brush.style.display = "none";
                ComfyApp.onClipspaceEditorClosed();
              }
              self.last_display_style = self.element.style.display;
            }
          });
        });
        const config = { attributes: true };
        observer.observe(this.element, config);
      }
      document.addEventListener("keydown", _MaskEditorDialog.handleKeyDown);
      if (ComfyApp.clipspace_return_node) {
        this.saveButton.innerText = "Save to node";
      } else {
        this.saveButton.innerText = "Save";
      }
      this.saveButton.disabled = false;
      this.element.style.display = "block";
      this.element.style.width = "85%";
      this.element.style.margin = "0 7.5%";
      this.element.style.height = "100vh";
      this.element.style.top = "50%";
      this.element.style.left = "42%";
      this.element.style.zIndex = "8888";
      yield this.setImages(this.imgCanvas);
      this.is_visible = true;
    });
  }
  isOpened() {
    return this.element.style.display == "block";
  }
  invalidateCanvas(orig_image, mask_image) {
    this.imgCanvas.width = orig_image.width;
    this.imgCanvas.height = orig_image.height;
    this.maskCanvas.width = orig_image.width;
    this.maskCanvas.height = orig_image.height;
    let imgCtx = this.imgCanvas.getContext("2d", { willReadFrequently: true });
    let maskCtx = this.maskCanvas.getContext("2d", {
      willReadFrequently: true
    });
    imgCtx.drawImage(orig_image, 0, 0, orig_image.width, orig_image.height);
    prepare_mask(mask_image, this.maskCanvas, maskCtx, this.getMaskColor());
  }
  setImages(imgCanvas) {
    return __async(this, null, function* () {
      let self = this;
      const imgCtx = imgCanvas.getContext("2d", { willReadFrequently: true });
      const maskCtx = this.maskCtx;
      const maskCanvas = this.maskCanvas;
      imgCtx.clearRect(0, 0, this.imgCanvas.width, this.imgCanvas.height);
      maskCtx.clearRect(0, 0, this.maskCanvas.width, this.maskCanvas.height);
      const filepath = ComfyApp.clipspace.images;
      const alpha_url = new URL(
        ComfyApp.clipspace.imgs[ComfyApp.clipspace["selectedIndex"]].src
      );
      alpha_url.searchParams.delete("channel");
      alpha_url.searchParams.delete("preview");
      alpha_url.searchParams.set("channel", "a");
      let mask_image = yield loadImage(alpha_url);
      const rgb_url = new URL(
        ComfyApp.clipspace.imgs[ComfyApp.clipspace["selectedIndex"]].src
      );
      rgb_url.searchParams.delete("channel");
      rgb_url.searchParams.set("channel", "rgb");
      this.image = new Image();
      this.image.onload = function() {
        maskCanvas.width = self.image.width;
        maskCanvas.height = self.image.height;
        self.invalidateCanvas(self.image, mask_image);
        self.initializeCanvasPanZoom();
      };
      this.image.src = rgb_url.toString();
    });
  }
  initializeCanvasPanZoom() {
    let drawWidth = this.image.width;
    let drawHeight = this.image.height;
    let width = this.element.clientWidth;
    let height = this.element.clientHeight;
    if (this.image.width > width) {
      drawWidth = width;
      drawHeight = drawWidth / this.image.width * this.image.height;
    }
    if (drawHeight > height) {
      drawHeight = height;
      drawWidth = drawHeight / this.image.height * this.image.width;
    }
    this.zoom_ratio = drawWidth / this.image.width;
    const canvasX = (width - drawWidth) / 2;
    const canvasY = (height - drawHeight) / 2;
    this.pan_x = canvasX;
    this.pan_y = canvasY;
    this.invalidatePanZoom();
  }
  invalidatePanZoom() {
    let raw_width = this.image.width * this.zoom_ratio;
    let raw_height = this.image.height * this.zoom_ratio;
    if (this.pan_x + raw_width < 10) {
      this.pan_x = 10 - raw_width;
    }
    if (this.pan_y + raw_height < 10) {
      this.pan_y = 10 - raw_height;
    }
    let width = `${raw_width}px`;
    let height = `${raw_height}px`;
    let left = `${this.pan_x}px`;
    let top = `${this.pan_y}px`;
    this.maskCanvas.style.width = width;
    this.maskCanvas.style.height = height;
    this.maskCanvas.style.left = left;
    this.maskCanvas.style.top = top;
    this.imgCanvas.style.width = width;
    this.imgCanvas.style.height = height;
    this.imgCanvas.style.left = left;
    this.imgCanvas.style.top = top;
  }
  setEventHandler(maskCanvas) {
    const self = this;
    if (!this.handler_registered) {
      maskCanvas.addEventListener("contextmenu", (event) => {
        event.preventDefault();
      });
      this.element.addEventListener(
        "wheel",
        (event) => this.handleWheelEvent(self, event)
      );
      this.element.addEventListener(
        "pointermove",
        (event) => this.pointMoveEvent(self, event)
      );
      this.element.addEventListener(
        "touchmove",
        (event) => this.pointMoveEvent(self, event)
      );
      this.element.addEventListener("dragstart", (event) => {
        if (event.ctrlKey) {
          event.preventDefault();
        }
      });
      maskCanvas.addEventListener(
        "pointerdown",
        (event) => this.handlePointerDown(self, event)
      );
      maskCanvas.addEventListener(
        "pointermove",
        (event) => this.draw_move(self, event)
      );
      maskCanvas.addEventListener(
        "touchmove",
        (event) => this.draw_move(self, event)
      );
      maskCanvas.addEventListener("pointerover", (event) => {
        this.brush.style.display = "block";
      });
      maskCanvas.addEventListener("pointerleave", (event) => {
        this.brush.style.display = "none";
      });
      document.addEventListener("pointerup", _MaskEditorDialog.handlePointerUp);
      this.handler_registered = true;
    }
  }
  getMaskCanvasStyle() {
    if (this.brush_color_mode === "negative") {
      return {
        mixBlendMode: "difference",
        opacity: "1"
      };
    } else {
      return {
        mixBlendMode: "initial",
        opacity: this.brush_opacity
      };
    }
  }
  getMaskColor() {
    if (this.brush_color_mode === "black") {
      return { r: 0, g: 0, b: 0 };
    }
    if (this.brush_color_mode === "white") {
      return { r: 255, g: 255, b: 255 };
    }
    if (this.brush_color_mode === "negative") {
      return { r: 255, g: 255, b: 255 };
    }
    return { r: 0, g: 0, b: 0 };
  }
  getMaskFillStyle() {
    const maskColor = this.getMaskColor();
    return "rgb(" + maskColor.r + "," + maskColor.g + "," + maskColor.b + ")";
  }
  getColorButtonText() {
    let colorCaption = "unknown";
    if (this.brush_color_mode === "black") {
      colorCaption = "black";
    } else if (this.brush_color_mode === "white") {
      colorCaption = "white";
    } else if (this.brush_color_mode === "negative") {
      colorCaption = "negative";
    }
    return "Color: " + colorCaption;
  }
  updateWhenBrushColorModeChanged() {
    this.colorButton.innerText = this.getColorButtonText();
    const maskCanvasStyle = this.getMaskCanvasStyle();
    this.maskCanvas.style.mixBlendMode = maskCanvasStyle.mixBlendMode;
    this.maskCanvas.style.opacity = maskCanvasStyle.opacity.toString();
    const maskColor = this.getMaskColor();
    const maskData = this.maskCtx.getImageData(
      0,
      0,
      this.maskCanvas.width,
      this.maskCanvas.height
    );
    for (let i = 0; i < maskData.data.length; i += 4) {
      maskData.data[i] = maskColor.r;
      maskData.data[i + 1] = maskColor.g;
      maskData.data[i + 2] = maskColor.b;
    }
    this.maskCtx.putImageData(maskData, 0, 0);
  }
  static handleKeyDown(event) {
    const self = _MaskEditorDialog.instance;
    if (event.key === "]") {
      self.brush_size = Math.min(self.brush_size + 2, 100);
      self.brush_slider_input.value = self.brush_size;
    } else if (event.key === "[") {
      self.brush_size = Math.max(self.brush_size - 2, 1);
      self.brush_slider_input.value = self.brush_size;
    } else if (event.key === "Enter") {
      self.save();
    }
    self.updateBrushPreview(self);
  }
  static handlePointerUp(event) {
    event.preventDefault();
    this.mousedown_x = null;
    this.mousedown_y = null;
    _MaskEditorDialog.instance.drawing_mode = false;
  }
  updateBrushPreview(self) {
    const brush = self.brush;
    var centerX = self.cursorX;
    var centerY = self.cursorY;
    brush.style.width = self.brush_size * 2 * this.zoom_ratio + "px";
    brush.style.height = self.brush_size * 2 * this.zoom_ratio + "px";
    brush.style.left = centerX - self.brush_size * this.zoom_ratio + "px";
    brush.style.top = centerY - self.brush_size * this.zoom_ratio + "px";
  }
  handleWheelEvent(self, event) {
    event.preventDefault();
    if (event.ctrlKey) {
      if (event.deltaY < 0) {
        this.zoom_ratio = Math.min(10, this.zoom_ratio + 0.2);
      } else {
        this.zoom_ratio = Math.max(0.2, this.zoom_ratio - 0.2);
      }
      this.invalidatePanZoom();
    } else {
      if (event.deltaY < 0) this.brush_size = Math.min(this.brush_size + 2, 100);
      else this.brush_size = Math.max(this.brush_size - 2, 1);
      this.brush_slider_input.value = this.brush_size.toString();
      this.updateBrushPreview(this);
    }
  }
  pointMoveEvent(self, event) {
    this.cursorX = event.pageX;
    this.cursorY = event.pageY;
    self.updateBrushPreview(self);
    if (event.ctrlKey) {
      event.preventDefault();
      self.pan_move(self, event);
    }
    let left_button_down = window.TouchEvent && event instanceof TouchEvent || event.buttons == 1;
    if (event.shiftKey && left_button_down) {
      self.drawing_mode = false;
      const y = event.clientY;
      let delta = (self.zoom_lasty - y) * 5e-3;
      self.zoom_ratio = Math.max(
        Math.min(10, self.last_zoom_ratio - delta),
        0.2
      );
      this.invalidatePanZoom();
      return;
    }
  }
  pan_move(self, event) {
    if (event.buttons == 1) {
      if (_MaskEditorDialog.mousedown_x) {
        let deltaX = _MaskEditorDialog.mousedown_x - event.clientX;
        let deltaY = _MaskEditorDialog.mousedown_y - event.clientY;
        self.pan_x = this.mousedown_pan_x - deltaX;
        self.pan_y = this.mousedown_pan_y - deltaY;
        self.invalidatePanZoom();
      }
    }
  }
  draw_move(self, event) {
    if (event.ctrlKey || event.shiftKey) {
      return;
    }
    event.preventDefault();
    this.cursorX = event.pageX;
    this.cursorY = event.pageY;
    self.updateBrushPreview(self);
    let left_button_down = window.TouchEvent && event instanceof TouchEvent || event.buttons == 1;
    let right_button_down = [2, 5, 32].includes(event.buttons);
    if (!event.altKey && left_button_down) {
      var diff = performance.now() - self.lasttime;
      const maskRect = self.maskCanvas.getBoundingClientRect();
      var x = event.offsetX;
      var y = event.offsetY;
      if (event.offsetX == null) {
        x = event.targetTouches[0].clientX - maskRect.left;
      }
      if (event.offsetY == null) {
        y = event.targetTouches[0].clientY - maskRect.top;
      }
      x /= self.zoom_ratio;
      y /= self.zoom_ratio;
      var brush_size = this.brush_size;
      if (event instanceof PointerEvent && event.pointerType == "pen") {
        brush_size *= event.pressure;
        this.last_pressure = event.pressure;
      } else if (window.TouchEvent && event instanceof TouchEvent && diff < 20) {
        brush_size *= this.last_pressure;
      } else {
        brush_size = this.brush_size;
      }
      if (diff > 20 && !this.drawing_mode)
        requestAnimationFrame(() => {
          self.maskCtx.beginPath();
          self.maskCtx.fillStyle = this.getMaskFillStyle();
          self.maskCtx.globalCompositeOperation = "source-over";
          self.maskCtx.arc(x, y, brush_size, 0, Math.PI * 2, false);
          self.maskCtx.fill();
          self.lastx = x;
          self.lasty = y;
        });
      else
        requestAnimationFrame(() => {
          self.maskCtx.beginPath();
          self.maskCtx.fillStyle = this.getMaskFillStyle();
          self.maskCtx.globalCompositeOperation = "source-over";
          var dx = x - self.lastx;
          var dy = y - self.lasty;
          var distance = Math.sqrt(dx * dx + dy * dy);
          var directionX = dx / distance;
          var directionY = dy / distance;
          for (var i = 0; i < distance; i += 5) {
            var px = self.lastx + directionX * i;
            var py = self.lasty + directionY * i;
            self.maskCtx.arc(px, py, brush_size, 0, Math.PI * 2, false);
            self.maskCtx.fill();
          }
          self.lastx = x;
          self.lasty = y;
        });
      self.lasttime = performance.now();
    } else if (event.altKey && left_button_down || right_button_down) {
      const maskRect = self.maskCanvas.getBoundingClientRect();
      const x2 = (event.offsetX || event.targetTouches[0].clientX - maskRect.left) / self.zoom_ratio;
      const y2 = (event.offsetY || event.targetTouches[0].clientY - maskRect.top) / self.zoom_ratio;
      var brush_size = this.brush_size;
      if (event instanceof PointerEvent && event.pointerType == "pen") {
        brush_size *= event.pressure;
        this.last_pressure = event.pressure;
      } else if (window.TouchEvent && event instanceof TouchEvent && diff < 20) {
        brush_size *= this.last_pressure;
      } else {
        brush_size = this.brush_size;
      }
      if (diff > 20 && !this.drawing_mode)
        requestAnimationFrame(() => {
          self.maskCtx.beginPath();
          self.maskCtx.globalCompositeOperation = "destination-out";
          self.maskCtx.arc(x2, y2, brush_size, 0, Math.PI * 2, false);
          self.maskCtx.fill();
          self.lastx = x2;
          self.lasty = y2;
        });
      else
        requestAnimationFrame(() => {
          self.maskCtx.beginPath();
          self.maskCtx.globalCompositeOperation = "destination-out";
          var dx = x2 - self.lastx;
          var dy = y2 - self.lasty;
          var distance = Math.sqrt(dx * dx + dy * dy);
          var directionX = dx / distance;
          var directionY = dy / distance;
          for (var i = 0; i < distance; i += 5) {
            var px = self.lastx + directionX * i;
            var py = self.lasty + directionY * i;
            self.maskCtx.arc(px, py, brush_size, 0, Math.PI * 2, false);
            self.maskCtx.fill();
          }
          self.lastx = x2;
          self.lasty = y2;
        });
      self.lasttime = performance.now();
    }
  }
  handlePointerDown(self, event) {
    if (event.ctrlKey) {
      if (event.buttons == 1) {
        _MaskEditorDialog.mousedown_x = event.clientX;
        _MaskEditorDialog.mousedown_y = event.clientY;
        this.mousedown_pan_x = this.pan_x;
        this.mousedown_pan_y = this.pan_y;
      }
      return;
    }
    var brush_size = this.brush_size;
    if (event instanceof PointerEvent && event.pointerType == "pen") {
      brush_size *= event.pressure;
      this.last_pressure = event.pressure;
    }
    if ([0, 2, 5].includes(event.button)) {
      self.drawing_mode = true;
      event.preventDefault();
      if (event.shiftKey) {
        self.zoom_lasty = event.clientY;
        self.last_zoom_ratio = self.zoom_ratio;
        return;
      }
      const maskRect = self.maskCanvas.getBoundingClientRect();
      const x = (event.offsetX || event.targetTouches[0].clientX - maskRect.left) / self.zoom_ratio;
      const y = (event.offsetY || event.targetTouches[0].clientY - maskRect.top) / self.zoom_ratio;
      self.maskCtx.beginPath();
      if (!event.altKey && event.button == 0) {
        self.maskCtx.fillStyle = this.getMaskFillStyle();
        self.maskCtx.globalCompositeOperation = "source-over";
      } else {
        self.maskCtx.globalCompositeOperation = "destination-out";
      }
      self.maskCtx.arc(x, y, brush_size, 0, Math.PI * 2, false);
      self.maskCtx.fill();
      self.lastx = x;
      self.lasty = y;
      self.lasttime = performance.now();
    }
  }
  save() {
    return __async(this, null, function* () {
      const backupCanvas = document.createElement("canvas");
      const backupCtx = backupCanvas.getContext("2d", {
        willReadFrequently: true
      });
      backupCanvas.width = this.image.width;
      backupCanvas.height = this.image.height;
      backupCtx.clearRect(0, 0, backupCanvas.width, backupCanvas.height);
      backupCtx.drawImage(
        this.maskCanvas,
        0,
        0,
        this.maskCanvas.width,
        this.maskCanvas.height,
        0,
        0,
        backupCanvas.width,
        backupCanvas.height
      );
      const backupData = backupCtx.getImageData(
        0,
        0,
        backupCanvas.width,
        backupCanvas.height
      );
      for (let i = 0; i < backupData.data.length; i += 4) {
        if (backupData.data[i + 3] == 255) backupData.data[i + 3] = 0;
        else backupData.data[i + 3] = 255;
        backupData.data[i] = 0;
        backupData.data[i + 1] = 0;
        backupData.data[i + 2] = 0;
      }
      backupCtx.globalCompositeOperation = "source-over";
      backupCtx.putImageData(backupData, 0, 0);
      const formData = new FormData();
      const filename = "clipspace-mask-" + performance.now() + ".png";
      const item = {
        filename,
        subfolder: "clipspace",
        type: "input"
      };
      if (ComfyApp.clipspace.images) ComfyApp.clipspace.images[0] = item;
      if (ComfyApp.clipspace.widgets) {
        const index = ComfyApp.clipspace.widgets.findIndex(
          (obj) => obj.name === "image"
        );
        if (index >= 0) ComfyApp.clipspace.widgets[index].value = item;
      }
      const dataURL = backupCanvas.toDataURL();
      const blob = dataURLToBlob(dataURL);
      let original_url = new URL(this.image.src);
      const original_ref = {
        filename: original_url.searchParams.get("filename")
      };
      let original_subfolder = original_url.searchParams.get("subfolder");
      if (original_subfolder) original_ref.subfolder = original_subfolder;
      let original_type = original_url.searchParams.get("type");
      if (original_type) original_ref.type = original_type;
      formData.append("image", blob, filename);
      formData.append("original_ref", JSON.stringify(original_ref));
      formData.append("type", "input");
      formData.append("subfolder", "clipspace");
      this.saveButton.innerText = "Saving...";
      this.saveButton.disabled = true;
      yield uploadMask(item, formData);
      ComfyApp.onClipspaceEditorSave();
      this.close();
    });
  }
};
__name(_MaskEditorDialog, "MaskEditorDialog");
__publicField(_MaskEditorDialog, "instance", null);
__publicField(_MaskEditorDialog, "mousedown_x", null);
__publicField(_MaskEditorDialog, "mousedown_y", null);
let MaskEditorDialog = _MaskEditorDialog;
app.registerExtension({
  name: "Comfy.MaskEditor",
  init(app2) {
    ComfyApp.open_maskeditor = function() {
      const dlg = MaskEditorDialog.getInstance();
      if (!dlg.isOpened()) {
        dlg.show();
      }
    };
    const context_predicate = /* @__PURE__ */ __name(() => ComfyApp.clipspace && ComfyApp.clipspace.imgs && ComfyApp.clipspace.imgs.length > 0, "context_predicate");
    ClipspaceDialog.registerButton(
      "MaskEditor",
      context_predicate,
      ComfyApp.open_maskeditor
    );
  }
});
const id = "Comfy.NodeTemplates";
const file = "comfy.templates.json";
const _ManageTemplates = class _ManageTemplates extends ComfyDialog {
  constructor() {
    super();
    __publicField(this, "templates");
    __publicField(this, "draggedEl");
    __publicField(this, "saveVisualCue");
    __publicField(this, "emptyImg");
    __publicField(this, "importInput");
    this.load().then((v) => {
      this.templates = v;
    });
    this.element.classList.add("comfy-manage-templates");
    this.draggedEl = null;
    this.saveVisualCue = null;
    this.emptyImg = new Image();
    this.emptyImg.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
    this.importInput = $el("input", {
      type: "file",
      accept: ".json",
      multiple: true,
      style: { display: "none" },
      parent: document.body,
      onchange: /* @__PURE__ */ __name(() => this.importAll(), "onchange")
    });
  }
  createButtons() {
    const btns = super.createButtons();
    btns[0].textContent = "Close";
    btns[0].onclick = (e) => {
      clearTimeout(this.saveVisualCue);
      this.close();
    };
    btns.unshift(
      $el("button", {
        type: "button",
        textContent: "Export",
        onclick: /* @__PURE__ */ __name(() => this.exportAll(), "onclick")
      })
    );
    btns.unshift(
      $el("button", {
        type: "button",
        textContent: "Import",
        onclick: /* @__PURE__ */ __name(() => {
          this.importInput.click();
        }, "onclick")
      })
    );
    return btns;
  }
  load() {
    return __async(this, null, function* () {
      let templates = [];
      if (app.storageLocation === "server") {
        if (app.isNewUserSession) {
          const json = localStorage.getItem(id);
          if (json) {
            templates = JSON.parse(json);
          }
          yield api.storeUserData(file, json, { stringify: false });
        } else {
          const res = yield api.getUserData(file);
          if (res.status === 200) {
            try {
              templates = yield res.json();
            } catch (error) {
            }
          } else if (res.status !== 404) {
            console.error(res.status + " " + res.statusText);
          }
        }
      } else {
        const json = localStorage.getItem(id);
        if (json) {
          templates = JSON.parse(json);
        }
      }
      return templates != null ? templates : [];
    });
  }
  store() {
    return __async(this, null, function* () {
      if (app.storageLocation === "server") {
        const templates = JSON.stringify(this.templates, void 0, 4);
        localStorage.setItem(id, templates);
        try {
          yield api.storeUserData(file, templates, { stringify: false });
        } catch (error) {
          console.error(error);
          alert(error.message);
        }
      } else {
        localStorage.setItem(id, JSON.stringify(this.templates));
      }
    });
  }
  importAll() {
    return __async(this, null, function* () {
      for (const file2 of this.importInput.files) {
        if (file2.type === "application/json" || file2.name.endsWith(".json")) {
          const reader = new FileReader();
          reader.onload = () => __async(this, null, function* () {
            const importFile = JSON.parse(reader.result);
            if (importFile == null ? void 0 : importFile.templates) {
              for (const template of importFile.templates) {
                if ((template == null ? void 0 : template.name) && (template == null ? void 0 : template.data)) {
                  this.templates.push(template);
                }
              }
              yield this.store();
            }
          });
          yield reader.readAsText(file2);
        }
      }
      this.importInput.value = null;
      this.close();
    });
  }
  exportAll() {
    if (this.templates.length == 0) {
      alert("No templates to export.");
      return;
    }
    const json = JSON.stringify({ templates: this.templates }, null, 2);
    const blob = new Blob([json], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const a = $el("a", {
      href: url,
      download: "node_templates.json",
      style: { display: "none" },
      parent: document.body
    });
    a.click();
    setTimeout(function() {
      a.remove();
      window.URL.revokeObjectURL(url);
    }, 0);
  }
  show() {
    super.show(
      $el(
        "div",
        {},
        this.templates.flatMap((t, i) => {
          let nameInput;
          return [
            $el(
              "div",
              {
                dataset: { id: i.toString() },
                className: "templateManagerRow",
                style: {
                  display: "grid",
                  gridTemplateColumns: "1fr auto",
                  border: "1px dashed transparent",
                  gap: "5px",
                  backgroundColor: "var(--comfy-menu-bg)"
                },
                ondragstart: /* @__PURE__ */ __name((e) => {
                  this.draggedEl = e.currentTarget;
                  e.currentTarget.style.opacity = "0.6";
                  e.currentTarget.style.border = "1px dashed yellow";
                  e.dataTransfer.effectAllowed = "move";
                  e.dataTransfer.setDragImage(this.emptyImg, 0, 0);
                }, "ondragstart"),
                ondragend: /* @__PURE__ */ __name((e) => {
                  e.target.style.opacity = "1";
                  e.currentTarget.style.border = "1px dashed transparent";
                  e.currentTarget.removeAttribute("draggable");
                  this.element.querySelectorAll(".templateManagerRow").forEach((el, i2) => {
                    var prev_i = Number.parseInt(el.dataset.id);
                    if (el == this.draggedEl && prev_i != i2) {
                      this.templates.splice(
                        i2,
                        0,
                        this.templates.splice(prev_i, 1)[0]
                      );
                    }
                    el.dataset.id = i2.toString();
                  });
                  this.store();
                }, "ondragend"),
                ondragover: /* @__PURE__ */ __name((e) => {
                  e.preventDefault();
                  if (e.currentTarget == this.draggedEl) return;
                  let rect = e.currentTarget.getBoundingClientRect();
                  if (e.clientY > rect.top + rect.height / 2) {
                    e.currentTarget.parentNode.insertBefore(
                      this.draggedEl,
                      e.currentTarget.nextSibling
                    );
                  } else {
                    e.currentTarget.parentNode.insertBefore(
                      this.draggedEl,
                      e.currentTarget
                    );
                  }
                }, "ondragover")
              },
              [
                $el(
                  "label",
                  {
                    textContent: "Name: ",
                    style: {
                      cursor: "grab"
                    },
                    onmousedown: /* @__PURE__ */ __name((e) => {
                      if (e.target.localName == "label")
                        e.currentTarget.parentNode.draggable = "true";
                    }, "onmousedown")
                  },
                  [
                    $el("input", {
                      value: t.name,
                      dataset: { name: t.name },
                      style: {
                        transitionProperty: "background-color",
                        transitionDuration: "0s"
                      },
                      onchange: /* @__PURE__ */ __name((e) => {
                        clearTimeout(this.saveVisualCue);
                        var el = e.target;
                        var row = el.parentNode.parentNode;
                        this.templates[row.dataset.id].name = el.value.trim() || "untitled";
                        this.store();
                        el.style.backgroundColor = "rgb(40, 95, 40)";
                        el.style.transitionDuration = "0s";
                        this.saveVisualCue = setTimeout(function() {
                          el.style.transitionDuration = ".7s";
                          el.style.backgroundColor = "var(--comfy-input-bg)";
                        }, 15);
                      }, "onchange"),
                      onkeypress: /* @__PURE__ */ __name((e) => {
                        var el = e.target;
                        clearTimeout(this.saveVisualCue);
                        el.style.transitionDuration = "0s";
                        el.style.backgroundColor = "var(--comfy-input-bg)";
                      }, "onkeypress"),
                      $: /* @__PURE__ */ __name((el) => nameInput = el, "$")
                    })
                  ]
                ),
                $el("div", {}, [
                  $el("button", {
                    textContent: "Export",
                    style: {
                      fontSize: "12px",
                      fontWeight: "normal"
                    },
                    onclick: /* @__PURE__ */ __name((e) => {
                      const json = JSON.stringify({ templates: [t] }, null, 2);
                      const blob = new Blob([json], {
                        type: "application/json"
                      });
                      const url = URL.createObjectURL(blob);
                      const a = $el("a", {
                        href: url,
                        download: (nameInput.value || t.name) + ".json",
                        style: { display: "none" },
                        parent: document.body
                      });
                      a.click();
                      setTimeout(function() {
                        a.remove();
                        window.URL.revokeObjectURL(url);
                      }, 0);
                    }, "onclick")
                  }),
                  $el("button", {
                    textContent: "Delete",
                    style: {
                      fontSize: "12px",
                      color: "red",
                      fontWeight: "normal"
                    },
                    onclick: /* @__PURE__ */ __name((e) => {
                      const item = e.target.parentNode.parentNode;
                      item.parentNode.removeChild(item);
                      this.templates.splice(item.dataset.id * 1, 1);
                      this.store();
                      var that = this;
                      setTimeout(function() {
                        that.element.querySelectorAll(".templateManagerRow").forEach((el, i2) => {
                          el.dataset.id = i2.toString();
                        });
                      }, 0);
                    }, "onclick")
                  })
                ])
              ]
            )
          ];
        })
      )
    );
  }
};
__name(_ManageTemplates, "ManageTemplates");
let ManageTemplates = _ManageTemplates;
app.registerExtension({
  name: id,
  setup() {
    const manage = new ManageTemplates();
    const clipboardAction = /* @__PURE__ */ __name((cb) => __async(this, null, function* () {
      const old = localStorage.getItem("litegrapheditor_clipboard");
      yield cb();
      localStorage.setItem("litegrapheditor_clipboard", old);
    }), "clipboardAction");
    const orig = LGraphCanvas.prototype.getCanvasMenuOptions;
    LGraphCanvas.prototype.getCanvasMenuOptions = function() {
      const options = orig.apply(this, arguments);
      options.push(null);
      options.push({
        content: `Save Selected as Template`,
        disabled: !Object.keys(app.canvas.selected_nodes || {}).length,
        callback: /* @__PURE__ */ __name(() => {
          const name = prompt("Enter name");
          if (!(name == null ? void 0 : name.trim())) return;
          clipboardAction(() => {
            app.canvas.copyToClipboard();
            let data = localStorage.getItem("litegrapheditor_clipboard");
            data = JSON.parse(data);
            const nodeIds = Object.keys(app.canvas.selected_nodes);
            for (let i = 0; i < nodeIds.length; i++) {
              const node = app.graph.getNodeById(Number.parseInt(nodeIds[i]));
              const nodeData = node == null ? void 0 : node.constructor.nodeData;
              let groupData = GroupNodeHandler.getGroupData(node);
              if (groupData) {
                groupData = groupData.nodeData;
                if (!data.groupNodes) {
                  data.groupNodes = {};
                }
                data.groupNodes[nodeData.name] = groupData;
                data.nodes[i].type = nodeData.name;
              }
            }
            manage.templates.push({
              name,
              data: JSON.stringify(data)
            });
            manage.store();
          });
        }, "callback")
      });
      const subItems = manage.templates.map((t) => {
        return {
          content: t.name,
          callback: /* @__PURE__ */ __name(() => {
            clipboardAction(() => __async(this, null, function* () {
              const data = JSON.parse(t.data);
              yield GroupNodeConfig.registerFromWorkflow(data.groupNodes, {});
              localStorage.setItem("litegrapheditor_clipboard", t.data);
              app.canvas.pasteFromClipboard();
            }));
          }, "callback")
        };
      });
      subItems.push(null, {
        content: "Manage",
        callback: /* @__PURE__ */ __name(() => manage.show(), "callback")
      });
      options.push({
        content: "Node Templates",
        submenu: {
          options: subItems
        }
      });
      return options;
    };
  }
});
app.registerExtension({
  name: "Comfy.NoteNode",
  registerCustomNodes() {
    const _NoteNode = class _NoteNode {
      constructor() {
        __publicField(this, "color", LGraphCanvas.node_colors.yellow.color);
        __publicField(this, "bgcolor", LGraphCanvas.node_colors.yellow.bgcolor);
        __publicField(this, "groupcolor", LGraphCanvas.node_colors.yellow.groupcolor);
        __publicField(this, "properties");
        __publicField(this, "serialize_widgets");
        __publicField(this, "isVirtualNode");
        __publicField(this, "collapsable");
        __publicField(this, "title_mode");
        if (!this.properties) {
          this.properties = { text: "" };
        }
        ComfyWidgets.STRING(
          // @ts-expect-error
          // Should we extends LGraphNode?
          this,
          "",
          ["", { default: this.properties.text, multiline: true }],
          app
        );
        this.serialize_widgets = true;
        this.isVirtualNode = true;
      }
    };
    __name(_NoteNode, "NoteNode");
    __publicField(_NoteNode, "category");
    let NoteNode = _NoteNode;
    LiteGraph.registerNodeType(
      "Note",
      // @ts-expect-error
      Object.assign(NoteNode, {
        title_mode: LiteGraph.NORMAL_TITLE,
        title: "Note",
        collapsable: true
      })
    );
    NoteNode.category = "utils";
  }
});
app.registerExtension({
  name: "Comfy.RerouteNode",
  registerCustomNodes(app2) {
    const _RerouteNode = class _RerouteNode {
      constructor() {
        if (!this.properties) {
          this.properties = {};
        }
        this.properties.showOutputText = _RerouteNode.defaultVisibility;
        this.properties.horizontal = false;
        this.addInput("", "*");
        this.addOutput(this.properties.showOutputText ? "*" : "", "*");
        this.onAfterGraphConfigured = function() {
          requestAnimationFrame(() => {
            this.onConnectionsChange(LiteGraph.INPUT, null, true, null);
          });
        };
        this.onConnectionsChange = function(type, index, connected, link_info) {
          var _a, _b, _c, _d, _e;
          this.applyOrientation();
          if (connected && type === LiteGraph.OUTPUT) {
            const types = new Set(
              this.outputs[0].links.map((l) => app2.graph.links[l].type).filter((t) => t !== "*")
            );
            if (types.size > 1) {
              const linksToDisconnect = [];
              for (let i = 0; i < this.outputs[0].links.length - 1; i++) {
                const linkId = this.outputs[0].links[i];
                const link = app2.graph.links[linkId];
                linksToDisconnect.push(link);
              }
              for (const link of linksToDisconnect) {
                const node = app2.graph.getNodeById(link.target_id);
                node.disconnectInput(link.target_slot);
              }
            }
          }
          let currentNode = this;
          let updateNodes = [];
          let inputType = null;
          let inputNode = null;
          while (currentNode) {
            updateNodes.unshift(currentNode);
            const linkId = currentNode.inputs[0].link;
            if (linkId !== null) {
              const link = app2.graph.links[linkId];
              if (!link) return;
              const node = app2.graph.getNodeById(link.origin_id);
              const type2 = node.constructor.type;
              if (type2 === "Reroute") {
                if (node === this) {
                  currentNode.disconnectInput(link.target_slot);
                  currentNode = null;
                } else {
                  currentNode = node;
                }
              } else {
                inputNode = currentNode;
                inputType = (_b = (_a = node.outputs[link.origin_slot]) == null ? void 0 : _a.type) != null ? _b : null;
                break;
              }
            } else {
              currentNode = null;
              break;
            }
          }
          const nodes = [this];
          let outputType = null;
          while (nodes.length) {
            currentNode = nodes.pop();
            const outputs = (currentNode.outputs ? currentNode.outputs[0].links : []) || [];
            if (outputs.length) {
              for (const linkId of outputs) {
                const link = app2.graph.links[linkId];
                if (!link) continue;
                const node = app2.graph.getNodeById(link.target_id);
                const type2 = node.constructor.type;
                if (type2 === "Reroute") {
                  nodes.push(node);
                  updateNodes.push(node);
                } else {
                  const nodeOutType = node.inputs && node.inputs[link == null ? void 0 : link.target_slot] && node.inputs[link.target_slot].type ? node.inputs[link.target_slot].type : null;
                  if (inputType && inputType !== "*" && nodeOutType !== inputType) {
                    node.disconnectInput(link.target_slot);
                  } else {
                    outputType = nodeOutType;
                  }
                }
              }
            } else {
            }
          }
          const displayType = inputType || outputType || "*";
          const color = LGraphCanvas.link_type_colors[displayType];
          let widgetConfig;
          let targetWidget;
          let widgetType;
          for (const node of updateNodes) {
            node.outputs[0].type = inputType || "*";
            node.__outputType = displayType;
            node.outputs[0].name = node.properties.showOutputText ? displayType : "";
            node.size = node.computeSize();
            node.applyOrientation();
            for (const l of node.outputs[0].links || []) {
              const link = app2.graph.links[l];
              if (link) {
                link.color = color;
                if (app2.configuringGraph) continue;
                const targetNode = app2.graph.getNodeById(link.target_id);
                const targetInput = (_c = targetNode.inputs) == null ? void 0 : _c[link.target_slot];
                if (targetInput == null ? void 0 : targetInput.widget) {
                  const config = getWidgetConfig(targetInput);
                  if (!widgetConfig) {
                    widgetConfig = (_d = config[1]) != null ? _d : {};
                    widgetType = config[0];
                  }
                  if (!targetWidget) {
                    targetWidget = (_e = targetNode.widgets) == null ? void 0 : _e.find(
                      (w) => w.name === targetInput.widget.name
                    );
                  }
                  const merged = mergeIfValid(targetInput, [
                    config[0],
                    widgetConfig
                  ]);
                  if (merged.customConfig) {
                    widgetConfig = merged.customConfig;
                  }
                }
              }
            }
          }
          for (const node of updateNodes) {
            if (widgetConfig && outputType) {
              node.inputs[0].widget = { name: "value" };
              setWidgetConfig(
                node.inputs[0],
                [widgetType != null ? widgetType : displayType, widgetConfig],
                targetWidget
              );
            } else {
              setWidgetConfig(node.inputs[0], null);
            }
          }
          if (inputNode) {
            const link = app2.graph.links[inputNode.inputs[0].link];
            if (link) {
              link.color = color;
            }
          }
        };
        this.clone = function() {
          const cloned = _RerouteNode.prototype.clone.apply(this);
          cloned.removeOutput(0);
          cloned.addOutput(this.properties.showOutputText ? "*" : "", "*");
          cloned.size = cloned.computeSize();
          return cloned;
        };
        this.isVirtualNode = true;
      }
      getExtraMenuOptions(_, options) {
        options.unshift(
          {
            content: (this.properties.showOutputText ? "Hide" : "Show") + " Type",
            callback: /* @__PURE__ */ __name(() => {
              this.properties.showOutputText = !this.properties.showOutputText;
              if (this.properties.showOutputText) {
                this.outputs[0].name = this.__outputType || this.outputs[0].type;
              } else {
                this.outputs[0].name = "";
              }
              this.size = this.computeSize();
              this.applyOrientation();
              app2.graph.setDirtyCanvas(true, true);
            }, "callback")
          },
          {
            content: (_RerouteNode.defaultVisibility ? "Hide" : "Show") + " Type By Default",
            callback: /* @__PURE__ */ __name(() => {
              _RerouteNode.setDefaultTextVisibility(
                !_RerouteNode.defaultVisibility
              );
            }, "callback")
          },
          {
            // naming is inverted with respect to LiteGraphNode.horizontal
            // LiteGraphNode.horizontal == true means that
            // each slot in the inputs and outputs are laid out horizontally,
            // which is the opposite of the visual orientation of the inputs and outputs as a node
            content: "Set " + (this.properties.horizontal ? "Horizontal" : "Vertical"),
            callback: /* @__PURE__ */ __name(() => {
              this.properties.horizontal = !this.properties.horizontal;
              this.applyOrientation();
            }, "callback")
          }
        );
      }
      applyOrientation() {
        this.horizontal = this.properties.horizontal;
        if (this.horizontal) {
          this.inputs[0].pos = [this.size[0] / 2, 0];
        } else {
          delete this.inputs[0].pos;
        }
        app2.graph.setDirtyCanvas(true, true);
      }
      computeSize() {
        return [
          this.properties.showOutputText && this.outputs && this.outputs.length ? Math.max(
            75,
            LiteGraph.NODE_TEXT_SIZE * this.outputs[0].name.length * 0.6 + 40
          ) : 75,
          26
        ];
      }
      static setDefaultTextVisibility(visible) {
        _RerouteNode.defaultVisibility = visible;
        if (visible) {
          localStorage["Comfy.RerouteNode.DefaultVisibility"] = "true";
        } else {
          delete localStorage["Comfy.RerouteNode.DefaultVisibility"];
        }
      }
    };
    __name(_RerouteNode, "RerouteNode");
    __publicField(_RerouteNode, "category");
    __publicField(_RerouteNode, "defaultVisibility", false);
    let RerouteNode = _RerouteNode;
    RerouteNode.setDefaultTextVisibility(
      !!localStorage["Comfy.RerouteNode.DefaultVisibility"]
    );
    LiteGraph.registerNodeType(
      "Reroute",
      Object.assign(RerouteNode, {
        title_mode: LiteGraph.NO_TITLE,
        title: "Reroute",
        collapsable: false
      })
    );
    RerouteNode.category = "utils";
  }
});
app.registerExtension({
  name: "Comfy.SaveImageExtraOutput",
  beforeRegisterNodeDef(nodeType, nodeData, app2) {
    return __async(this, null, function* () {
      if (nodeData.name === "SaveImage" || nodeData.name === "SaveAnimatedWEBP") {
        const onNodeCreated = nodeType.prototype.onNodeCreated;
        nodeType.prototype.onNodeCreated = function() {
          const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : void 0;
          const widget = this.widgets.find((w) => w.name === "filename_prefix");
          widget.serializeValue = () => {
            return applyTextReplacements(app2, widget.value);
          };
          return r;
        };
      } else {
        const onNodeCreated = nodeType.prototype.onNodeCreated;
        nodeType.prototype.onNodeCreated = function() {
          const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : void 0;
          if (!this.properties || !("Node name for S&R" in this.properties)) {
            this.addProperty("Node name for S&R", this.constructor.type, "string");
          }
          return r;
        };
      }
    });
  }
});
let touchZooming;
let touchCount = 0;
app.registerExtension({
  name: "Comfy.SimpleTouchSupport",
  setup() {
    let zoomPos;
    let touchTime;
    let lastTouch;
    function getMultiTouchPos(e) {
      return Math.hypot(
        e.touches[0].clientX - e.touches[1].clientX,
        e.touches[0].clientY - e.touches[1].clientY
      );
    }
    __name(getMultiTouchPos, "getMultiTouchPos");
    app.canvasEl.addEventListener(
      "touchstart",
      (e) => {
        var _a, _b;
        touchCount++;
        lastTouch = null;
        if (((_a = e.touches) == null ? void 0 : _a.length) === 1) {
          touchTime = /* @__PURE__ */ new Date();
          lastTouch = e.touches[0];
        } else {
          touchTime = null;
          if (((_b = e.touches) == null ? void 0 : _b.length) === 2) {
            zoomPos = getMultiTouchPos(e);
            app.canvas.pointer_is_down = false;
          }
        }
      },
      true
    );
    app.canvasEl.addEventListener("touchend", (e) => {
      var _a, _b, _c;
      touchZooming = false;
      touchCount = (_b = (_a = e.touches) == null ? void 0 : _a.length) != null ? _b : touchCount - 1;
      if (touchTime && !((_c = e.touches) == null ? void 0 : _c.length)) {
        if ((/* @__PURE__ */ new Date()).getTime() - touchTime > 600) {
          try {
            e.constructor = CustomEvent;
          } catch (error) {
          }
          e.clientX = lastTouch.clientX;
          e.clientY = lastTouch.clientY;
          app.canvas.pointer_is_down = true;
          app.canvas._mousedown_callback(e);
        }
        touchTime = null;
      }
    });
    app.canvasEl.addEventListener(
      "touchmove",
      (e) => {
        var _a, _b;
        touchTime = null;
        if (((_a = e.touches) == null ? void 0 : _a.length) === 2) {
          app.canvas.pointer_is_down = false;
          touchZooming = true;
          LiteGraph.closeAllContextMenus();
          (_b = app.canvas.search_box) == null ? void 0 : _b.close();
          const newZoomPos = getMultiTouchPos(e);
          const midX = (e.touches[0].clientX + e.touches[1].clientX) / 2;
          const midY = (e.touches[0].clientY + e.touches[1].clientY) / 2;
          let scale = app.canvas.ds.scale;
          const diff = zoomPos - newZoomPos;
          if (diff > 0.5) {
            scale *= 1 / 1.07;
          } else if (diff < -0.5) {
            scale *= 1.07;
          }
          app.canvas.ds.changeScale(scale, [midX, midY]);
          app.canvas.setDirty(true, true);
          zoomPos = newZoomPos;
        }
      },
      true
    );
  }
});
const processMouseDown = LGraphCanvas.prototype.processMouseDown;
LGraphCanvas.prototype.processMouseDown = function(e) {
  if (touchZooming || touchCount) {
    return;
  }
  return processMouseDown.apply(this, arguments);
};
const processMouseMove = LGraphCanvas.prototype.processMouseMove;
LGraphCanvas.prototype.processMouseMove = function(e) {
  if (touchZooming || touchCount > 1) {
    return;
  }
  return processMouseMove.apply(this, arguments);
};
app.registerExtension({
  name: "Comfy.SlotDefaults",
  suggestionsNumber: null,
  init() {
    LiteGraph.search_filter_enabled = true;
    LiteGraph.middle_click_slot_add_default_node = true;
    this.suggestionsNumber = app.ui.settings.addSetting({
      id: "Comfy.NodeSuggestions.number",
      category: ["Comfy", "Node Search Box", "NodeSuggestions"],
      name: "Number of nodes suggestions",
      tooltip: "Only for litegraph searchbox/context menu",
      type: "slider",
      attrs: {
        min: 1,
        max: 100,
        step: 1
      },
      defaultValue: 5,
      onChange: /* @__PURE__ */ __name((newVal, oldVal) => {
        this.setDefaults(newVal);
      }, "onChange")
    });
  },
  slot_types_default_out: {},
  slot_types_default_in: {},
  beforeRegisterNodeDef(nodeType, nodeData, app2) {
    return __async(this, null, function* () {
      var nodeId = nodeData.name;
      var inputs = [];
      inputs = nodeData["input"]["required"];
      for (const inputKey in inputs) {
        var input = inputs[inputKey];
        if (typeof input[0] !== "string") continue;
        var type = input[0];
        if (type in ComfyWidgets) {
          var customProperties = input[1];
          if (!(customProperties == null ? void 0 : customProperties.forceInput)) continue;
        }
        if (!(type in this.slot_types_default_out)) {
          this.slot_types_default_out[type] = ["Reroute"];
        }
        if (this.slot_types_default_out[type].includes(nodeId)) continue;
        this.slot_types_default_out[type].push(nodeId);
        const lowerType = type.toLocaleLowerCase();
        if (!(lowerType in LiteGraph.registered_slot_in_types)) {
          LiteGraph.registered_slot_in_types[lowerType] = { nodes: [] };
        }
        LiteGraph.registered_slot_in_types[lowerType].nodes.push(
          nodeType.comfyClass
        );
      }
      var outputs = nodeData["output"];
      for (const key in outputs) {
        var type = outputs[key];
        if (!(type in this.slot_types_default_in)) {
          this.slot_types_default_in[type] = ["Reroute"];
        }
        this.slot_types_default_in[type].push(nodeId);
        if (!(type in LiteGraph.registered_slot_out_types)) {
          LiteGraph.registered_slot_out_types[type] = { nodes: [] };
        }
        LiteGraph.registered_slot_out_types[type].nodes.push(nodeType.comfyClass);
        if (!LiteGraph.slot_types_out.includes(type)) {
          LiteGraph.slot_types_out.push(type);
        }
      }
      var maxNum = this.suggestionsNumber.value;
      this.setDefaults(maxNum);
    });
  },
  setDefaults(maxNum) {
    LiteGraph.slot_types_default_out = {};
    LiteGraph.slot_types_default_in = {};
    for (const type in this.slot_types_default_out) {
      LiteGraph.slot_types_default_out[type] = this.slot_types_default_out[type].slice(0, maxNum);
    }
    for (const type in this.slot_types_default_in) {
      LiteGraph.slot_types_default_in[type] = this.slot_types_default_in[type].slice(0, maxNum);
    }
  }
});
function roundVectorToGrid(vec) {
  vec[0] = LiteGraph.CANVAS_GRID_SIZE * Math.round(vec[0] / LiteGraph.CANVAS_GRID_SIZE);
  vec[1] = LiteGraph.CANVAS_GRID_SIZE * Math.round(vec[1] / LiteGraph.CANVAS_GRID_SIZE);
  return vec;
}
__name(roundVectorToGrid, "roundVectorToGrid");
app.registerExtension({
  name: "Comfy.SnapToGrid",
  init() {
    app.ui.settings.addSetting({
      id: "Comfy.SnapToGrid.GridSize",
      category: ["Comfy", "Graph", "GridSize"],
      name: "Snap to gird size",
      type: "slider",
      attrs: {
        min: 1,
        max: 500
      },
      tooltip: "When dragging and resizing nodes while holding shift they will be aligned to the grid, this controls the size of that grid.",
      defaultValue: LiteGraph.CANVAS_GRID_SIZE,
      onChange(value) {
        LiteGraph.CANVAS_GRID_SIZE = +value;
      }
    });
    const onNodeMoved = app.canvas.onNodeMoved;
    app.canvas.onNodeMoved = function(node) {
      const r = onNodeMoved == null ? void 0 : onNodeMoved.apply(this, arguments);
      if (app.shiftDown) {
        for (const id2 in this.selected_nodes) {
          this.selected_nodes[id2].alignToGrid();
        }
      }
      return r;
    };
    const onNodeAdded = app.graph.onNodeAdded;
    app.graph.onNodeAdded = function(node) {
      const onResize = node.onResize;
      node.onResize = function() {
        if (app.shiftDown) {
          roundVectorToGrid(node.size);
        }
        return onResize == null ? void 0 : onResize.apply(this, arguments);
      };
      return onNodeAdded == null ? void 0 : onNodeAdded.apply(this, arguments);
    };
    const origDrawNode = LGraphCanvas.prototype.drawNode;
    LGraphCanvas.prototype.drawNode = function(node, ctx) {
      if (app.shiftDown && this.node_dragged && node.id in this.selected_nodes) {
        const [x, y] = roundVectorToGrid([...node.pos]);
        const shiftX = x - node.pos[0];
        let shiftY = y - node.pos[1];
        let w, h;
        if (node.flags.collapsed) {
          w = node._collapsed_width;
          h = LiteGraph.NODE_TITLE_HEIGHT;
          shiftY -= LiteGraph.NODE_TITLE_HEIGHT;
        } else {
          w = node.size[0];
          h = node.size[1];
          let titleMode = node.constructor.title_mode;
          if (titleMode !== LiteGraph.TRANSPARENT_TITLE && titleMode !== LiteGraph.NO_TITLE) {
            h += LiteGraph.NODE_TITLE_HEIGHT;
            shiftY -= LiteGraph.NODE_TITLE_HEIGHT;
          }
        }
        const f = ctx.fillStyle;
        ctx.fillStyle = "rgba(100, 100, 100, 0.5)";
        ctx.fillRect(shiftX, shiftY, w, h);
        ctx.fillStyle = f;
      }
      return origDrawNode.apply(this, arguments);
    };
    let selectedAndMovingGroup = null;
    const groupMove = LGraphGroup.prototype.move;
    LGraphGroup.prototype.move = function(deltax, deltay, ignore_nodes) {
      const v = groupMove.apply(this, arguments);
      if (!selectedAndMovingGroup && app.canvas.selected_group === this && (deltax || deltay)) {
        selectedAndMovingGroup = this;
      }
      if (app.canvas.last_mouse_dragging === false && app.shiftDown) {
        this.recomputeInsideNodes();
        for (const node of this._nodes) {
          node.alignToGrid();
        }
        LGraphNode.prototype.alignToGrid.apply(this);
      }
      return v;
    };
    const drawGroups = LGraphCanvas.prototype.drawGroups;
    LGraphCanvas.prototype.drawGroups = function(canvas, ctx) {
      if (this.selected_group && app.shiftDown) {
        if (this.selected_group_resizing) {
          roundVectorToGrid(this.selected_group.size);
        } else if (selectedAndMovingGroup) {
          const [x, y] = roundVectorToGrid([...selectedAndMovingGroup.pos]);
          const f = ctx.fillStyle;
          const s = ctx.strokeStyle;
          ctx.fillStyle = "rgba(100, 100, 100, 0.33)";
          ctx.strokeStyle = "rgba(100, 100, 100, 0.66)";
          ctx.rect(x, y, ...selectedAndMovingGroup.size);
          ctx.fill();
          ctx.stroke();
          ctx.fillStyle = f;
          ctx.strokeStyle = s;
        }
      } else if (!this.selected_group) {
        selectedAndMovingGroup = null;
      }
      return drawGroups.apply(this, arguments);
    };
    const onGroupAdd = LGraphCanvas.onGroupAdd;
    LGraphCanvas.onGroupAdd = function() {
      const v = onGroupAdd.apply(app.canvas, arguments);
      if (app.shiftDown) {
        const lastGroup = app.graph._groups[app.graph._groups.length - 1];
        if (lastGroup) {
          roundVectorToGrid(lastGroup.pos);
          roundVectorToGrid(lastGroup.size);
        }
      }
      return v;
    };
  }
});
app.registerExtension({
  name: "Comfy.UploadImage",
  beforeRegisterNodeDef(nodeType, nodeData, app2) {
    return __async(this, null, function* () {
      var _a, _b, _c, _d;
      if (((_d = (_c = (_b = (_a = nodeData == null ? void 0 : nodeData.input) == null ? void 0 : _a.required) == null ? void 0 : _b.image) == null ? void 0 : _c[1]) == null ? void 0 : _d.image_upload) === true) {
        nodeData.input.required.upload = ["IMAGEUPLOAD"];
      }
    });
  }
});
const WEBCAM_READY = Symbol();
app.registerExtension({
  name: "Comfy.WebcamCapture",
  getCustomWidgets(app2) {
    return {
      WEBCAM(node, inputName) {
        let res;
        node[WEBCAM_READY] = new Promise((resolve) => res = resolve);
        const container = document.createElement("div");
        container.style.background = "rgba(0,0,0,0.25)";
        container.style.textAlign = "center";
        const video = document.createElement("video");
        video.style.height = video.style.width = "100%";
        const loadVideo = /* @__PURE__ */ __name(() => __async(this, null, function* () {
          try {
            const stream = yield navigator.mediaDevices.getUserMedia({
              video: true,
              audio: false
            });
            container.replaceChildren(video);
            setTimeout(() => res(video), 500);
            video.addEventListener("loadedmetadata", () => res(video), false);
            video.srcObject = stream;
            video.play();
          } catch (error) {
            const label = document.createElement("div");
            label.style.color = "red";
            label.style.overflow = "auto";
            label.style.maxHeight = "100%";
            label.style.whiteSpace = "pre-wrap";
            if (window.isSecureContext) {
              label.textContent = "Unable to load webcam, please ensure access is granted:\n" + error.message;
            } else {
              label.textContent = "Unable to load webcam. A secure context is required, if you are not accessing ComfyUI on localhost (127.0.0.1) you will have to enable TLS (https)\n\n" + error.message;
            }
            container.replaceChildren(label);
          }
        }), "loadVideo");
        loadVideo();
        return { widget: node.addDOMWidget(inputName, "WEBCAM", container) };
      }
    };
  },
  nodeCreated(node) {
    if (node.type, node.constructor.comfyClass !== "WebcamCapture") return;
    let video;
    const camera = node.widgets.find((w2) => w2.name === "image");
    const w = node.widgets.find((w2) => w2.name === "width");
    const h = node.widgets.find((w2) => w2.name === "height");
    const captureOnQueue = node.widgets.find(
      (w2) => w2.name === "capture_on_queue"
    );
    const canvas = document.createElement("canvas");
    const capture = /* @__PURE__ */ __name(() => {
      canvas.width = w.value;
      canvas.height = h.value;
      const ctx = canvas.getContext("2d");
      ctx.drawImage(video, 0, 0, w.value, h.value);
      const data = canvas.toDataURL("image/png");
      const img = new Image();
      img.onload = () => {
        node.imgs = [img];
        app.graph.setDirtyCanvas(true);
        requestAnimationFrame(() => {
          var _a;
          (_a = node.setSizeForImage) == null ? void 0 : _a.call(node);
        });
      };
      img.src = data;
    }, "capture");
    const btn = node.addWidget(
      "button",
      "waiting for camera...",
      "capture",
      capture
    );
    btn.disabled = true;
    btn.serializeValue = () => void 0;
    camera.serializeValue = () => __async(this, null, function* () {
      var _a;
      if (captureOnQueue.value) {
        capture();
      } else if (!((_a = node.imgs) == null ? void 0 : _a.length)) {
        const err = `No webcam image captured`;
        alert(err);
        throw new Error(err);
      }
      const blob = yield new Promise((r) => canvas.toBlob(r));
      const name = `${+/* @__PURE__ */ new Date()}.png`;
      const file2 = new File([blob], name);
      const body = new FormData();
      body.append("image", file2);
      body.append("subfolder", "webcam");
      body.append("type", "temp");
      const resp = yield api.fetchApi("/upload/image", {
        method: "POST",
        body
      });
      if (resp.status !== 200) {
        const err = `Error uploading camera image: ${resp.status} - ${resp.statusText}`;
        alert(err);
        throw new Error(err);
      }
      return `webcam/${name} [temp]`;
    });
    node[WEBCAM_READY].then((v) => {
      video = v;
      if (!w.value) {
        w.value = video.videoWidth || 640;
        h.value = video.videoHeight || 480;
      }
      btn.disabled = false;
      btn.label = "capture";
    });
  }
});
function splitFilePath(path) {
  const folder_separator = path.lastIndexOf("/");
  if (folder_separator === -1) {
    return ["", path];
  }
  return [
    path.substring(0, folder_separator),
    path.substring(folder_separator + 1)
  ];
}
__name(splitFilePath, "splitFilePath");
function getResourceURL(subfolder, filename, type = "input") {
  const params = [
    "filename=" + encodeURIComponent(filename),
    "type=" + type,
    "subfolder=" + subfolder,
    app.getRandParam().substring(1)
  ].join("&");
  return `/view?${params}`;
}
__name(getResourceURL, "getResourceURL");
function uploadFile(audioWidget, audioUIWidget, file2, updateNode, pasted = false) {
  return __async(this, null, function* () {
    try {
      const body = new FormData();
      body.append("image", file2);
      if (pasted) body.append("subfolder", "pasted");
      const resp = yield api.fetchApi("/upload/image", {
        method: "POST",
        body
      });
      if (resp.status === 200) {
        const data = yield resp.json();
        let path = data.name;
        if (data.subfolder) path = data.subfolder + "/" + path;
        if (!audioWidget.options.values.includes(path)) {
          audioWidget.options.values.push(path);
        }
        if (updateNode) {
          audioUIWidget.element.src = api.apiURL(
            getResourceURL(...splitFilePath(path))
          );
          audioWidget.value = path;
        }
      } else {
        alert(resp.status + " - " + resp.statusText);
      }
    } catch (error) {
      alert(error);
    }
  });
}
__name(uploadFile, "uploadFile");
app.registerExtension({
  name: "Comfy.AudioWidget",
  beforeRegisterNodeDef(nodeType, nodeData) {
    return __async(this, null, function* () {
      if (["LoadAudio", "SaveAudio", "PreviewAudio"].includes(nodeType.comfyClass)) {
        nodeData.input.required.audioUI = ["AUDIO_UI"];
      }
    });
  },
  getCustomWidgets() {
    return {
      AUDIO_UI(node, inputName) {
        const audio = document.createElement("audio");
        audio.controls = true;
        audio.classList.add("comfy-audio");
        audio.setAttribute("name", "media");
        const audioUIWidget = node.addDOMWidget(
          inputName,
          /* name=*/
          "audioUI",
          audio
        );
        audioUIWidget.serialize = false;
        const isOutputNode = node.constructor.nodeData.output_node;
        if (isOutputNode) {
          audioUIWidget.element.classList.add("empty-audio-widget");
          const onExecuted = node.onExecuted;
          node.onExecuted = function(message) {
            onExecuted == null ? void 0 : onExecuted.apply(this, arguments);
            const audios = message.audio;
            if (!audios) return;
            const audio2 = audios[0];
            audioUIWidget.element.src = api.apiURL(
              getResourceURL(audio2.subfolder, audio2.filename, audio2.type)
            );
            audioUIWidget.element.classList.remove("empty-audio-widget");
          };
        }
        return { widget: audioUIWidget };
      }
    };
  },
  onNodeOutputsUpdated(nodeOutputs) {
    for (const [nodeId, output] of Object.entries(nodeOutputs)) {
      const node = app.graph.getNodeById(Number.parseInt(nodeId));
      if ("audio" in output) {
        const audioUIWidget = node.widgets.find(
          (w) => w.name === "audioUI"
        );
        const audio = output.audio[0];
        audioUIWidget.element.src = api.apiURL(
          getResourceURL(audio.subfolder, audio.filename, audio.type)
        );
        audioUIWidget.element.classList.remove("empty-audio-widget");
      }
    }
  }
});
app.registerExtension({
  name: "Comfy.UploadAudio",
  beforeRegisterNodeDef(nodeType, nodeData) {
    return __async(this, null, function* () {
      var _a, _b, _c, _d;
      if (((_d = (_c = (_b = (_a = nodeData == null ? void 0 : nodeData.input) == null ? void 0 : _a.required) == null ? void 0 : _b.audio) == null ? void 0 : _c[1]) == null ? void 0 : _d.audio_upload) === true) {
        nodeData.input.required.upload = ["AUDIOUPLOAD"];
      }
    });
  },
  getCustomWidgets() {
    return {
      AUDIOUPLOAD(node, inputName) {
        const audioWidget = node.widgets.find(
          (w) => w.name === "audio"
        );
        const audioUIWidget = node.widgets.find(
          (w) => w.name === "audioUI"
        );
        const onAudioWidgetUpdate = /* @__PURE__ */ __name(() => {
          audioUIWidget.element.src = api.apiURL(
            getResourceURL(...splitFilePath(audioWidget.value))
          );
        }, "onAudioWidgetUpdate");
        if (audioWidget.value) {
          onAudioWidgetUpdate();
        }
        audioWidget.callback = onAudioWidgetUpdate;
        const onGraphConfigured = node.onGraphConfigured;
        node.onGraphConfigured = function() {
          onGraphConfigured == null ? void 0 : onGraphConfigured.apply(this, arguments);
          if (audioWidget.value) {
            onAudioWidgetUpdate();
          }
        };
        const fileInput = document.createElement("input");
        fileInput.type = "file";
        fileInput.accept = "audio/*";
        fileInput.style.display = "none";
        fileInput.onchange = () => {
          if (fileInput.files.length) {
            uploadFile(audioWidget, audioUIWidget, fileInput.files[0], true);
          }
        };
        const uploadWidget = node.addWidget(
          "button",
          inputName,
          /* value=*/
          "",
          () => {
            fileInput.click();
          }
        );
        uploadWidget.label = "choose file to upload";
        uploadWidget.serialize = false;
        return { widget: uploadWidget };
      }
    };
  }
});
//# sourceMappingURL=index-DkvOTKox.js.map
